Compare commits

..

4 Commits

Author SHA1 Message Date
akwizgran
98e5d892a4 Poll Tor plugin infrequently once our HS is reachable. 2020-06-30 14:57:03 +01:00
akwizgran
94f8f68336 Keep track of connected OR connections. 2020-06-30 14:53:55 +01:00
akwizgran
2f8dd51ef8 Remove tests for removed polling code. 2020-06-30 14:53:55 +01:00
akwizgran
5dd1c28e77 Remove backoff code from plugins. 2020-06-30 14:53:55 +01:00
177 changed files with 2432 additions and 5259 deletions

View File

@@ -1,5 +1,8 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<AndroidXmlCodeStyleSettings>
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="ANNOTATION_PARAMETER_WRAP" value="1" />
<option name="IMPORT_LAYOUT_TABLE">

View File

@@ -1,9 +0,0 @@
Translations for this project are managed through Transifex:
https://transifex.com/otf/briar
If you'd like to volunteer as a translator, please create a Transifex account and request to be
added to the project's translation team. The Localization Lab has some instructions and advice for
translators here:
https://wiki.localizationlab.org/index.php/Briar

View File

@@ -11,8 +11,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
versionCode 10210
versionName "1.2.10"
versionCode 10207
versionName "1.2.7"
consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -16,8 +16,6 @@
android:label="@string/app_name"
android:supportsRtl="true">
<receiver android:name=".system.AlarmReceiver" />
</application>
</manifest>

View File

@@ -6,8 +6,6 @@ import org.briarproject.bramble.plugin.tor.CircumventionModule;
import org.briarproject.bramble.reporting.ReportingModule;
import org.briarproject.bramble.socks.SocksModule;
import org.briarproject.bramble.system.AndroidSystemModule;
import org.briarproject.bramble.system.AndroidTaskSchedulerModule;
import org.briarproject.bramble.system.AndroidWakefulIoExecutorModule;
import dagger.Module;
@@ -15,8 +13,6 @@ import dagger.Module;
AndroidBatteryModule.class,
AndroidNetworkModule.class,
AndroidSystemModule.class,
AndroidTaskSchedulerModule.class,
AndroidWakefulIoExecutorModule.class,
CircumventionModule.class,
ReportingModule.class,
SocksModule.class

View File

@@ -1,8 +0,0 @@
package org.briarproject.bramble;
import org.briarproject.bramble.api.system.AlarmListener;
public interface BrambleAppComponent {
AlarmListener alarmListener();
}

View File

@@ -1,6 +0,0 @@
package org.briarproject.bramble;
public interface BrambleApplication {
BrambleAppComponent getBrambleAppComponent();
}

View File

@@ -1,11 +0,0 @@
package org.briarproject.bramble.api.system;
import android.content.Intent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AlarmListener {
void onAlarm(Intent intent);
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
public interface AndroidWakeLock {
/**
* Acquires the wake lock. This has no effect if the wake lock has already
* been acquired.
*/
void acquire();
/**
* Releases the wake lock. This has no effect if the wake lock has already
* been released.
*/
void release();
}

View File

@@ -1,38 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
@NotNullByDefault
public interface AndroidWakeLockManager {
/**
* Creates a wake lock with the given tag. The tag is only used for
* logging; the underlying OS wake lock will use its own tag.
*/
AndroidWakeLock createWakeLock(String tag);
/**
* Runs the given task while holding a wake lock.
*/
void runWakefully(Runnable r, String tag);
/**
* Submits the given task to the given executor while holding a wake lock.
* The lock is released when the task completes, or if an exception is
* thrown while submitting or running the task.
*/
void executeWakefully(Runnable r, Executor executor, String tag);
/**
* Starts a dedicated thread to run the given task asynchronously. A wake
* lock is acquired before starting the thread and released when the task
* completes, or if an exception is thrown while starting the thread or
* running the task.
* <p>
* This method should only be used for lifecycle management tasks that
* can't be run on an executor.
*/
void executeWakefully(Runnable r, String tag);
}

View File

@@ -9,17 +9,16 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.network.NetworkStatus;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import org.briarproject.bramble.api.system.Scheduler;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -51,22 +50,20 @@ class AndroidNetworkManager implements NetworkManager, Service {
private static final String WIFI_AP_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_AP_STATE_CHANGED";
private final TaskScheduler scheduler;
private final ScheduledExecutorService scheduler;
private final EventBus eventBus;
private final Executor eventExecutor;
private final Context appContext;
private final AtomicReference<Cancellable> connectivityCheck =
private final AtomicReference<Future<?>> connectivityCheck =
new AtomicReference<>();
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile BroadcastReceiver networkStateReceiver = null;
@Inject
AndroidNetworkManager(TaskScheduler scheduler, EventBus eventBus,
@EventExecutor Executor eventExecutor, Application app) {
AndroidNetworkManager(@Scheduler ScheduledExecutorService scheduler,
EventBus eventBus, Application app) {
this.scheduler = scheduler;
this.eventBus = eventBus;
this.eventExecutor = eventExecutor;
this.appContext = app.getApplicationContext();
}
@@ -107,12 +104,11 @@ class AndroidNetworkManager implements NetworkManager, Service {
}
private void scheduleConnectionStatusUpdate(int delay, TimeUnit unit) {
Cancellable newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, eventExecutor,
delay, unit);
Cancellable oldConnectivityCheck =
Future<?> newConnectivityCheck =
scheduler.schedule(this::updateConnectionStatus, delay, unit);
Future<?> oldConnectivityCheck =
connectivityCheck.getAndSet(newConnectivityCheck);
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel();
if (oldConnectivityCheck != null) oldConnectivityCheck.cancel(false);
}
private class NetworkStateReceiver extends BroadcastReceiver {

View File

@@ -1,36 +0,0 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothSocket;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import java.io.IOException;
@NotNullByDefault
class AndroidBluetoothConnectionFactory
implements BluetoothConnectionFactory<BluetoothSocket> {
private final BluetoothConnectionLimiter connectionLimiter;
private final AndroidWakeLockManager wakeLockManager;
private final TimeoutMonitor timeoutMonitor;
AndroidBluetoothConnectionFactory(
BluetoothConnectionLimiter connectionLimiter,
AndroidWakeLockManager wakeLockManager,
TimeoutMonitor timeoutMonitor) {
this.connectionLimiter = connectionLimiter;
this.wakeLockManager = wakeLockManager;
this.timeoutMonitor = timeoutMonitor;
}
@Override
public DuplexTransportConnection wrapSocket(DuplexPlugin plugin,
BluetoothSocket s) throws IOException {
return new AndroidBluetoothTransportConnection(plugin,
connectionLimiter, wakeLockManager, timeoutMonitor, s);
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
@@ -10,9 +9,9 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
@@ -31,6 +30,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.Nullable;
@@ -59,40 +59,35 @@ import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidBluetoothPlugin
extends BluetoothPlugin<BluetoothSocket, BluetoothServerSocket> {
class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
private static final Logger LOG =
getLogger(AndroidBluetoothPlugin.class.getName());
private static final int MAX_DISCOVERY_MS = 10_000;
private final ScheduledExecutorService scheduler;
private final AndroidExecutor androidExecutor;
private final Application app;
private final Context appContext;
private final Clock clock;
private volatile boolean wasEnabledByUs = false;
private volatile BluetoothStateReceiver receiver = null;
// Non-null if the plugin started successfully
private volatile BluetoothAdapter adapter = null;
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
BluetoothConnectionFactory<BluetoothSocket> connectionFactory,
Executor ioExecutor,
Executor wakefulIoExecutor,
SecureRandom secureRandom,
AndroidExecutor androidExecutor,
Application app,
Clock clock,
Backoff backoff,
PluginCallback callback,
int maxLatency,
int maxIdleTime) {
super(connectionLimiter, connectionFactory, ioExecutor,
wakefulIoExecutor, secureRandom, backoff, callback,
maxLatency, maxIdleTime);
TimeoutMonitor timeoutMonitor, Executor ioExecutor,
SecureRandom secureRandom, ScheduledExecutorService scheduler,
AndroidExecutor androidExecutor, Context appContext, Clock clock,
PluginCallback callback, int maxLatency, int maxIdleTime,
int pollingInterval) {
super(connectionLimiter, timeoutMonitor, ioExecutor, secureRandom,
callback, maxLatency, maxIdleTime, pollingInterval);
this.scheduler = scheduler;
this.androidExecutor = androidExecutor;
this.app = app;
this.appContext = appContext;
this.clock = clock;
}
@@ -104,13 +99,13 @@ class AndroidBluetoothPlugin
filter.addAction(ACTION_STATE_CHANGED);
filter.addAction(ACTION_SCAN_MODE_CHANGED);
receiver = new BluetoothStateReceiver();
app.registerReceiver(receiver, filter);
appContext.registerReceiver(receiver, filter);
}
@Override
public void stop() {
super.stop();
if (receiver != null) app.unregisterReceiver(receiver);
if (receiver != null) appContext.unregisterReceiver(receiver);
}
@Override
@@ -132,10 +127,42 @@ class AndroidBluetoothPlugin
return adapter != null && adapter.isEnabled();
}
@Override
void enableAdapter() {
if (adapter != null && !adapter.isEnabled()) {
if (adapter.enable()) {
LOG.info("Enabling Bluetooth");
wasEnabledByUs = true;
} else {
LOG.info("Could not enable Bluetooth");
}
}
}
@Override
void disableAdapterIfEnabledByUs() {
if (isAdapterEnabled() && wasEnabledByUs) {
if (adapter.disable()) LOG.info("Disabling Bluetooth");
else LOG.info("Could not disable Bluetooth");
wasEnabledByUs = false;
}
}
@Override
void setEnabledByUs() {
wasEnabledByUs = true;
}
@Override
void onAdapterDisabled() {
super.onAdapterDisabled();
wasEnabledByUs = false;
}
@Override
@Nullable
String getBluetoothAddress() {
String address = AndroidUtils.getBluetoothAddress(app, adapter);
String address = AndroidUtils.getBluetoothAddress(appContext, adapter);
return address.isEmpty() ? null : address;
}
@@ -153,7 +180,13 @@ class AndroidBluetoothPlugin
@Override
DuplexTransportConnection acceptConnection(BluetoothServerSocket ss)
throws IOException {
return connectionFactory.wrapSocket(this, ss.accept());
return wrapSocket(ss.accept());
}
private DuplexTransportConnection wrapSocket(BluetoothSocket s)
throws IOException {
return new AndroidBluetoothTransportConnection(this, connectionLimiter,
timeoutMonitor, appContext, scheduler, s);
}
@Override
@@ -170,7 +203,7 @@ class AndroidBluetoothPlugin
try {
s = d.createInsecureRfcommSocketToServiceRecord(u);
s.connect();
return connectionFactory.wrapSocket(this, s);
return wrapSocket(s);
} catch (IOException e) {
IoUtils.tryToClose(s, LOG, WARNING);
throw e;
@@ -205,7 +238,7 @@ class AndroidBluetoothPlugin
filter.addAction(ACTION_DISCOVERY_STARTED);
filter.addAction(ACTION_DISCOVERY_FINISHED);
filter.addAction(ACTION_FOUND);
app.registerReceiver(receiver, filter);
appContext.registerReceiver(receiver, filter);
try {
if (adapter.startDiscovery()) {
long now = clock.currentTimeMillis();
@@ -242,7 +275,7 @@ class AndroidBluetoothPlugin
} finally {
LOG.info("Cancelling discovery");
adapter.cancelDiscovery();
app.unregisterReceiver(receiver);
appContext.unregisterReceiver(receiver);
}
// Shuffle the addresses so we don't always try the same one first
shuffle(addresses);

View File

@@ -1,72 +1,57 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.app.Application;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.security.SecureRandom;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
@Immutable
@NotNullByDefault
public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private static final int MAX_LATENCY = (int) SECONDS.toMillis(30);
private static final int MAX_IDLE_TIME = (int) SECONDS.toMillis(30);
private static final int POLLING_INTERVAL = (int) MINUTES.toMillis(2);
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final AndroidExecutor androidExecutor;
private final AndroidWakeLockManager wakeLockManager;
private final Application app;
private final Context appContext;
private final SecureRandom secureRandom;
private final EventBus eventBus;
private final Clock clock;
private final TimeoutMonitor timeoutMonitor;
private final BackoffFactory backoffFactory;
@Inject
public AndroidBluetoothPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
AndroidExecutor androidExecutor,
AndroidWakeLockManager wakeLockManager,
Application app,
SecureRandom secureRandom,
EventBus eventBus,
Clock clock,
TimeoutMonitor timeoutMonitor,
BackoffFactory backoffFactory) {
public AndroidBluetoothPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler,
AndroidExecutor androidExecutor, Context appContext,
SecureRandom secureRandom, EventBus eventBus, Clock clock,
TimeoutMonitor timeoutMonitor) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.scheduler = scheduler;
this.androidExecutor = androidExecutor;
this.wakeLockManager = wakeLockManager;
this.app = app;
this.appContext = appContext;
this.secureRandom = secureRandom;
this.eventBus = eventBus;
this.clock = clock;
this.timeoutMonitor = timeoutMonitor;
this.backoffFactory = backoffFactory;
}
@Override
@@ -83,15 +68,10 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(PluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl(eventBus);
BluetoothConnectionFactory<BluetoothSocket> connectionFactory =
new AndroidBluetoothConnectionFactory(connectionLimiter,
wakeLockManager, timeoutMonitor);
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
connectionLimiter, connectionFactory, ioExecutor,
wakefulIoExecutor, secureRandom, androidExecutor, app,
clock, backoff, callback, MAX_LATENCY, MAX_IDLE_TIME);
connectionLimiter, timeoutMonitor, ioExecutor, secureRandom,
scheduler, androidExecutor, appContext, clock, callback,
MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,19 +1,26 @@
package org.briarproject.bramble.plugin.bluetooth;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.PowerManager;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.util.RenewableWakeLock;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ScheduledExecutorService;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS;
import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag;
import static org.briarproject.bramble.util.AndroidUtils.isValidBluetoothAddress;
@NotNullByDefault
@@ -21,21 +28,25 @@ class AndroidBluetoothTransportConnection
extends AbstractDuplexTransportConnection {
private final BluetoothConnectionLimiter connectionLimiter;
private final RenewableWakeLock wakeLock;
private final BluetoothSocket socket;
private final InputStream in;
private final AndroidWakeLock wakeLock;
AndroidBluetoothTransportConnection(Plugin plugin,
BluetoothConnectionLimiter connectionLimiter,
AndroidWakeLockManager wakeLockManager,
TimeoutMonitor timeoutMonitor,
BluetoothSocket socket) throws IOException {
TimeoutMonitor timeoutMonitor, Context appContext,
ScheduledExecutorService scheduler, BluetoothSocket socket)
throws IOException {
super(plugin);
this.connectionLimiter = connectionLimiter;
this.socket = socket;
in = timeoutMonitor.createTimeoutInputStream(
socket.getInputStream(), plugin.getMaxIdleTime() * 2);
wakeLock = wakeLockManager.createWakeLock("BluetoothConnection");
PowerManager powerManager = (PowerManager)
requireNonNull(appContext.getSystemService(POWER_SERVICE));
String tag = getWakeLockTag(appContext);
wakeLock = new RenewableWakeLock(powerManager, scheduler,
PARTIAL_WAKE_LOCK, tag, 1, MINUTES);
wakeLock.acquire();
String address = socket.getRemoteDevice().getAddress();
if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address);
@@ -55,7 +66,6 @@ class AndroidBluetoothTransportConnection
protected void closeConnection(boolean exception) throws IOException {
try {
socket.close();
in.close();
} finally {
wakeLock.release();
connectionLimiter.connectionClosed(this);

View File

@@ -1,7 +1,7 @@
package org.briarproject.bramble.plugin.tcp;
import android.annotation.TargetApi;
import android.app.Application;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -15,7 +15,6 @@ import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.settings.Settings;
@@ -42,7 +41,6 @@ import static java.util.Collections.list;
import static java.util.Collections.singletonList;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.DEFAULT_PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
@@ -62,22 +60,20 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
private volatile SocketFactory socketFactory;
AndroidLanTcpPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Application app,
Backoff backoff,
PluginCallback callback,
int maxLatency,
int maxIdleTime,
int connectionTimeout) {
super(ioExecutor, wakefulIoExecutor, backoff, callback, maxLatency,
maxIdleTime, connectionTimeout);
AndroidLanTcpPlugin(Executor ioExecutor, Context appContext,
PluginCallback callback, int maxLatency, int maxIdleTime,
int pollingInterval, int connectionTimeout) {
super(ioExecutor, callback, maxLatency, maxIdleTime, pollingInterval,
connectionTimeout);
// Don't execute more than one connection status check at a time
connectionStatusExecutor =
new PoliteExecutor("AndroidLanTcpPlugin", ioExecutor, 1);
connectivityManager = (ConnectivityManager)
requireNonNull(app.getSystemService(CONNECTIVITY_SERVICE));
wifiManager = (WifiManager) app.getSystemService(WIFI_SERVICE);
ConnectivityManager connectivityManager = (ConnectivityManager)
appContext.getSystemService(CONNECTIVITY_SERVICE);
if (connectivityManager == null) throw new AssertionError();
this.connectivityManager = connectivityManager;
wifiManager = (WifiManager) appContext.getApplicationContext()
.getSystemService(WIFI_SERVICE);
socketFactory = SocketFactory.getDefault();
}
@@ -277,11 +273,11 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
// make outgoing connections on API 21+ if another network
// has internet access
socketFactory = SocketFactory.getDefault();
bind();
if (s == INACTIVE) bind();
} else {
LOG.info("Connected to wifi");
socketFactory = getSocketFactory();
bind();
if (s == INACTIVE) bind();
}
});
}

View File

@@ -1,52 +1,40 @@
package org.briarproject.bramble.plugin.tcp;
import android.app.Application;
import android.content.Context;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
@Immutable
@NotNullByDefault
public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30_000; // 30 seconds
private static final int MAX_IDLE_TIME = 30_000; // 30 seconds
private static final int CONNECTION_TIMEOUT = 3_000; // 3 seconds
private static final int MIN_POLLING_INTERVAL = 60_000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 600_000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private static final int MAX_LATENCY = (int) SECONDS.toMillis(30);
private static final int MAX_IDLE_TIME = (int) SECONDS.toMillis(30);
private static final int POLLING_INTERVAL = (int) MINUTES.toMillis(1);
private static final int CONNECTION_TIMEOUT = (int) SECONDS.toMillis(3);
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final EventBus eventBus;
private final BackoffFactory backoffFactory;
private final Application app;
private final Context appContext;
@Inject
public AndroidLanTcpPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
EventBus eventBus,
BackoffFactory backoffFactory,
Application app) {
public AndroidLanTcpPluginFactory(Executor ioExecutor, EventBus eventBus,
Context appContext) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory;
this.app = app;
this.appContext = appContext;
}
@Override
@@ -61,11 +49,9 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory {
@Override
public DuplexPlugin createPlugin(PluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
AndroidLanTcpPlugin plugin = new AndroidLanTcpPlugin(ioExecutor,
wakefulIoExecutor, app, backoff, callback,
MAX_LATENCY, MAX_IDLE_TIME, CONNECTION_TIMEOUT);
appContext, callback, MAX_LATENCY, MAX_IDLE_TIME,
POLLING_INTERVAL, CONNECTION_TIMEOUT);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,60 +1,61 @@
package org.briarproject.bramble.plugin.tor;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.PowerManager;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.util.RenewableWakeLock;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.net.SocketFactory;
import static android.content.Context.MODE_PRIVATE;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.briarproject.bramble.util.AndroidUtils.getWakeLockTag;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class AndroidTorPlugin extends TorPlugin {
private final Application app;
private final AndroidWakeLock wakeLock;
private final Context appContext;
private final RenewableWakeLock wakeLock;
AndroidTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Application app,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
AndroidTorPlugin(Executor ioExecutor, ScheduledExecutorService scheduler,
Context appContext, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
AndroidWakeLockManager wakeLockManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
int maxLatency,
int maxIdleTime,
File torDirectory) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
PluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, int initialPollingInterval,
int stablePollingInterval) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
torRendezvousCrypto, callback, architecture, maxLatency,
maxIdleTime, torDirectory);
this.app = app;
wakeLock = wakeLockManager.createWakeLock("TorPlugin");
maxIdleTime, initialPollingInterval, stablePollingInterval,
appContext.getDir("tor", MODE_PRIVATE));
this.appContext = appContext;
PowerManager pm = (PowerManager)
appContext.getSystemService(POWER_SERVICE);
if (pm == null) throw new AssertionError();
wakeLock = new RenewableWakeLock(pm, scheduler, PARTIAL_WAKE_LOCK,
getWakeLockTag(appContext), 1, MINUTES);
}
@Override
@@ -65,8 +66,8 @@ class AndroidTorPlugin extends TorPlugin {
@Override
protected long getLastUpdateTime() {
try {
PackageManager pm = app.getPackageManager();
PackageInfo pi = pm.getPackageInfo(app.getPackageName(), 0);
PackageManager pm = appContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(appContext.getPackageName(), 0);
return pi.lastUpdateTime;
} catch (NameNotFoundException e) {
throw new AssertionError(e);

View File

@@ -1,91 +1,86 @@
package org.briarproject.bramble.plugin.tor;
import android.app.Application;
import android.content.Context;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.bramble.util.AndroidUtils;
import java.io.File;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Logger.getLogger;
@Immutable
@NotNullByDefault
public class AndroidTorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG =
Logger.getLogger(AndroidTorPluginFactory.class.getName());
getLogger(AndroidTorPluginFactory.class.getName());
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private static final int MAX_LATENCY = (int) SECONDS.toMillis(30);
private static final int MAX_IDLE_TIME = (int) SECONDS.toMillis(30);
private final Executor ioExecutor, wakefulIoExecutor;
private final Application app;
/**
* How often to poll before our hidden service becomes reachable.
*/
private static final int INITIAL_POLLING_INTERVAL =
(int) MINUTES.toMillis(1);
/**
* How often to poll when our hidden service is reachable. Our contacts
* will poll when they come online, so our polling is just a fallback in
* case of repeated connection failures.
*/
private static final int STABLE_POLLING_INTERVAL =
(int) MINUTES.toMillis(15);
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final Context appContext;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final AndroidWakeLockManager wakeLockManager;
private final Clock clock;
private final File torDirectory;
@Inject
public AndroidTorPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
Application app,
NetworkManager networkManager,
LocationUtils locationUtils,
EventBus eventBus,
SocketFactory torSocketFactory,
BackoffFactory backoffFactory,
public AndroidTorPluginFactory(Executor ioExecutor,
ScheduledExecutorService scheduler, Context appContext,
NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
AndroidWakeLockManager wakeLockManager,
Clock clock,
@TorDirectory File torDirectory) {
BatteryManager batteryManager, Clock clock) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.app = app;
this.scheduler = scheduler;
this.appContext = appContext;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.wakeLockManager = wakeLockManager;
this.clock = clock;
this.torDirectory = torDirectory;
}
@Override
@@ -125,15 +120,13 @@ public class AndroidTorPluginFactory implements DuplexPluginFactory {
// Use position-independent executable
architecture += "_pie";
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor,
wakefulIoExecutor, app, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, wakeLockManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory);
AndroidTorPlugin plugin = new AndroidTorPlugin(ioExecutor, scheduler,
appContext, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
torRendezvousCrypto, callback, architecture, MAX_LATENCY,
MAX_IDLE_TIME, INITIAL_POLLING_INTERVAL,
STABLE_POLLING_INTERVAL);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,18 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
interface AlarmConstants {
/**
* Request code for the broadcast intent attached to the periodic alarm.
*/
int REQUEST_ALARM = 1;
/**
* Key for storing the process ID in the extras of the periodic alarm's
* intent. This allows us to ignore alarms scheduled by dead processes.
*/
String EXTRA_PID = "org.briarproject.bramble.EXTRA_PID";
}

View File

@@ -1,17 +0,0 @@
package org.briarproject.bramble.system;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.briarproject.bramble.BrambleApplication;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context ctx, Intent intent) {
BrambleApplication app =
(BrambleApplication) ctx.getApplicationContext();
app.getBrambleAppComponent().alarmListener().onAlarm(intent);
}
}

View File

@@ -1,17 +1,12 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.SecureRandomProvider;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import javax.inject.Singleton;
@@ -21,23 +16,6 @@ import dagger.Provides;
@Module
public class AndroidSystemModule {
private final ScheduledExecutorService scheduledExecutorService;
public AndroidSystemModule() {
// Discard tasks that are submitted during shutdown
RejectedExecutionHandler policy =
new ScheduledThreadPoolExecutor.DiscardPolicy();
scheduledExecutorService = new ScheduledThreadPoolExecutor(1, policy);
}
@Provides
@Singleton
ScheduledExecutorService provideScheduledExecutorService(
LifecycleManager lifecycleManager) {
lifecycleManager.registerForShutdown(scheduledExecutorService);
return scheduledExecutorService;
}
@Provides
@Singleton
SecureRandomProvider provideSecureRandomProvider(
@@ -69,11 +47,4 @@ public class AndroidSystemModule {
ResourceProvider provideResourceProvider(AndroidResourceProvider provider) {
return provider;
}
@Provides
@Singleton
AndroidWakeLockManager provideWakeLockManager(
AndroidWakeLockManagerImpl wakeLockManager) {
return wakeLockManager;
}
}

View File

@@ -1,242 +0,0 @@
package org.briarproject.bramble.system;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Process;
import android.os.SystemClock;
import org.briarproject.bramble.api.lifecycle.Service;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.Wakeful;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.INTERVAL_FIFTEEN_MINUTES;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
import static android.content.Context.ALARM_SERVICE;
import static android.os.Build.VERSION.SDK_INT;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.system.AlarmConstants.EXTRA_PID;
import static org.briarproject.bramble.system.AlarmConstants.REQUEST_ALARM;
@ThreadSafe
@NotNullByDefault
class AndroidTaskScheduler implements TaskScheduler, Service, AlarmListener {
private static final Logger LOG =
getLogger(AndroidTaskScheduler.class.getName());
private static final long ALARM_MS = INTERVAL_FIFTEEN_MINUTES;
private final Application app;
private final AndroidWakeLockManager wakeLockManager;
private final ScheduledExecutorService scheduledExecutorService;
private final AlarmManager alarmManager;
private final Object lock = new Object();
@GuardedBy("lock")
private final Queue<ScheduledTask> tasks = new PriorityQueue<>();
AndroidTaskScheduler(Application app,
AndroidWakeLockManager wakeLockManager,
ScheduledExecutorService scheduledExecutorService) {
this.app = app;
this.wakeLockManager = wakeLockManager;
this.scheduledExecutorService = scheduledExecutorService;
alarmManager = (AlarmManager)
requireNonNull(app.getSystemService(ALARM_SERVICE));
}
@Override
public void startService() {
scheduleAlarm();
}
@Override
public void stopService() {
cancelAlarm();
}
@Override
public Cancellable schedule(Runnable task, Executor executor, long delay,
TimeUnit unit) {
AtomicBoolean cancelled = new AtomicBoolean(false);
return schedule(task, executor, delay, unit, cancelled);
}
@Override
public Cancellable scheduleWithFixedDelay(Runnable task, Executor executor,
long delay, long interval, TimeUnit unit) {
AtomicBoolean cancelled = new AtomicBoolean(false);
return scheduleWithFixedDelay(task, executor, delay, interval, unit,
cancelled);
}
@Override
public void onAlarm(Intent intent) {
wakeLockManager.runWakefully(() -> {
int extraPid = intent.getIntExtra(EXTRA_PID, -1);
int currentPid = Process.myPid();
if (extraPid == currentPid) {
LOG.info("Alarm");
rescheduleAlarm();
runDueTasks();
} else if (LOG.isLoggable(INFO)) {
LOG.info("Ignoring alarm with PID " + extraPid
+ ", current PID is " + currentPid);
}
}, "TaskAlarm");
}
private Cancellable schedule(Runnable task, Executor executor, long delay,
TimeUnit unit, AtomicBoolean cancelled) {
long now = SystemClock.elapsedRealtime();
long dueMillis = now + MILLISECONDS.convert(delay, unit);
Runnable wakeful = () ->
wakeLockManager.executeWakefully(task, executor, "TaskHandoff");
Future<?> check = scheduleCheckForDueTasks(delay, unit);
ScheduledTask s = new ScheduledTask(wakeful, dueMillis, check,
cancelled);
synchronized (lock) {
tasks.add(s);
}
return s;
}
private Cancellable scheduleWithFixedDelay(Runnable task, Executor executor,
long delay, long interval, TimeUnit unit, AtomicBoolean cancelled) {
// All executions of this periodic task share a cancelled flag
Runnable wrapped = () -> {
task.run();
scheduleWithFixedDelay(task, executor, interval, interval, unit,
cancelled);
};
return schedule(wrapped, executor, delay, unit, cancelled);
}
private Future<?> scheduleCheckForDueTasks(long delay, TimeUnit unit) {
Runnable wakeful = () -> wakeLockManager.runWakefully(
this::runDueTasks, "TaskScheduler");
return scheduledExecutorService.schedule(wakeful, delay, unit);
}
@Wakeful
private void runDueTasks() {
long now = SystemClock.elapsedRealtime();
List<ScheduledTask> due = new ArrayList<>();
synchronized (lock) {
while (true) {
ScheduledTask s = tasks.peek();
if (s == null || s.dueMillis > now) break;
due.add(tasks.remove());
}
}
if (LOG.isLoggable(INFO)) {
LOG.info("Running " + due.size() + " due tasks");
}
for (ScheduledTask s : due) {
if (LOG.isLoggable(INFO)) {
LOG.info("Task is " + (now - s.dueMillis) + " ms overdue");
}
s.run();
}
}
private void scheduleAlarm() {
if (SDK_INT >= 23) scheduleIdleAlarm();
else scheduleInexactRepeatingAlarm();
}
private void rescheduleAlarm() {
// If SDK_INT < 23 the alarm repeats automatically
if (SDK_INT >= 23) scheduleIdleAlarm();
}
private void cancelAlarm() {
alarmManager.cancel(getAlarmPendingIntent());
}
private void scheduleInexactRepeatingAlarm() {
alarmManager.setInexactRepeating(ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + ALARM_MS, ALARM_MS,
getAlarmPendingIntent());
}
@TargetApi(23)
private void scheduleIdleAlarm() {
alarmManager.setAndAllowWhileIdle(ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + ALARM_MS,
getAlarmPendingIntent());
}
private PendingIntent getAlarmPendingIntent() {
Intent i = new Intent(app, AlarmReceiver.class);
i.putExtra(EXTRA_PID, android.os.Process.myPid());
return PendingIntent.getBroadcast(app, REQUEST_ALARM, i,
FLAG_CANCEL_CURRENT);
}
private class ScheduledTask
implements Runnable, Cancellable, Comparable<ScheduledTask> {
private final Runnable task;
private final long dueMillis;
private final Future<?> check;
private final AtomicBoolean cancelled;
public ScheduledTask(Runnable task, long dueMillis,
Future<?> check, AtomicBoolean cancelled) {
this.task = task;
this.dueMillis = dueMillis;
this.check = check;
this.cancelled = cancelled;
}
@Override
public void run() {
if (!cancelled.get()) task.run();
}
@Override
public void cancel() {
// Cancel any future executions of this task
cancelled.set(true);
// Cancel the scheduled check for due tasks
check.cancel(false);
// Remove the task from the queue
synchronized (lock) {
tasks.remove(this);
}
}
@Override
public int compareTo(ScheduledTask s) {
//noinspection UseCompareMethod
if (dueMillis < s.dueMillis) return -1;
if (dueMillis > s.dueMillis) return 1;
return 0;
}
}
}

View File

@@ -1,49 +0,0 @@
package org.briarproject.bramble.system;
import android.app.Application;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.AlarmListener;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class AndroidTaskSchedulerModule {
public static class EagerSingletons {
@Inject
AndroidTaskScheduler scheduler;
}
@Provides
@Singleton
AndroidTaskScheduler provideAndroidTaskScheduler(
LifecycleManager lifecycleManager, Application app,
AndroidWakeLockManager wakeLockManager,
ScheduledExecutorService scheduledExecutorService) {
AndroidTaskScheduler scheduler = new AndroidTaskScheduler(app,
wakeLockManager, scheduledExecutorService);
lifecycleManager.registerService(scheduler);
return scheduler;
}
@Provides
@Singleton
AlarmListener provideAlarmListener(AndroidTaskScheduler scheduler) {
return scheduler;
}
@Provides
@Singleton
TaskScheduler provideTaskScheduler(AndroidTaskScheduler scheduler) {
return scheduler;
}
}

View File

@@ -1,74 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.logging.Level.FINE;
import static java.util.logging.Logger.getLogger;
/**
* A wrapper around a {@link SharedWakeLock} that provides the more convenient
* semantics of {@link AndroidWakeLock} (i.e. calls to acquire() and release()
* don't need to be balanced).
*/
@ThreadSafe
@NotNullByDefault
class AndroidWakeLockImpl implements AndroidWakeLock {
private static final Logger LOG =
getLogger(AndroidWakeLockImpl.class.getName());
private static final AtomicInteger INSTANCE_ID = new AtomicInteger(0);
private final SharedWakeLock sharedWakeLock;
private final String tag;
private final Object lock = new Object();
@GuardedBy("lock")
private boolean held = false;
AndroidWakeLockImpl(SharedWakeLock sharedWakeLock, String tag) {
this.sharedWakeLock = sharedWakeLock;
this.tag = tag + "_" + INSTANCE_ID.getAndIncrement();
}
@Override
public void acquire() {
synchronized (lock) {
if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already acquired");
}
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " acquiring shared wake lock");
}
held = true;
sharedWakeLock.acquire();
}
}
}
@Override
public void release() {
synchronized (lock) {
if (held) {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " releasing shared wake lock");
}
held = false;
sharedWakeLock.release();
} else {
if (LOG.isLoggable(FINE)) {
LOG.fine(tag + " already released");
}
}
}
}
}

View File

@@ -1,119 +0,0 @@
package org.briarproject.bramble.system;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.PowerManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.inject.Inject;
import static android.content.Context.POWER_SERVICE;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@NotNullByDefault
class AndroidWakeLockManagerImpl implements AndroidWakeLockManager {
/**
* How often to replace the wake lock.
*/
private static final long LOCK_DURATION_MS = MINUTES.toMillis(1);
/**
* Automatically release the lock this many milliseconds after it's due
* to have been replaced and released.
*/
private static final long SAFETY_MARGIN_MS = SECONDS.toMillis(30);
private final SharedWakeLock sharedWakeLock;
@Inject
AndroidWakeLockManagerImpl(Application app,
ScheduledExecutorService scheduledExecutorService) {
PowerManager powerManager = (PowerManager)
requireNonNull(app.getSystemService(POWER_SERVICE));
String tag = getWakeLockTag(app);
sharedWakeLock = new RenewableWakeLock(powerManager,
scheduledExecutorService, PARTIAL_WAKE_LOCK, tag,
LOCK_DURATION_MS, SAFETY_MARGIN_MS);
}
@Override
public AndroidWakeLock createWakeLock(String tag) {
return new AndroidWakeLockImpl(sharedWakeLock, tag);
}
@Override
public void runWakefully(Runnable r, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
r.run();
} finally {
wakeLock.release();
}
}
@Override
public void executeWakefully(Runnable r, Executor executor, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
executor.execute(() -> {
try {
r.run();
} finally {
// Release the wake lock if the task throws an exception
wakeLock.release();
}
});
} catch (Exception e) {
// Release the wake lock if the executor throws an exception when
// we submit the task (in which case the release() call above won't
// happen)
wakeLock.release();
throw e;
}
}
@Override
public void executeWakefully(Runnable r, String tag) {
AndroidWakeLock wakeLock = createWakeLock(tag);
wakeLock.acquire();
try {
new Thread(() -> {
try {
r.run();
} finally {
wakeLock.release();
}
}).start();
} catch (Exception e) {
wakeLock.release();
throw e;
}
}
private String getWakeLockTag(Context ctx) {
PackageManager pm = ctx.getPackageManager();
for (PackageInfo info : pm.getInstalledPackages(0)) {
String name = info.packageName.toLowerCase();
if (name.startsWith("com.huawei.powergenie")) {
return "LocationManagerService";
} else if (name.startsWith("com.evenwell.powermonitor")) {
return "AudioIn";
}
}
return ctx.getPackageName();
}
}

View File

@@ -1,23 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.system.AndroidWakeLockManager;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;
import dagger.Module;
import dagger.Provides;
@Module
public
class AndroidWakefulIoExecutorModule {
@Provides
@WakefulIoExecutor
Executor provideWakefulIoExecutor(@IoExecutor Executor ioExecutor,
AndroidWakeLockManager wakeLockManager) {
return r -> wakeLockManager.executeWakefully(r, ioExecutor,
"WakefulIoExecutor");
}
}

View File

@@ -1,130 +0,0 @@
package org.briarproject.bramble.system;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
@ThreadSafe
@NotNullByDefault
class RenewableWakeLock implements SharedWakeLock {
private static final Logger LOG =
getLogger(RenewableWakeLock.class.getName());
private final PowerManager powerManager;
private final ScheduledExecutorService scheduledExecutorService;
private final int levelAndFlags;
private final String tag;
private final long durationMs, safetyMarginMs;
private final Object lock = new Object();
@GuardedBy("lock")
@Nullable
private WakeLock wakeLock;
@GuardedBy("lock")
@Nullable
private Future<?> future;
@GuardedBy("lock")
private int refCount = 0;
@GuardedBy("lock")
private long acquired = 0;
RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduledExecutorService,
int levelAndFlags,
String tag,
long durationMs,
long safetyMarginMs) {
this.powerManager = powerManager;
this.scheduledExecutorService = scheduledExecutorService;
this.levelAndFlags = levelAndFlags;
this.tag = tag;
this.durationMs = durationMs;
this.safetyMarginMs = safetyMarginMs;
}
@Override
public void acquire() {
synchronized (lock) {
refCount++;
if (refCount == 1) {
if (LOG.isLoggable(INFO)) {
LOG.info("Acquiring wake lock " + tag);
}
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
// We do our own reference counting so we can replace the lock
// TODO: Check whether using a ref-counted wake lock affects
// power management apps
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs);
future = scheduledExecutorService.schedule(this::renew,
durationMs, MILLISECONDS);
acquired = android.os.SystemClock.elapsedRealtime();
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
}
}
private void renew() {
if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
long now = android.os.SystemClock.elapsedRealtime();
long expiry = acquired + durationMs + safetyMarginMs;
if (now > expiry && LOG.isLoggable(WARNING)) {
LOG.warning("Wake lock expired " + (now - expiry) + " ms ago");
}
WakeLock oldWakeLock = wakeLock;
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + safetyMarginMs);
oldWakeLock.release();
future = scheduledExecutorService.schedule(this::renew, durationMs,
MILLISECONDS);
acquired = now;
}
}
@Override
public void release() {
synchronized (lock) {
refCount--;
if (refCount == 0) {
if (LOG.isLoggable(INFO)) {
LOG.info("Releasing wake lock " + tag);
}
requireNonNull(future).cancel(false);
future = null;
requireNonNull(wakeLock).release();
wakeLock = null;
acquired = 0;
} else if (LOG.isLoggable(FINE)) {
LOG.fine("Wake lock " + tag + " has " + refCount + " holders");
}
}
}
}

View File

@@ -1,22 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidWakeLock;
@NotNullByDefault
interface SharedWakeLock {
/**
* Acquires the wake lock. This increments the wake lock's reference count,
* so unlike {@link AndroidWakeLock#acquire()} every call to this method
* must be followed by a balancing call to {@link #release()}.
*/
void acquire();
/**
* Releases the wake lock. This decrements the wake lock's reference count,
* so unlike {@link AndroidWakeLock#release()} every call to this method
* must follow a balancing call to {@link #acquire()}.
*/
void release();
}

View File

@@ -3,6 +3,8 @@ package org.briarproject.bramble.util;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.provider.Settings;
@@ -117,4 +119,17 @@ public class AndroidUtils {
if (SDK_INT < 24) return new String[] {"image/jpeg", "image/png"};
else return new String[] {"image/jpeg", "image/png", "image/gif"};
}
public static String getWakeLockTag(Context ctx) {
PackageManager pm = ctx.getPackageManager();
for (PackageInfo info : pm.getInstalledPackages(0)) {
String name = info.packageName.toLowerCase();
if (name.startsWith("com.huawei.powergenie")) {
return "LocationManagerService";
} else if (name.startsWith("com.evenwell.powermonitor")) {
return "AudioIn";
}
}
return ctx.getPackageName();
}
}

View File

@@ -0,0 +1,100 @@
package org.briarproject.bramble.util;
import android.os.PowerManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO;
@ThreadSafe
@NotNullByDefault
public class RenewableWakeLock {
private static final Logger LOG =
Logger.getLogger(RenewableWakeLock.class.getName());
/**
* Automatically release the lock this many milliseconds after it's due
* to have been replaced and released.
*/
private static final int SAFETY_MARGIN_MS = 10_000;
private final PowerManager powerManager;
private final ScheduledExecutorService scheduler;
private final int levelAndFlags;
private final String tag;
private final long durationMs;
private final Runnable renewTask;
private final Object lock = new Object();
@Nullable
private PowerManager.WakeLock wakeLock; // Locking: lock
@Nullable
private ScheduledFuture future; // Locking: lock
public RenewableWakeLock(PowerManager powerManager,
ScheduledExecutorService scheduler, int levelAndFlags, String tag,
long duration, TimeUnit timeUnit) {
this.powerManager = powerManager;
this.scheduler = scheduler;
this.levelAndFlags = levelAndFlags;
this.tag = tag;
durationMs = MILLISECONDS.convert(duration, timeUnit);
renewTask = this::renew;
}
public void acquire() {
if (LOG.isLoggable(INFO)) LOG.info("Acquiring wake lock " + tag);
synchronized (lock) {
if (wakeLock != null) {
LOG.info("Already acquired");
return;
}
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
}
}
private void renew() {
if (LOG.isLoggable(INFO)) LOG.info("Renewing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
PowerManager.WakeLock oldWakeLock = wakeLock;
wakeLock = powerManager.newWakeLock(levelAndFlags, tag);
wakeLock.setReferenceCounted(false);
wakeLock.acquire(durationMs + SAFETY_MARGIN_MS);
oldWakeLock.release();
future = scheduler.schedule(renewTask, durationMs, MILLISECONDS);
}
}
public void release() {
if (LOG.isLoggable(INFO)) LOG.info("Releasing wake lock " + tag);
synchronized (lock) {
if (wakeLock == null) {
LOG.info("Already released");
return;
}
if (future == null) throw new AssertionError();
future.cancel(false);
future = null;
wakeLock.release();
wakeLock = null;
}
}
}

View File

@@ -7,10 +7,6 @@ public interface TimeoutMonitor {
/**
* Returns an {@link InputStream} that wraps the given stream and allows
* read timeouts to be detected.
* <p>
* The returned stream must be {@link InputStream#close() closed} when it's
* no longer needed to ensure that resources held by the timeout monitor
* are released.
*
* @param timeoutMs The read timeout in milliseconds. Timeouts will be
* detected eventually but are not guaranteed to be detected immediately.

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.Wakeful;
import java.util.concurrent.ExecutorService;
@@ -66,7 +65,6 @@ public interface LifecycleManager {
* Opens the {@link DatabaseComponent} using the given key and starts any
* registered {@link Service Services}.
*/
@Wakeful
StartResult startServices(SecretKey dbKey);
/**
@@ -74,7 +72,6 @@ public interface LifecycleManager {
* registered {@link ExecutorService ExecutorServices}, and closes the
* {@link DatabaseComponent}.
*/
@Wakeful
void stopServices();
/**
@@ -107,7 +104,6 @@ public interface LifecycleManager {
*
* @param txn A read-write transaction
*/
@Wakeful
void onDatabaseOpened(Transaction txn) throws DbException;
}
}

View File

@@ -1,20 +1,16 @@
package org.briarproject.bramble.api.lifecycle;
import org.briarproject.bramble.api.system.Wakeful;
public interface Service {
/**
* Starts the service. This method must not be called concurrently with
* Starts the service.This method must not be called concurrently with
* {@link #stopService()}.
*/
@Wakeful
void startService() throws ServiceException;
/**
* Stops the service. This method must not be called concurrently with
* {@link #startService()}.
*/
@Wakeful
void stopService() throws ServiceException;
}

View File

@@ -1,22 +0,0 @@
package org.briarproject.bramble.api.plugin;
/**
* 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();
}

View File

@@ -1,7 +0,0 @@
package org.briarproject.bramble.api.plugin;
public interface BackoffFactory {
Backoff createBackoff(int minInterval, int maxInterval,
double base);
}

View File

@@ -10,12 +10,6 @@ public interface BluetoothConstants {
String PROP_ADDRESS = "address";
String PROP_UUID = "uuid";
// Local settings (not shared with contacts)
String PREF_ADDRESS_IS_REFLECTED = "addressIsReflected";
String PREF_EVER_CONNECTED = "everConnected";
// Default values for local settings
// Default value for PREF_PLUGIN_ENABLE
boolean DEFAULT_PREF_PLUGIN_ENABLE = false;
boolean DEFAULT_PREF_ADDRESS_IS_REFLECTED = false;
boolean DEFAULT_PREF_EVER_CONNECTED = false;
}

View File

@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.system.Wakeful;
import java.util.Collection;
@@ -71,13 +70,11 @@ public interface Plugin {
/**
* Starts the plugin.
*/
@Wakeful
void start() throws PluginException;
/**
* Stops the plugin.
*/
@Wakeful
void stop() throws PluginException;
/**
@@ -109,7 +106,6 @@ public interface Plugin {
* Attempts to create connections using the given transport properties,
* passing any created connections to the corresponding handlers.
*/
@Wakeful
void poll(Collection<Pair<TransportProperties, ConnectionHandler>>
properties);
}

View File

@@ -8,8 +8,6 @@ import org.briarproject.bramble.api.plugin.event.TransportStateEvent;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import java.util.Collection;
/**
* An interface through which a transport plugin interacts with the rest of
* the application.
@@ -27,11 +25,6 @@ public interface PluginCallback extends ConnectionHandler {
*/
TransportProperties getLocalProperties();
/**
* Returns the plugin's remote transport properties.
*/
Collection<TransportProperties> getRemoteProperties();
/**
* Merges the given settings with the plugin's settings
*/

View File

@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
import org.briarproject.bramble.api.system.Wakeful;
import javax.annotation.Nullable;
@@ -22,7 +21,6 @@ public interface DuplexPlugin extends Plugin {
* Attempts to create and return a connection using the given transport
* properties. Returns null if a connection cannot be created.
*/
@Wakeful
@Nullable
DuplexTransportConnection createConnection(TransportProperties p);

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that informs the Bluetooth plugin that we have enabled the
* Bluetooth adapter.
*/
@Immutable
@NotNullByDefault
public class BluetoothEnabledEvent extends Event {
}

View File

@@ -0,0 +1,15 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that asks the Bluetooth plugin to disable the Bluetooth adapter if
* we previously enabled it.
*/
@Immutable
@NotNullByDefault
public class DisableBluetoothEvent extends Event {
}

View File

@@ -0,0 +1,14 @@
package org.briarproject.bramble.api.plugin.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that asks the Bluetooth plugin to enable the Bluetooth adapter.
*/
@Immutable
@NotNullByDefault
public class EnableBluetoothEvent extends Event {
}

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.plugin.Plugin;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.system.Wakeful;
import javax.annotation.Nullable;
@@ -19,7 +18,6 @@ public interface SimplexPlugin extends Plugin {
* Attempts to create and return a reader for the given transport
* properties. Returns null if a reader cannot be created.
*/
@Wakeful
@Nullable
TransportConnectionReader createReader(TransportProperties p);
@@ -27,7 +25,6 @@ public interface SimplexPlugin extends Plugin {
* Attempts to create and return a writer for the given transport
* properties. Returns null if a writer cannot be created.
*/
@Wakeful
@Nullable
TransportConnectionWriter createWriter(TransportProperties p);
}

View File

@@ -12,11 +12,6 @@ public interface TransportPropertyConstants {
*/
int MAX_PROPERTY_LENGTH = 100;
/**
* Prefix for keys that represent reflected properties.
*/
String REFLECTED_PROPERTY_PREFIX = "u:";
/**
* Message metadata key for the transport ID of a local or remote update,
* as a BDF string.

View File

@@ -1,27 +0,0 @@
package org.briarproject.bramble.api.properties.event;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when {@link TransportProperties} are received
* from a contact.
*/
@Immutable
@NotNullByDefault
public class RemoteTransportPropertiesUpdatedEvent extends Event {
private final TransportId transportId;
public RemoteTransportPropertiesUpdatedEvent(TransportId transportId) {
this.transportId = transportId;
}
public TransportId getTransportId() {
return transportId;
}
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.api.plugin;
package org.briarproject.bramble.api.system;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -12,11 +11,15 @@ import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the {@link File directory} where the Tor plugin
* should store its state.
* Annotation for injecting a scheduled executor service
* that can be used to schedule the execution of tasks.
* <p>
* The service should <b>only</b> be used for running tasks on other executors
* at scheduled times.
* No significant work should be run by the service itself!
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface TorDirectory {
}
public @interface Scheduler {
}

View File

@@ -1,43 +0,0 @@
package org.briarproject.bramble.api.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
/**
* A service that can be used to schedule the execution of tasks.
*/
@NotNullByDefault
public interface TaskScheduler {
/**
* Submits the given task to the given executor after the given delay.
* <p>
* If the platform supports wake locks, a wake lock will be held while
* submitting and running the task.
*/
Cancellable schedule(Runnable task, Executor executor, long delay,
TimeUnit unit);
/**
* Submits the given task to the given executor after the given delay,
* and then repeatedly with the given interval between executions
* (measured from the end of one execution to the beginning of the next).
* <p>
* If the platform supports wake locks, a wake lock will be held while
* submitting and running the task.
*/
Cancellable scheduleWithFixedDelay(Runnable task, Executor executor,
long delay, long interval, TimeUnit unit);
interface Cancellable {
/**
* Cancels the task if it has not already started running. If the task
* is {@link #scheduleWithFixedDelay(Runnable, Executor, long, long, TimeUnit) periodic},
* all future executions of the task are cancelled.
*/
void cancel();
}
}

View File

@@ -1,19 +0,0 @@
package org.briarproject.bramble.api.system;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for methods that must be called while holding a wake lock, if
* the platform supports wake locks.
*/
@Qualifier
@Target(METHOD)
@Retention(RUNTIME)
public @interface Wakeful {
}

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api.system;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation for injecting the executor for long-running IO tasks that should
* run without sleeping. Also used for annotating methods that should run on
* this executor.
* <p>
* The contract of this executor is that tasks may be run concurrently, and
* submitting a task will never block. Tasks must not run indefinitely. Tasks
* submitted during shutdown are discarded.
*/
@Qualifier
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
public @interface WakefulIoExecutor {
}

View File

@@ -9,6 +9,7 @@ import org.briarproject.bramble.plugin.PluginModule;
import org.briarproject.bramble.properties.PropertiesModule;
import org.briarproject.bramble.rendezvous.RendezvousModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule;
@@ -30,6 +31,8 @@ public interface BrambleCoreEagerSingletons {
void inject(RendezvousModule.EagerSingletons init);
void inject(SystemModule.EagerSingletons init);
void inject(TransportModule.EagerSingletons init);
void inject(ValidationModule.EagerSingletons init);
@@ -47,6 +50,7 @@ public interface BrambleCoreEagerSingletons {
c.inject(new RendezvousModule.EagerSingletons());
c.inject(new PluginModule.EagerSingletons());
c.inject(new PropertiesModule.EagerSingletons());
c.inject(new SystemModule.EagerSingletons());
c.inject(new TransportModule.EagerSingletons());
c.inject(new ValidationModule.EagerSingletons());
c.inject(new VersioningModule.EagerSingletons());

View File

@@ -21,7 +21,7 @@ import org.briarproject.bramble.rendezvous.RendezvousModule;
import org.briarproject.bramble.settings.SettingsModule;
import org.briarproject.bramble.sync.SyncModule;
import org.briarproject.bramble.sync.validation.ValidationModule;
import org.briarproject.bramble.system.ClockModule;
import org.briarproject.bramble.system.SystemModule;
import org.briarproject.bramble.transport.TransportModule;
import org.briarproject.bramble.versioning.VersioningModule;
@@ -29,7 +29,6 @@ import dagger.Module;
@Module(includes = {
ClientModule.class,
ClockModule.class,
ConnectionModule.class,
ContactModule.class,
CryptoModule.class,
@@ -49,6 +48,7 @@ import dagger.Module;
RendezvousModule.class,
SettingsModule.class,
SyncModule.class,
SystemModule.class,
TransportModule.class,
ValidationModule.class,
VersioningModule.class

View File

@@ -3,15 +3,15 @@ package org.briarproject.bramble.io;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import org.briarproject.bramble.api.system.Wakeful;
import org.briarproject.bramble.api.system.Scheduler;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Logger;
import javax.annotation.concurrent.GuardedBy;
@@ -30,7 +30,7 @@ class TimeoutMonitorImpl implements TimeoutMonitor {
private static final long CHECK_INTERVAL_MS = SECONDS.toMillis(10);
private final TaskScheduler scheduler;
private final ScheduledExecutorService scheduler;
private final Executor ioExecutor;
private final Clock clock;
private final Object lock = new Object();
@@ -38,10 +38,10 @@ class TimeoutMonitorImpl implements TimeoutMonitor {
private final List<TimeoutInputStream> streams = new ArrayList<>();
@GuardedBy("lock")
private Cancellable cancellable = null;
private Future<?> task = null;
@Inject
TimeoutMonitorImpl(TaskScheduler scheduler,
TimeoutMonitorImpl(@Scheduler ScheduledExecutorService scheduler,
@IoExecutor Executor ioExecutor, Clock clock) {
this.scheduler = scheduler;
this.ioExecutor = ioExecutor;
@@ -55,9 +55,8 @@ class TimeoutMonitorImpl implements TimeoutMonitor {
timeoutMs, this::removeStream);
synchronized (lock) {
if (streams.isEmpty()) {
cancellable = scheduler.scheduleWithFixedDelay(
this::checkTimeouts, ioExecutor, CHECK_INTERVAL_MS,
CHECK_INTERVAL_MS, MILLISECONDS);
task = scheduler.scheduleWithFixedDelay(this::checkTimeouts,
CHECK_INTERVAL_MS, CHECK_INTERVAL_MS, MILLISECONDS);
}
streams.add(stream);
}
@@ -65,35 +64,33 @@ class TimeoutMonitorImpl implements TimeoutMonitor {
}
private void removeStream(TimeoutInputStream stream) {
Cancellable toCancel = null;
Future<?> toCancel = null;
synchronized (lock) {
if (streams.remove(stream) && streams.isEmpty()) {
toCancel = cancellable;
cancellable = null;
toCancel = task;
task = null;
}
}
if (toCancel != null) {
LOG.info("Cancelling timeout monitor task");
toCancel.cancel();
}
if (toCancel != null) toCancel.cancel(false);
}
@IoExecutor
@Wakeful
@Scheduler
private void checkTimeouts() {
List<TimeoutInputStream> snapshot;
synchronized (lock) {
snapshot = new ArrayList<>(streams);
}
for (TimeoutInputStream stream : snapshot) {
if (stream.hasTimedOut()) {
LOG.info("Input stream has timed out");
try {
stream.close();
} catch (IOException e) {
logException(LOG, INFO, e);
ioExecutor.execute(() -> {
List<TimeoutInputStream> snapshot;
synchronized (lock) {
snapshot = new ArrayList<>(streams);
}
for (TimeoutInputStream stream : snapshot) {
if (stream.hasTimedOut()) {
LOG.info("Input stream has timed out");
try {
stream.close();
} catch (IOException e) {
logException(LOG, INFO, e);
}
}
}
}
});
}
}

View File

@@ -1,18 +0,0 @@
package org.briarproject.bramble.plugin;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
class BackoffFactoryImpl implements BackoffFactory {
@Override
public Backoff createBackoff(int minInterval, int maxInterval,
double base) {
return new BackoffImpl(minInterval, maxInterval, base);
}
}

View File

@@ -1,42 +0,0 @@
package org.briarproject.bramble.plugin;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.concurrent.ThreadSafe;
@ThreadSafe
@NotNullByDefault
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);
}
}

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.plugin;
import org.briarproject.bramble.api.connection.ConnectionManager;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
@@ -29,7 +28,6 @@ import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.api.settings.SettingsManager;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.ArrayList;
import java.util.Collection;
@@ -46,14 +44,12 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject;
import static java.util.Collections.emptyList;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
@@ -66,7 +62,7 @@ class PluginManagerImpl implements PluginManager, Service {
private static final Logger LOG =
getLogger(PluginManagerImpl.class.getName());
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final EventBus eventBus;
private final PluginConfig pluginConfig;
private final ConnectionManager connectionManager;
@@ -79,15 +75,11 @@ class PluginManagerImpl implements PluginManager, Service {
private final AtomicBoolean used = new AtomicBoolean(false);
@Inject
PluginManagerImpl(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
EventBus eventBus,
PluginConfig pluginConfig,
ConnectionManager connectionManager,
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
PluginConfig pluginConfig, ConnectionManager connectionManager,
SettingsManager settingsManager,
TransportPropertyManager transportPropertyManager) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.eventBus = eventBus;
this.pluginConfig = pluginConfig;
this.connectionManager = connectionManager;
@@ -115,7 +107,7 @@ class PluginManagerImpl implements PluginManager, Service {
simplexPlugins.add(s);
CountDownLatch startLatch = new CountDownLatch(1);
startLatches.put(t, startLatch);
wakefulIoExecutor.execute(new PluginStarter(s, startLatch));
ioExecutor.execute(new PluginStarter(s, startLatch));
}
}
// Instantiate the duplex plugins and start them asynchronously
@@ -131,7 +123,7 @@ class PluginManagerImpl implements PluginManager, Service {
duplexPlugins.add(d);
CountDownLatch startLatch = new CountDownLatch(1);
startLatches.put(t, startLatch);
wakefulIoExecutor.execute(new PluginStarter(d, startLatch));
ioExecutor.execute(new PluginStarter(d, startLatch));
}
}
}
@@ -143,16 +135,12 @@ class PluginManagerImpl implements PluginManager, Service {
LOG.info("Stopping simplex plugins");
for (SimplexPlugin s : simplexPlugins) {
CountDownLatch startLatch = startLatches.get(s.getId());
// Don't need the wakeful executor here as we wait for the plugin
// to stop before returning
ioExecutor.execute(new PluginStopper(s, startLatch, stopLatch));
}
// Stop the duplex plugins
LOG.info("Stopping duplex plugins");
for (DuplexPlugin d : duplexPlugins) {
CountDownLatch startLatch = startLatches.get(d.getId());
// Don't need the wakeful executor here as we wait for the plugin
// to stop before returning
ioExecutor.execute(new PluginStopper(d, startLatch, stopLatch));
}
// Wait for all the plugins to stop
@@ -215,7 +203,7 @@ class PluginManagerImpl implements PluginManager, Service {
}
}
private static class PluginStarter implements Runnable {
private class PluginStarter implements Runnable {
private final Plugin plugin;
private final CountDownLatch startLatch;
@@ -245,7 +233,7 @@ class PluginManagerImpl implements PluginManager, Service {
}
}
private static class PluginStopper implements Runnable {
private class PluginStopper implements Runnable {
private final Plugin plugin;
private final CountDownLatch startLatch, stopLatch;
@@ -315,18 +303,6 @@ class PluginManagerImpl implements PluginManager, Service {
}
}
@Override
public Collection<TransportProperties> getRemoteProperties() {
try {
Map<ContactId, TransportProperties> remote =
transportPropertyManager.getRemoteProperties(id);
return remote.values();
} catch (DbException e) {
logException(LOG, WARNING, e);
return emptyList();
}
}
@Override
public void mergeSettings(Settings s) {
PluginManagerImpl.this.mergeSettings(s, id.getString());
@@ -355,10 +331,6 @@ class PluginManagerImpl implements PluginManager, Service {
} else if (oldState == ACTIVE) {
eventBus.broadcast(new TransportInactiveEvent(id));
}
} else if (newState == DISABLED) {
// Broadcast an event even though the state hasn't changed, as
// the reasons for the plugin being disabled may have changed
eventBus.broadcast(new TransportStateEvent(id, newState));
}
}

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.plugin;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginConfig;
import org.briarproject.bramble.api.plugin.PluginManager;
@@ -22,11 +21,6 @@ public class PluginModule {
Poller poller;
}
@Provides
BackoffFactory provideBackoffFactory() {
return new BackoffFactoryImpl();
}
@Provides
@Singleton
PluginManager providePluginManager(LifecycleManager lifecycleManager,

View File

@@ -19,17 +19,13 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import org.briarproject.bramble.api.system.Wakeful;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.bramble.api.system.Scheduler;
import java.security.SecureRandom;
import java.util.ArrayList;
@@ -38,6 +34,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
@@ -58,8 +56,8 @@ class PollerImpl implements Poller, EventListener {
private static final Logger LOG = getLogger(PollerImpl.class.getName());
private final Executor ioExecutor, wakefulIoExecutor;
private final TaskScheduler scheduler;
private final Executor ioExecutor;
private final ScheduledExecutorService scheduler;
private final ConnectionManager connectionManager;
private final ConnectionRegistry connectionRegistry;
private final PluginManager pluginManager;
@@ -72,16 +70,12 @@ class PollerImpl implements Poller, EventListener {
@Inject
PollerImpl(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
TaskScheduler scheduler,
@Scheduler ScheduledExecutorService scheduler,
ConnectionManager connectionManager,
ConnectionRegistry connectionRegistry,
PluginManager pluginManager,
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
TransportPropertyManager transportPropertyManager,
SecureRandom random,
Clock clock) {
SecureRandom random, Clock clock) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.scheduler = scheduler;
this.connectionManager = connectionManager;
this.connectionRegistry = connectionRegistry;
@@ -101,16 +95,10 @@ class PollerImpl implements Poller, EventListener {
connectToContact(c.getContactId());
} else if (e instanceof ConnectionClosedEvent) {
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
// Reschedule polling, the polling interval may have decreased
reschedule(c.getTransportId());
// If an outgoing connection failed, try to reconnect
if (!c.isIncoming() && c.isException()) {
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 TransportActiveEvent) {
TransportActiveEvent t = (TransportActiveEvent) e;
// Poll the newly activated transport
@@ -138,7 +126,7 @@ class PollerImpl implements Poller, EventListener {
}
private void connectToContact(ContactId c, SimplexPlugin p) {
wakefulIoExecutor.execute(() -> {
ioExecutor.execute(() -> {
TransportId t = p.getId();
if (connectionRegistry.isConnected(c, t)) return;
try {
@@ -154,7 +142,7 @@ class PollerImpl implements Poller, EventListener {
}
private void connectToContact(ContactId c, DuplexPlugin p) {
wakefulIoExecutor.execute(() -> {
ioExecutor.execute(() -> {
TransportId t = p.getId();
if (connectionRegistry.isConnected(c, t)) return;
try {
@@ -169,12 +157,6 @@ class PollerImpl implements Poller, EventListener {
});
}
private void reschedule(TransportId t) {
Plugin p = pluginManager.getPlugin(t);
if (p != null && p.shouldPoll())
schedule(p, p.getPollingInterval(), false);
}
private void pollNow(TransportId t) {
Plugin p = pluginManager.getPlugin(t);
// Randomise next polling interval
@@ -191,11 +173,11 @@ class PollerImpl implements Poller, EventListener {
if (scheduled == null || due < scheduled.task.due) {
// If a later task exists, cancel it. If it's already started
// it will abort safely when it finds it's been replaced
if (scheduled != null) scheduled.cancellable.cancel();
if (scheduled != null) scheduled.future.cancel(false);
PollTask task = new PollTask(p, due, randomiseNext);
Cancellable cancellable = scheduler.schedule(task, ioExecutor,
delay, MILLISECONDS);
tasks.put(t, new ScheduledPollTask(task, cancellable));
Future future = scheduler.schedule(() ->
ioExecutor.execute(task), delay, MILLISECONDS);
tasks.put(t, new ScheduledPollTask(task, future));
}
} finally {
lock.unlock();
@@ -206,7 +188,7 @@ class PollerImpl implements Poller, EventListener {
lock.lock();
try {
ScheduledPollTask scheduled = tasks.remove(t);
if (scheduled != null) scheduled.cancellable.cancel();
if (scheduled != null) scheduled.future.cancel(false);
} finally {
lock.unlock();
}
@@ -237,11 +219,11 @@ class PollerImpl implements Poller, EventListener {
private class ScheduledPollTask {
private final PollTask task;
private final Cancellable cancellable;
private final Future future;
private ScheduledPollTask(PollTask task, Cancellable cancellable) {
private ScheduledPollTask(PollTask task, Future future) {
this.task = task;
this.cancellable = cancellable;
this.future = future;
}
}
@@ -259,7 +241,6 @@ class PollerImpl implements Poller, EventListener {
@Override
@IoExecutor
@Wakeful
public void run() {
lock.lock();
try {

View File

@@ -1,14 +0,0 @@
package org.briarproject.bramble.plugin.bluetooth;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import java.io.IOException;
@NotNullByDefault
interface BluetoothConnectionFactory<S> {
DuplexTransportConnection wrapSocket(DuplexPlugin plugin, S socket)
throws IOException;
}

View File

@@ -1,11 +1,11 @@
package org.briarproject.bramble.plugin.bluetooth;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.Multiset;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
@@ -14,15 +14,16 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.ConnectionHandler;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.PluginException;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent;
import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent;
import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.event.RemoteTransportPropertiesUpdatedEvent;
import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
import org.briarproject.bramble.api.settings.Settings;
@@ -44,12 +45,8 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.DEFAULT_PREF_ADDRESS_IS_REFLECTED;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.DEFAULT_PREF_EVER_CONNECTED;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.DEFAULT_PREF_PLUGIN_ENABLE;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_ADDRESS_IS_REFLECTED;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_EVER_CONNECTED;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES;
@@ -57,7 +54,6 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED;
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.REFLECTED_PROPERTY_PREFIX;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
@@ -66,21 +62,19 @@ import static org.briarproject.bramble.util.StringUtils.macToString;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
private static final Logger LOG =
getLogger(BluetoothPlugin.class.getName());
final BluetoothConnectionLimiter connectionLimiter;
final BluetoothConnectionFactory<S> connectionFactory;
final TimeoutMonitor timeoutMonitor;
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final SecureRandom secureRandom;
private final Backoff backoff;
private final PluginCallback callback;
private final int maxLatency, maxIdleTime;
private final int maxLatency, maxIdleTime, pollingInterval;
private final AtomicBoolean used = new AtomicBoolean(false);
private final AtomicBoolean everConnected = new AtomicBoolean(false);
protected final PluginState state = new PluginState();
@@ -90,6 +84,12 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
abstract boolean isAdapterEnabled();
abstract void enableAdapter();
abstract void disableAdapterIfEnabledByUs();
abstract void setEnabledByUs();
/**
* Returns the local Bluetooth address, or null if no valid address can
* be found.
@@ -113,23 +113,17 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
abstract DuplexTransportConnection discoverAndConnect(String uuid);
BluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
BluetoothConnectionFactory<S> connectionFactory,
Executor ioExecutor,
Executor wakefulIoExecutor,
SecureRandom secureRandom,
Backoff backoff,
PluginCallback callback,
int maxLatency,
int maxIdleTime) {
TimeoutMonitor timeoutMonitor, Executor ioExecutor,
SecureRandom secureRandom, PluginCallback callback, int maxLatency, int maxIdleTime,
int pollingInterval) {
this.connectionLimiter = connectionLimiter;
this.connectionFactory = connectionFactory;
this.timeoutMonitor = timeoutMonitor;
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.secureRandom = secureRandom;
this.backoff = backoff;
this.callback = callback;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
this.pollingInterval = pollingInterval;
}
void onAdapterEnabled() {
@@ -171,8 +165,6 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
Settings settings = callback.getSettings();
boolean enabledByUser = settings.getBoolean(PREF_PLUGIN_ENABLE,
DEFAULT_PREF_PLUGIN_ENABLE);
everConnected.set(settings.getBoolean(PREF_EVER_CONNECTED,
DEFAULT_PREF_EVER_CONNECTED));
state.setStarted(enabledByUser);
try {
initialiseAdapter();
@@ -180,7 +172,10 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
throw new PluginException(e);
}
updateProperties();
if (enabledByUser && isAdapterEnabled()) bind();
if (enabledByUser) {
if (isAdapterEnabled()) bind();
else enableAdapter();
}
}
private void bind() {
@@ -199,7 +194,6 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
tryToClose(ss);
return;
}
backoff.reset();
acceptContactConnections(ss);
});
}
@@ -208,68 +202,25 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
TransportProperties p = callback.getLocalProperties();
String address = p.get(PROP_ADDRESS);
String uuid = p.get(PROP_UUID);
Settings s = callback.getSettings();
boolean isReflected = s.getBoolean(PREF_ADDRESS_IS_REFLECTED,
DEFAULT_PREF_ADDRESS_IS_REFLECTED);
boolean changed = false;
if (address == null || isReflected) {
if (address == null) {
address = getBluetoothAddress();
if (LOG.isLoggable(INFO)) {
if (LOG.isLoggable(INFO))
LOG.info("Local address " + scrubMacAddress(address));
}
if (address == null) {
if (everConnected.get()) {
address = getReflectedAddress();
if (LOG.isLoggable(INFO)) {
LOG.info("Reflected address " +
scrubMacAddress(address));
}
if (address != null) {
changed = true;
isReflected = true;
}
}
} else {
if (!isNullOrEmpty(address)) {
p.put(PROP_ADDRESS, address);
changed = true;
isReflected = false;
}
}
if (uuid == null) {
byte[] random = new byte[UUID_BYTES];
secureRandom.nextBytes(random);
uuid = UUID.nameUUIDFromBytes(random).toString();
p.put(PROP_UUID, uuid);
changed = true;
}
contactConnectionsUuid = uuid;
if (changed) {
p = new TransportProperties();
// If we previously used a reflected address and there's no longer
// a reflected address with enough votes to be used, we'll continue
// to use the old reflected address until there's a new winner
if (address != null) p.put(PROP_ADDRESS, address);
p.put(PROP_UUID, uuid);
callback.mergeLocalProperties(p);
s = new Settings();
s.putBoolean(PREF_ADDRESS_IS_REFLECTED, isReflected);
callback.mergeSettings(s);
}
}
@Nullable
private String getReflectedAddress() {
// Count the number of votes for each reflected address
String key = REFLECTED_PROPERTY_PREFIX + PROP_ADDRESS;
Multiset<String> votes = new Multiset<>();
for (TransportProperties p : callback.getRemoteProperties()) {
String address = p.get(key);
if (address != null && isValidAddress(address)) votes.add(address);
}
// If an address gets more than half of the votes, accept it
int total = votes.getTotal();
for (String address : votes.keySet()) {
if (votes.getCount(address) * 2 > total) return address;
}
return null;
if (changed) callback.mergeLocalProperties(p);
}
private void acceptContactConnections(SS ss) {
@@ -285,28 +236,15 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
}
LOG.info("Connection received");
connectionLimiter.connectionOpened(conn);
backoff.reset();
setEverConnected();
callback.handleConnection(conn);
}
}
private void setEverConnected() {
if (!everConnected.getAndSet(true)) {
ioExecutor.execute(() -> {
Settings s = new Settings();
s.putBoolean(PREF_EVER_CONNECTED, true);
callback.mergeSettings(s);
// Contacts may already have sent a reflected address
updateProperties();
});
}
}
@Override
public void stop() {
SS ss = state.setStopped();
tryToClose(ss);
disableAdapterIfEnabledByUs();
}
@Override
@@ -326,14 +264,13 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
@Override
public int getPollingInterval() {
return backoff.getPollingInterval();
return pollingInterval;
}
@Override
public void poll(Collection<Pair<TransportProperties, ConnectionHandler>>
properties) {
if (getState() != ACTIVE) return;
backoff.increment();
for (Pair<TransportProperties, ConnectionHandler> p : properties) {
connect(p.getFirst(), p.getSecond());
}
@@ -344,13 +281,9 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
if (isNullOrEmpty(address)) return;
String uuid = p.get(PROP_UUID);
if (isNullOrEmpty(uuid)) return;
wakefulIoExecutor.execute(() -> {
ioExecutor.execute(() -> {
DuplexTransportConnection d = createConnection(p);
if (d != null) {
backoff.reset();
setEverConnected();
h.handleConnection(d);
}
if (d != null) h.handleConnection(d);
});
}
@@ -451,10 +384,7 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
LOG.info("Connecting to key agreement UUID " + uuid);
conn = connect(address, uuid);
}
if (conn != null) {
connectionLimiter.connectionOpened(conn);
setEverConnected();
}
if (conn != null) connectionLimiter.connectionOpened(conn);
return conn;
}
@@ -477,7 +407,13 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
@Override
public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) {
if (e instanceof EnableBluetoothEvent) {
ioExecutor.execute(this::enableAdapter);
} else if (e instanceof DisableBluetoothEvent) {
ioExecutor.execute(this::disableAdapterIfEnabledByUs);
} else if (e instanceof BluetoothEnabledEvent) {
setEnabledByUs();
} else if (e instanceof SettingsUpdatedEvent) {
SettingsUpdatedEvent s = (SettingsUpdatedEvent) e;
if (s.getNamespace().equals(ID.getString()))
ioExecutor.execute(() -> onSettingsUpdated(s.getSettings()));
@@ -485,12 +421,6 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
ioExecutor.execute(connectionLimiter::keyAgreementStarted);
} else if (e instanceof KeyAgreementStoppedListeningEvent) {
ioExecutor.execute(connectionLimiter::keyAgreementEnded);
} else if (e instanceof RemoteTransportPropertiesUpdatedEvent) {
RemoteTransportPropertiesUpdatedEvent r =
(RemoteTransportPropertiesUpdatedEvent) e;
if (r.getTransportId().equals(ID)) {
ioExecutor.execute(this::updateProperties);
}
}
}
@@ -503,13 +433,11 @@ abstract class BluetoothPlugin<S, SS> implements DuplexPlugin, EventListener {
if (ss != null) {
LOG.info("Disabled by user, closing server socket");
tryToClose(ss);
disableAdapterIfEnabledByUs();
} else if (s == INACTIVE) {
if (isAdapterEnabled()) {
LOG.info("Enabled by user, opening server socket");
bind();
} else {
LOG.info("Enabled by user but adapter is disabled");
}
LOG.info("Enabled by user, opening server socket");
if (isAdapterEnabled()) bind();
else enableAdapter();
}
}

View File

@@ -5,7 +5,6 @@ import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.keyagreement.KeyAgreementConnection;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
@@ -88,15 +87,10 @@ class LanTcpPlugin extends TcpPlugin {
}
}
LanTcpPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Backoff backoff,
PluginCallback callback,
int maxLatency,
int maxIdleTime,
int connectionTimeout) {
super(ioExecutor, wakefulIoExecutor, backoff, callback, maxLatency,
maxIdleTime, connectionTimeout);
LanTcpPlugin(Executor ioExecutor, PluginCallback callback, int maxLatency,
int maxIdleTime, int pollingInterval, int connectionTimeout) {
super(ioExecutor, callback, maxLatency, maxIdleTime, pollingInterval,
connectionTimeout);
}
@Override
@@ -354,7 +348,7 @@ class LanTcpPlugin extends TcpPlugin {
tryToClose(ss, LOG, WARNING);
}
}
if (ss == null || !ss.isBound()) {
if (ss == null) {
LOG.info("Could not bind server socket for key agreement");
return null;
}

View File

@@ -1,47 +1,35 @@
package org.briarproject.bramble.plugin.tcp;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
@Immutable
@NotNullByDefault
public class LanTcpPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30_000; // 30 seconds
private static final int MAX_IDLE_TIME = 30_000; // 30 seconds
private static final int CONNECTION_TIMEOUT = 3_000; // 3 seconds
private static final int MIN_POLLING_INTERVAL = 60_000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 600_000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private static final int MAX_LATENCY = (int) SECONDS.toMillis(30);
private static final int MAX_IDLE_TIME = (int) SECONDS.toMillis(30);
private static final int POLLING_INTERVAL = (int) MINUTES.toMillis(1);
private static final int CONNECTION_TIMEOUT = (int) SECONDS.toMillis(3);
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final EventBus eventBus;
private final BackoffFactory backoffFactory;
@Inject
public LanTcpPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
EventBus eventBus,
BackoffFactory backoffFactory) {
public LanTcpPluginFactory(Executor ioExecutor, EventBus eventBus) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory;
}
@Override
@@ -56,10 +44,8 @@ public class LanTcpPluginFactory implements DuplexPluginFactory {
@Override
public DuplexPlugin createPlugin(PluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
LanTcpPlugin plugin = new LanTcpPlugin(ioExecutor, wakefulIoExecutor,
backoff, callback, MAX_LATENCY, MAX_IDLE_TIME,
LanTcpPlugin plugin = new LanTcpPlugin(ioExecutor, callback,
MAX_LATENCY, MAX_IDLE_TIME, POLLING_INTERVAL,
CONNECTION_TIMEOUT);
eventBus.addListener(plugin);
return plugin;

View File

@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.ConnectionHandler;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
@@ -66,10 +65,9 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
private static final Pattern DOTTED_QUAD =
Pattern.compile("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$");
protected final Executor ioExecutor, wakefulIoExecutor, bindExecutor;
protected final Backoff backoff;
protected final Executor ioExecutor, bindExecutor;
protected final PluginCallback callback;
protected final int maxLatency, maxIdleTime;
protected final int maxLatency, maxIdleTime, pollingInterval;
protected final int connectionTimeout, socketTimeout;
protected final AtomicBoolean used = new AtomicBoolean(false);
protected final PluginState state = new PluginState();
@@ -107,19 +105,13 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
*/
protected abstract boolean isEnabledByDefault();
TcpPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Backoff backoff,
PluginCallback callback,
int maxLatency,
int maxIdleTime,
int connectionTimeout) {
TcpPlugin(Executor ioExecutor, PluginCallback callback, int maxLatency,
int maxIdleTime, int pollingInterval, int connectionTimeout) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.backoff = backoff;
this.callback = callback;
this.maxLatency = maxLatency;
this.maxIdleTime = maxIdleTime;
this.pollingInterval = pollingInterval;
this.connectionTimeout = connectionTimeout;
if (maxIdleTime > Integer.MAX_VALUE / 2)
socketTimeout = Integer.MAX_VALUE;
@@ -149,21 +141,15 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
protected void bind() {
bindExecutor.execute(() -> {
State s = getState();
if (s != ACTIVE && s != INACTIVE) return;
if (getState() != INACTIVE) return;
bind(true);
bind(false);
});
}
private void bind(boolean ipv4) {
ServerSocket old = state.getServerSocket(ipv4);
ServerSocket ss = null;
for (InetSocketAddress addr : getLocalSocketAddresses(ipv4)) {
if (old != null && addr.equals(old.getLocalSocketAddress())) {
LOG.info("Server socket already bound");
return;
}
try {
ss = new ServerSocket();
ss.bind(addr);
@@ -174,7 +160,7 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
tryToClose(ss, LOG, WARNING);
}
}
if (ss == null || !ss.isBound()) {
if (ss == null) {
LOG.info("Could not bind server socket");
return;
}
@@ -183,7 +169,6 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
tryToClose(ss, LOG, WARNING);
return;
}
backoff.reset();
InetSocketAddress local =
(InetSocketAddress) ss.getLocalSocketAddress();
setLocalSocketAddress(local, ipv4);
@@ -216,7 +201,6 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
LOG.info("Connection from " +
scrubSocketAddress(s.getRemoteSocketAddress()));
}
backoff.reset();
callback.handleConnection(new TcpTransportConnection(this, s));
}
}
@@ -243,26 +227,22 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
@Override
public int getPollingInterval() {
return backoff.getPollingInterval();
return pollingInterval;
}
@Override
public void poll(Collection<Pair<TransportProperties, ConnectionHandler>>
properties) {
if (getState() != ACTIVE) return;
backoff.increment();
for (Pair<TransportProperties, ConnectionHandler> p : properties) {
connect(p.getFirst(), p.getSecond());
}
}
private void connect(TransportProperties p, ConnectionHandler h) {
wakefulIoExecutor.execute(() -> {
ioExecutor.execute(() -> {
DuplexTransportConnection d = createConnection(p);
if (d != null) {
backoff.reset();
h.handleConnection(d);
}
if (d != null) h.handleConnection(d);
});
}

View File

@@ -2,7 +2,6 @@ package org.briarproject.bramble.plugin.tcp;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
@@ -30,16 +29,11 @@ class WanTcpPlugin extends TcpPlugin {
private volatile MappingResult mappingResult;
WanTcpPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
Backoff backoff,
PortMapper portMapper,
PluginCallback callback,
int maxLatency,
int maxIdleTime,
int connectionTimeout) {
super(ioExecutor, wakefulIoExecutor, backoff, callback, maxLatency,
maxIdleTime, connectionTimeout);
WanTcpPlugin(Executor ioExecutor, PortMapper portMapper,
PluginCallback callback, int maxLatency, int maxIdleTime,
int pollingInterval, int connectionTimeout) {
super(ioExecutor, callback, maxLatency, maxIdleTime, pollingInterval,
connectionTimeout);
this.portMapper = portMapper;
}

View File

@@ -1,50 +1,38 @@
package org.briarproject.bramble.plugin.tcp;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.plugin.WanTcpConstants.ID;
@Immutable
@NotNullByDefault
public class WanTcpPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30_000; // 30 seconds
private static final int MAX_IDLE_TIME = 30_000; // 30 seconds
private static final int CONNECTION_TIMEOUT = 30_000; // 30 seconds
private static final int MIN_POLLING_INTERVAL = 60_000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 600_000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private static final int MAX_LATENCY = (int) SECONDS.toMillis(30);
private static final int MAX_IDLE_TIME = (int) SECONDS.toMillis(30);
private static final int POLLING_INTERVAL = (int) MINUTES.toMillis(1);
private static final int CONNECTION_TIMEOUT = (int) SECONDS.toMillis(30);
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final EventBus eventBus;
private final BackoffFactory backoffFactory;
private final ShutdownManager shutdownManager;
@Inject
public WanTcpPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
EventBus eventBus,
BackoffFactory backoffFactory,
public WanTcpPluginFactory(Executor ioExecutor, EventBus eventBus,
ShutdownManager shutdownManager) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.eventBus = eventBus;
this.backoffFactory = backoffFactory;
this.shutdownManager = shutdownManager;
}
@@ -60,12 +48,9 @@ public class WanTcpPluginFactory implements DuplexPluginFactory {
@Override
public DuplexPlugin createPlugin(PluginCallback callback) {
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
PortMapper portMapper = new PortMapperImpl(shutdownManager);
WanTcpPlugin plugin = new WanTcpPlugin(ioExecutor, wakefulIoExecutor,
backoff, portMapper, callback, MAX_LATENCY, MAX_IDLE_TIME,
CONNECTION_TIMEOUT);
WanTcpPlugin plugin = new WanTcpPlugin(ioExecutor,
new PortMapperImpl(shutdownManager), callback, MAX_LATENCY,
MAX_IDLE_TIME, POLLING_INTERVAL, CONNECTION_TIMEOUT);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -17,7 +17,6 @@ import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.ConnectionHandler;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.PluginException;
@@ -46,9 +45,11 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
@@ -109,29 +110,59 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private static final Logger LOG = getLogger(TorPlugin.class.getName());
/**
* Controller events we want to receive.
*/
private static final String[] EVENTS = {
"CIRC", "ORCONN", "HS_DESC", "NOTICE", "WARN", "ERR"
};
/**
* Command-line argument to set our process as Tor's owning controller
* so Tor exits when our process dies.
*/
private static final String OWNER = "__OwningControllerProcess";
/**
* How long to wait for the authentication cookie file to be created.
*/
private static final int COOKIE_TIMEOUT_MS = 3000;
/**
* How often to check whether the authentication cookie file has been
* created.
*/
private static final int COOKIE_POLLING_INTERVAL_MS = 200;
/**
* Regex for matching v2 hidden service names.
*/
private static final Pattern ONION_V2 = Pattern.compile("[a-z2-7]{16}");
/**
* Regex for matching v3 hidden service names.
*/
private static final Pattern ONION_V3 = Pattern.compile("[a-z2-7]{56}");
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor connectionStatusExecutor;
/**
* How many copies of our descriptor must be uploaded before we consider
* our hidden service to be reachable and switch to less frequent polling.
*/
private static final int MIN_DESCRIPTORS_UPLOADED = 5;
private final Executor ioExecutor, connectionStatusExecutor;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final SocketFactory torSocketFactory;
private final Clock clock;
private final BatteryManager batteryManager;
private final Backoff backoff;
private final TorRendezvousCrypto torRendezvousCrypto;
private final PluginCallback callback;
private final String architecture;
private final CircumventionProvider circumventionProvider;
private final ResourceProvider resourceProvider;
private final int maxLatency, maxIdleTime, socketTimeout;
private final int initialPollingInterval, stablePollingInterval;
private final File torDirectory, torFile, geoIpFile, obfs4File, configFile;
private final File doneFile, cookieFile;
private final AtomicBoolean used = new AtomicBoolean(false);
@@ -146,24 +177,16 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
protected abstract long getLastUpdateTime();
TorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
TorPlugin(Executor ioExecutor, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
int maxLatency,
int maxIdleTime,
File torDirectory) {
PluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, int initialPollingInterval,
int stablePollingInterval, File torDirectory) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.torSocketFactory = torSocketFactory;
@@ -171,7 +194,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
this.backoff = backoff;
this.torRendezvousCrypto = torRendezvousCrypto;
this.callback = callback;
this.architecture = architecture;
@@ -180,6 +202,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (maxIdleTime > Integer.MAX_VALUE / 2)
socketTimeout = Integer.MAX_VALUE;
else socketTimeout = maxIdleTime * 2;
this.initialPollingInterval = initialPollingInterval;
this.stablePollingInterval = stablePollingInterval;
this.torDirectory = torDirectory;
torFile = new File(torDirectory, "tor");
geoIpFile = new File(torDirectory, "geoip");
@@ -444,7 +468,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
callback.mergeSettings(s);
// Create a hidden service if necessary
ioExecutor.execute(() -> publishHiddenService(localPort));
backoff.reset();
// Accept incoming hidden service connections from Tor
acceptContactConnections(ss);
});
@@ -462,7 +485,7 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
// in the migration period since first publishing it
if (!isNullOrEmpty(privKey2)) {
long now = clock.currentTimeMillis();
long then = v3Created == null ? now : Long.parseLong(v3Created);
long then = v3Created == null ? now : Long.valueOf(v3Created);
if (now - then >= V3_MIGRATION_PERIOD_MS) retireV2HiddenService();
else publishV2HiddenService(port, privKey2);
}
@@ -524,15 +547,15 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
LOG.warning("Tor did not return a private key");
return;
}
// Publish the hidden service's onion hostname in transport properties
String onion3 = response.get(HS_ADDRESS);
if (LOG.isLoggable(INFO)) {
LOG.info("V3 hidden service " + scrubOnion(onion3));
}
TransportProperties p = new TransportProperties();
p.put(PROP_ONION_V3, onion3);
callback.mergeLocalProperties(p);
if (privKey == null) {
// Publish the hidden service's onion hostname in transport props
TransportProperties p = new TransportProperties();
p.put(PROP_ONION_V3, onion3);
callback.mergeLocalProperties(p);
// Save the hidden service's private key for next time
Settings s = new Settings();
s.put(HS_PRIVATE_KEY_V3, response.get(HS_PRIVKEY));
@@ -554,7 +577,6 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
return;
}
LOG.info("Connection received");
backoff.reset();
callback.handleConnection(new TorTransportConnection(this, s));
}
}
@@ -616,26 +638,28 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public int getPollingInterval() {
return backoff.getPollingInterval();
if (state.isDescriptorPublished()) {
LOG.info("Using stable polling interval");
return stablePollingInterval;
} else {
LOG.info("Using initial polling interval");
return initialPollingInterval;
}
}
@Override
public void poll(Collection<Pair<TransportProperties, ConnectionHandler>>
properties) {
if (getState() != ACTIVE) return;
backoff.increment();
for (Pair<TransportProperties, ConnectionHandler> p : properties) {
connect(p.getFirst(), p.getSecond());
}
}
private void connect(TransportProperties p, ConnectionHandler h) {
wakefulIoExecutor.execute(() -> {
ioExecutor.execute(() -> {
DuplexTransportConnection d = createConnection(p);
if (d != null) {
backoff.reset();
h.handleConnection(d);
}
if (d != null) h.handleConnection(d);
});
}
@@ -765,10 +789,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void circuitStatus(String status, String id, String path) {
if (status.equals("BUILT") &&
state.getAndSetCircuitBuilt()) {
if (status.equals("BUILT") && state.getAndSetCircuitBuilt()) {
LOG.info("First circuit built");
backoff.reset();
}
}
@@ -778,8 +800,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override
public void orConnStatus(String status, String orName) {
if (LOG.isLoggable(INFO))
LOG.info("OR connection " + status + " " + orName);
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
state.setOrConnectionStatus(orName, status);
if (status.equals("CLOSED") || status.equals("FAILED")) {
// Check whether we've lost connectivity
updateConnectionStatus(networkManager.getNetworkStatus(),
@@ -800,20 +822,18 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
state.setBootstrapped();
backoff.reset();
}
}
@Override
public void unrecognized(String type, String msg) {
if (type.equals("HS_DESC") && msg.startsWith("UPLOADED")) {
if (LOG.isLoggable(INFO)) {
String[] words = msg.split(" ");
if (words.length > 1 && ONION_V3.matcher(words[1]).matches()) {
LOG.info("V3 descriptor uploaded");
} else {
LOG.info("V2 descriptor uploaded");
}
String[] words = msg.split(" ");
if (words.length > 1 && ONION_V3.matcher(words[1]).matches()) {
LOG.info("V3 descriptor uploaded");
state.descriptorUploaded();
} else {
LOG.info("V2 descriptor uploaded");
}
}
}
@@ -969,6 +989,12 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Nullable
private ServerSocket serverSocket = null;
@GuardedBy("this")
private final Set<String> orConnections = new HashSet<>();
@GuardedBy("this")
private int descriptorsUploaded = 0;
synchronized void setStarted() {
started = true;
callback.pluginStateChanged(getState());
@@ -1002,7 +1028,10 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
synchronized void enableNetwork(boolean enable) {
networkInitialised = true;
networkEnabled = enable;
if (!enable) circuitBuilt = false;
if (!enable) {
circuitBuilt = false;
descriptorsUploaded = 0;
}
callback.pluginStateChanged(getState());
}
@@ -1012,6 +1041,34 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
callback.pluginStateChanged(getState());
}
synchronized void setOrConnectionStatus(String orName, String status) {
if (status.equals("CONNECTED")) {
if (!orConnections.add(orName)) {
LOG.warning("Duplicate OR connection");
}
} else {
orConnections.remove(orName);
if (orConnections.isEmpty()) descriptorsUploaded = 0;
}
if (LOG.isLoggable(INFO)) {
LOG.info(orConnections.size() + " OR connections");
}
callback.pluginStateChanged(getState());
}
// Doesn't affect getState()
synchronized void descriptorUploaded() {
if (networkEnabled && !orConnections.isEmpty()) {
descriptorsUploaded++;
} else {
LOG.warning("Descriptor was uploaded with no OR connection");
}
}
synchronized boolean isDescriptorPublished() {
return descriptorsUploaded >= MIN_DESCRIPTORS_UPLOADED;
}
// Doesn't affect getState()
synchronized boolean setServerSocket(ServerSocket ss) {
if (stopped || serverSocket != null) return false;
@@ -1031,7 +1088,8 @@ abstract class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
if (reasonsDisabled != 0) return DISABLED;
if (!networkInitialised) return ENABLING;
if (!networkEnabled) return INACTIVE;
return bootstrapped && circuitBuilt ? ACTIVE : ENABLING;
return bootstrapped && circuitBuilt && !orConnections.isEmpty()
? ACTIVE : ENABLING;
}
synchronized int getReasonsDisabled() {

View File

@@ -18,7 +18,6 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.properties.event.RemoteTransportPropertiesUpdatedEvent;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility;
import org.briarproject.bramble.api.sync.GroupId;
@@ -43,7 +42,6 @@ import static org.briarproject.bramble.api.properties.TransportPropertyConstants
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_LOCAL;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_TRANSPORT_ID;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MSG_KEY_VERSION;
import static org.briarproject.bramble.api.properties.TransportPropertyConstants.REFLECTED_PROPERTY_PREFIX;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
@Immutable
@@ -131,10 +129,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
// We've already received a newer update - delete this one
db.deleteMessage(txn, m.getId());
db.deleteMessageMetadata(txn, m.getId());
return false;
}
}
txn.attach(new RemoteTransportPropertiesUpdatedEvent(t));
} catch (FormatException e) {
throw new InvalidMessageException(e);
}
@@ -157,27 +153,15 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
if (props.isEmpty()) return;
try {
db.transaction(false, txn -> {
Contact contact = db.getContact(txn, c);
Group g = getContactGroup(contact);
Group g = getContactGroup(db.getContact(txn, c));
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(
txn, g.getId());
BdfDictionary discovered =
meta.getOptionalDictionary(GROUP_KEY_DISCOVERED);
BdfDictionary merged;
boolean changed;
if (discovered == null) {
merged = new BdfDictionary(props);
changed = true;
} else {
merged = new BdfDictionary(discovered);
merged.putAll(props);
changed = !merged.equals(discovered);
}
if (changed) {
meta.put(GROUP_KEY_DISCOVERED, merged);
clientHelper.mergeGroupMetadata(txn, g.getId(), meta);
updateLocalProperties(txn, contact, t);
}
if (discovered == null) discovered = new BdfDictionary();
discovered.putAll(props);
meta.put(GROUP_KEY_DISCOVERED, discovered);
clientHelper.mergeGroupMetadata(txn, g.getId(), meta);
});
} catch (FormatException e) {
throw new DbException(e);
@@ -242,24 +226,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
});
}
private void updateLocalProperties(Transaction txn, Contact c,
TransportId t) throws DbException {
try {
TransportProperties local;
LatestUpdate latest = findLatest(txn, localGroup.getId(), t, true);
if (latest == null) {
local = new TransportProperties();
} else {
BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId);
local = parseProperties(message);
}
storeLocalProperties(txn, c, t, local);
} catch (FormatException e) {
throw new DbException(e);
}
}
private TransportProperties getRemoteProperties(Transaction txn, Contact c,
TransportId t) throws DbException {
Group g = getContactGroup(c);
@@ -332,10 +298,18 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
storeMessage(txn, localGroup.getId(), t, merged, version,
true, false);
// Delete the previous update, if any
if (latest != null) db.removeMessage(txn, latest.messageId);
if (latest != null)
db.removeMessage(txn, latest.messageId);
// Store the merged properties in each contact's group
for (Contact c : db.getContacts(txn)) {
storeLocalProperties(txn, c, t, merged);
Group g = getContactGroup(c);
latest = findLatest(txn, g.getId(), t, true);
version = latest == null ? 1 : latest.version + 1;
storeMessage(txn, g.getId(), t, merged, version,
true, true);
// Delete the previous update, if any
if (latest != null)
db.removeMessage(txn, latest.messageId);
}
}
});
@@ -344,34 +318,6 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
}
}
private void storeLocalProperties(Transaction txn, Contact c,
TransportId t, TransportProperties p)
throws DbException, FormatException {
Group g = getContactGroup(c);
LatestUpdate latest = findLatest(txn, g.getId(), t, true);
long version = latest == null ? 1 : latest.version + 1;
// Reflect any remote properties we've discovered
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(txn,
g.getId());
BdfDictionary discovered =
meta.getOptionalDictionary(GROUP_KEY_DISCOVERED);
TransportProperties combined;
if (discovered == null) {
combined = p;
} else {
combined = new TransportProperties(p);
TransportProperties d = clientHelper
.parseAndValidateTransportProperties(discovered);
for (Entry<String, String> e : d.entrySet()) {
String key = REFLECTED_PROPERTY_PREFIX + e.getKey();
combined.put(key, e.getValue());
}
}
storeMessage(txn, g.getId(), t, combined, version, true, true);
// Delete the previous update, if any
if (latest != null) db.removeMessage(txn, latest.messageId);
}
private Group getContactGroup(Contact c) {
return contactGroupFactory.createContactGroup(CLIENT_ID,
MAJOR_VERSION, c);

View File

@@ -41,9 +41,7 @@ import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedE
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousPollEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import org.briarproject.bramble.api.system.Wakeful;
import org.briarproject.bramble.api.system.Scheduler;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
@@ -54,6 +52,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;
@@ -69,7 +68,6 @@ import static org.briarproject.bramble.api.contact.PendingContactState.ADDING_CO
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
import static org.briarproject.bramble.api.contact.PendingContactState.OFFLINE;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNonNull;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNull;
import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS;
import static org.briarproject.bramble.rendezvous.RendezvousConstants.RENDEZVOUS_TIMEOUT_MS;
@@ -82,7 +80,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
private static final Logger LOG =
getLogger(RendezvousPollerImpl.class.getName());
private final TaskScheduler scheduler;
private final ScheduledExecutorService scheduler;
private final DatabaseComponent db;
private final IdentityManager identityManager;
private final TransportCrypto transportCrypto;
@@ -104,12 +102,10 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
new HashMap<>();
@Nullable
private KeyPair handshakeKeyPair = null;
@Nullable
private Cancellable pollTask = null;
@Inject
RendezvousPollerImpl(@IoExecutor Executor ioExecutor,
TaskScheduler scheduler,
@Scheduler ScheduledExecutorService scheduler,
DatabaseComponent db,
IdentityManager identityManager,
TransportCrypto transportCrypto,
@@ -148,6 +144,8 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
} catch (DbException e) {
throw new ServiceException(e);
}
scheduler.scheduleAtFixedRate(this::poll, POLLING_INTERVAL_MS,
POLLING_INTERVAL_MS, MILLISECONDS);
}
@EventExecutor
@@ -188,12 +186,6 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
}
if (cs.numEndpoints == 0) broadcastState(p.getId(), OFFLINE);
else broadcastState(p.getId(), WAITING_FOR_CONNECTION);
if (cryptoStates.size() == 1) {
LOG.info("Starting poller");
requireNull(pollTask);
pollTask = scheduler.scheduleWithFixedDelay(this::poll, worker,
POLLING_INTERVAL_MS, POLLING_INTERVAL_MS, MILLISECONDS);
}
} catch (DbException | GeneralSecurityException e) {
logException(LOG, WARNING, e);
}
@@ -213,12 +205,12 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
return plugin.createRendezvousEndpoint(k, cs.alice, h);
}
// Worker
@Wakeful
@Scheduler
private void poll() {
LOG.info("Polling");
removeExpiredPendingContacts();
for (PluginState ps : pluginStates.values()) poll(ps);
worker.execute(() -> {
removeExpiredPendingContacts();
for (PluginState ps : pluginStates.values()) poll(ps);
});
}
// Worker
@@ -243,15 +235,9 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
RendezvousEndpoint endpoint = ps.endpoints.remove(p);
if (endpoint != null) tryToClose(endpoint, LOG, INFO);
}
if (cryptoStates.isEmpty()) {
LOG.info("Stopping poller");
requireNonNull(pollTask).cancel();
pollTask = null;
}
}
// Worker
@Wakeful
private void poll(PluginState ps) {
if (ps.endpoints.isEmpty()) return;
TransportId t = ps.plugin.getId();

View File

@@ -1,15 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.system.Clock;
import dagger.Module;
import dagger.Provides;
@Module
public class ClockModule {
@Provides
Clock provideClock() {
return new SystemClock();
}
}

View File

@@ -1,23 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.util.concurrent.Executor;
import dagger.Module;
import dagger.Provides;
/**
* Provides a default implementation of {@link WakefulIoExecutor} for systems
* without wake locks.
*/
@Module
public class DefaultWakefulIoExecutorModule {
@Provides
@WakefulIoExecutor
Executor provideWakefulIoExecutor(@IoExecutor Executor ioExecutor) {
return ioExecutor;
}
}

View File

@@ -1,7 +1,8 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.Scheduler;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
@@ -14,26 +15,34 @@ import dagger.Module;
import dagger.Provides;
@Module
public class DefaultTaskSchedulerModule {
public class SystemModule {
public static class EagerSingletons {
@Inject
TaskScheduler scheduler;
@Scheduler
ScheduledExecutorService scheduledExecutorService;
}
private final ScheduledExecutorService scheduledExecutorService;
private final ScheduledExecutorService scheduler;
public DefaultTaskSchedulerModule() {
public SystemModule() {
// Discard tasks that are submitted during shutdown
RejectedExecutionHandler policy =
new ScheduledThreadPoolExecutor.DiscardPolicy();
scheduledExecutorService = new ScheduledThreadPoolExecutor(1, policy);
scheduler = new ScheduledThreadPoolExecutor(1, policy);
}
@Provides
Clock provideClock() {
return new SystemClock();
}
@Provides
@Singleton
TaskScheduler provideTaskScheduler(LifecycleManager lifecycleManager) {
lifecycleManager.registerForShutdown(scheduledExecutorService);
return new TaskSchedulerImpl(scheduledExecutorService);
@Scheduler
ScheduledExecutorService provideScheduledExecutorService(
LifecycleManager lifecycleManager) {
lifecycleManager.registerForShutdown(scheduler);
return scheduler;
}
}

View File

@@ -1,43 +0,0 @@
package org.briarproject.bramble.system;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.TaskScheduler;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.concurrent.ThreadSafe;
/**
* A {@link TaskScheduler} that uses a {@link ScheduledExecutorService}.
*/
@ThreadSafe
@NotNullByDefault
class TaskSchedulerImpl implements TaskScheduler {
private final ScheduledExecutorService scheduledExecutorService;
TaskSchedulerImpl(ScheduledExecutorService scheduledExecutorService) {
this.scheduledExecutorService = scheduledExecutorService;
}
@Override
public Cancellable schedule(Runnable task, Executor executor, long delay,
TimeUnit unit) {
Runnable execute = () -> executor.execute(task);
ScheduledFuture<?> future =
scheduledExecutorService.schedule(execute, delay, unit);
return () -> future.cancel(false);
}
@Override
public Cancellable scheduleWithFixedDelay(Runnable task, Executor executor,
long delay, long interval, TimeUnit unit) {
Runnable execute = () -> executor.execute(task);
ScheduledFuture<?> future = scheduledExecutorService.
scheduleWithFixedDelay(execute, delay, interval, unit);
return () -> future.cancel(false);
}
}

View File

@@ -6,9 +6,10 @@ import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.Scheduler;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
@@ -21,15 +22,14 @@ class TransportKeyManagerFactoryImpl implements
private final DatabaseComponent db;
private final TransportCrypto transportCrypto;
private final Executor dbExecutor;
private final TaskScheduler scheduler;
private final ScheduledExecutorService scheduler;
private final Clock clock;
@Inject
TransportKeyManagerFactoryImpl(DatabaseComponent db,
TransportCrypto transportCrypto,
@DatabaseExecutor Executor dbExecutor,
TaskScheduler scheduler,
Clock clock) {
@Scheduler ScheduledExecutorService scheduler, Clock clock) {
this.db = db;
this.transportCrypto = transportCrypto;
this.dbExecutor = dbExecutor;

View File

@@ -6,14 +6,12 @@ import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.TransportCrypto;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.Wakeful;
import org.briarproject.bramble.api.system.Scheduler;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.StreamContext;
import org.briarproject.bramble.api.transport.TransportKeySet;
@@ -26,6 +24,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
@@ -54,7 +53,7 @@ class TransportKeyManagerImpl implements TransportKeyManager {
private final DatabaseComponent db;
private final TransportCrypto transportCrypto;
private final Executor dbExecutor;
private final TaskScheduler scheduler;
private final ScheduledExecutorService scheduler;
private final Clock clock;
private final TransportId transportId;
private final long timePeriodLength;
@@ -73,12 +72,9 @@ class TransportKeyManagerImpl implements TransportKeyManager {
pendingContactOutContexts = new HashMap<>();
TransportKeyManagerImpl(DatabaseComponent db,
TransportCrypto transportCrypto,
Executor dbExecutor,
TaskScheduler scheduler,
Clock clock,
TransportId transportId,
long maxLatency) {
TransportCrypto transportCrypto, Executor dbExecutor,
@Scheduler ScheduledExecutorService scheduler, Clock clock,
TransportId transportId, long maxLatency) {
this.db = db;
this.transportCrypto = transportCrypto;
this.dbExecutor = dbExecutor;
@@ -200,17 +196,17 @@ class TransportKeyManagerImpl implements TransportKeyManager {
private void scheduleKeyUpdate(long now) {
long delay = timePeriodLength - now % timePeriodLength;
scheduler.schedule(this::updateKeys, dbExecutor, delay, MILLISECONDS);
scheduler.schedule((Runnable) this::updateKeys, delay, MILLISECONDS);
}
@DatabaseExecutor
@Wakeful
private void updateKeys() {
try {
db.transaction(false, this::updateKeys);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
dbExecutor.execute(() -> {
try {
db.transaction(false, this::updateKeys);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
});
}
@Override
@@ -443,8 +439,6 @@ class TransportKeyManagerImpl implements TransportKeyManager {
}
}
@DatabaseExecutor
@Wakeful
private void updateKeys(Transaction txn) throws DbException {
long now = clock.currentTimeMillis();
lock.lock();

View File

@@ -1,18 +0,0 @@
package org.briarproject.bramble;
import org.briarproject.bramble.system.DefaultTaskSchedulerModule;
public interface BrambleCoreIntegrationTestEagerSingletons
extends BrambleCoreEagerSingletons {
void inject(DefaultTaskSchedulerModule.EagerSingletons init);
class Helper {
public static void injectEagerSingletons(
BrambleCoreIntegrationTestEagerSingletons c) {
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(c);
c.inject(new DefaultTaskSchedulerModule.EagerSingletons());
}
}
}

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.contact;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.BrambleCoreEagerSingletons;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactManager;
@@ -62,13 +62,11 @@ public class ContactExchangeIntegrationTest extends BrambleTestCase {
alice = DaggerContactExchangeIntegrationTestComponent.builder()
.testDatabaseConfigModule(
new TestDatabaseConfigModule(aliceDir)).build();
BrambleCoreIntegrationTestEagerSingletons.Helper
.injectEagerSingletons(alice);
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(alice);
bob = DaggerContactExchangeIntegrationTestComponent.builder()
.testDatabaseConfigModule(new TestDatabaseConfigModule(bobDir))
.build();
BrambleCoreIntegrationTestEagerSingletons.Helper
.injectEagerSingletons(bob);
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(bob);
// Set up the devices and get the identities
aliceIdentity = setUp(alice, "Alice");
bobIdentity = setUp(bob, "Bob");

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.contact;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.BrambleCoreEagerSingletons;
import org.briarproject.bramble.BrambleCoreModule;
import org.briarproject.bramble.api.connection.ConnectionManager;
import org.briarproject.bramble.api.contact.ContactExchangeManager;
@@ -23,7 +23,7 @@ import dagger.Component;
BrambleCoreModule.class
})
interface ContactExchangeIntegrationTestComponent
extends BrambleCoreIntegrationTestEagerSingletons {
extends BrambleCoreEagerSingletons {
ConnectionManager getConnectionManager();

View File

@@ -1,63 +0,0 @@
package org.briarproject.bramble.plugin;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class BackoffImplTest extends BrambleTestCase {
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());
}
}

View File

@@ -109,8 +109,8 @@ public class PluginManagerImplTest extends BrambleTestCase {
oneOf(duplexPlugin).stop();
}});
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, ioExecutor,
eventBus, pluginConfig, connectionManager, settingsManager,
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
pluginConfig, connectionManager, settingsManager,
transportPropertyManager);
// Two plugins should be started and stopped

View File

@@ -12,15 +12,12 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.plugin.event.ConnectionClosedEvent;
import org.briarproject.bramble.api.plugin.event.ConnectionOpenedEvent;
import org.briarproject.bramble.api.plugin.event.TransportActiveEvent;
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
import org.briarproject.bramble.api.plugin.simplex.SimplexPlugin;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.ImmediateExecutor;
import org.briarproject.bramble.test.RunAction;
@@ -32,6 +29,8 @@ import org.junit.Test;
import java.security.SecureRandom;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
@@ -45,7 +44,8 @@ import static org.briarproject.bramble.test.TestUtils.getTransportId;
public class PollerImplTest extends BrambleMockTestCase {
private final TaskScheduler scheduler = context.mock(TaskScheduler.class);
private final ScheduledExecutorService scheduler =
context.mock(ScheduledExecutorService.class);
private final ConnectionManager connectionManager =
context.mock(ConnectionManager.class);
private final ConnectionRegistry connectionRegistry =
@@ -55,11 +55,10 @@ public class PollerImplTest extends BrambleMockTestCase {
private final TransportPropertyManager transportPropertyManager =
context.mock(TransportPropertyManager.class);
private final Clock clock = context.mock(Clock.class);
private final Cancellable cancellable = context.mock(Cancellable.class);
private final ScheduledFuture future = context.mock(ScheduledFuture.class);
private final SecureRandom random;
private final Executor ioExecutor = new ImmediateExecutor();
private final Executor wakefulIoExecutor = new ImmediateExecutor();
private final TransportId transportId = getTransportId();
private final ContactId contactId = getContactId();
private final TransportProperties properties = new TransportProperties();
@@ -75,9 +74,9 @@ public class PollerImplTest extends BrambleMockTestCase {
@Before
public void setUp() {
poller = new PollerImpl(ioExecutor, wakefulIoExecutor, scheduler,
connectionManager, connectionRegistry, pluginManager,
transportPropertyManager, random, clock);
poller = new PollerImpl(ioExecutor, scheduler, connectionManager,
connectionRegistry, pluginManager, transportPropertyManager,
random, clock);
}
@Test
@@ -157,22 +156,20 @@ public class PollerImplTest extends BrambleMockTestCase {
}
@Test
public void testRescheduleOnOutgoingConnectionClosed() {
public void testDoesNotReconnectOnOutgoingConnectionClosed() {
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
context.checking(new Expectations() {{
allowing(plugin).getId();
will(returnValue(transportId));
}});
expectReschedule(plugin);
poller.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
false, false));
}
@Test
public void testRescheduleAndReconnectOnOutgoingConnectionFailed()
throws Exception {
public void testReconnectsOnOutgoingConnectionFailed() throws Exception {
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
DuplexTransportConnection duplexConnection =
context.mock(DuplexTransportConnection.class);
@@ -181,7 +178,6 @@ public class PollerImplTest extends BrambleMockTestCase {
allowing(plugin).getId();
will(returnValue(transportId));
}});
expectReschedule(plugin);
expectReconnect(plugin, duplexConnection);
poller.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
@@ -189,151 +185,31 @@ public class PollerImplTest extends BrambleMockTestCase {
}
@Test
public void testRescheduleOnIncomingConnectionClosed() {
public void testDoesNotReconnectOnIncomingConnectionClosed() {
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
context.checking(new Expectations() {{
allowing(plugin).getId();
will(returnValue(transportId));
}});
expectReschedule(plugin);
poller.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
true, false));
}
@Test
public void testRescheduleOnIncomingConnectionFailed() {
public void testDoesNotReconnectOnIncomingConnectionFailed() {
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
context.checking(new Expectations() {{
allowing(plugin).getId();
will(returnValue(transportId));
}});
expectReschedule(plugin);
poller.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
true, false));
}
@Test
public void testRescheduleOnConnectionOpened() {
Plugin plugin = context.mock(Plugin.class);
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(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(cancellable));
}});
poller.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
false));
}
@Test
public void testRescheduleDoesNotReplaceEarlierTask() {
Plugin plugin = context.mock(Plugin.class);
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(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(cancellable));
// 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.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
false));
poller.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
false));
}
@Test
public void testRescheduleReplacesLaterTask() {
Plugin plugin = context.mock(Plugin.class);
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(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(cancellable));
// Second event
// Get the plugin
oneOf(pluginManager).getPlugin(transportId);
will(returnValue(plugin));
// The plugin supports polling
oneOf(plugin).shouldPoll();
will(returnValue(true));
// Replace the previously scheduled task, due later
oneOf(plugin).getPollingInterval();
will(returnValue(pollingInterval - 2));
oneOf(clock).currentTimeMillis();
will(returnValue(now + 1));
oneOf(cancellable).cancel();
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with((long) pollingInterval - 2),
with(MILLISECONDS));
}});
poller.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
false));
poller.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
false));
}
@Test
public void testPollsOnTransportActivated() throws Exception {
DuplexPlugin plugin = context.mock(DuplexPlugin.class);
@@ -350,9 +226,9 @@ public class PollerImplTest extends BrambleMockTestCase {
// Schedule a polling task immediately
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with(0L), with(MILLISECONDS));
will(returnValue(cancellable));
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
with(MILLISECONDS));
will(returnValue(future));
will(new RunAction());
// Running the polling task schedules the next polling task
oneOf(plugin).getPollingInterval();
@@ -362,9 +238,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with((long) (pollingInterval * 0.5)),
with(MILLISECONDS));
will(returnValue(cancellable));
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
will(returnValue(future));
// Get the transport properties and connected contacts
oneOf(transportPropertyManager).getRemoteProperties(transportId);
will(returnValue(singletonMap(contactId, properties)));
@@ -394,9 +269,9 @@ public class PollerImplTest extends BrambleMockTestCase {
// Schedule a polling task immediately
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with(0L), with(MILLISECONDS));
will(returnValue(cancellable));
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
with(MILLISECONDS));
will(returnValue(future));
will(new RunAction());
// Running the polling task schedules the next polling task
oneOf(plugin).getPollingInterval();
@@ -406,9 +281,8 @@ public class PollerImplTest extends BrambleMockTestCase {
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with((long) (pollingInterval * 0.5)),
with(MILLISECONDS));
will(returnValue(cancellable));
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
will(returnValue(future));
// Get the transport properties and connected contacts
oneOf(transportPropertyManager).getRemoteProperties(transportId);
will(returnValue(singletonMap(contactId, properties)));
@@ -436,37 +310,17 @@ public class PollerImplTest extends BrambleMockTestCase {
// Schedule a polling task immediately
oneOf(clock).currentTimeMillis();
will(returnValue(now));
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(ioExecutor), with(0L), with(MILLISECONDS));
will(returnValue(cancellable));
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
with(MILLISECONDS));
will(returnValue(future));
// The plugin is deactivated before the task runs - cancel the task
oneOf(cancellable).cancel();
oneOf(future).cancel(false);
}});
poller.eventOccurred(new TransportActiveEvent(transportId));
poller.eventOccurred(new TransportInactiveEvent(transportId));
}
private void expectReschedule(Plugin plugin) {
context.checking(new Expectations() {{
// 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(ioExecutor), with((long) pollingInterval),
with(MILLISECONDS));
will(returnValue(cancellable));
}});
}
private void expectReconnect(DuplexPlugin plugin,
DuplexTransportConnection duplexConnection) throws Exception {
context.checking(new Expectations() {{

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.plugin.tcp;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.Plugin.State;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportConnectionReader;
@@ -22,13 +21,11 @@ import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.emptyList;
import static java.util.Collections.list;
import static java.util.concurrent.Executors.newCachedThreadPool;
import static java.util.concurrent.TimeUnit.SECONDS;
@@ -44,7 +41,6 @@ import static org.junit.Assume.assumeTrue;
public class LanTcpPluginTest extends BrambleTestCase {
private final Backoff backoff = new TestBackoff();
private final ExecutorService ioExecutor = newCachedThreadPool();
private Callback callback = null;
@@ -53,8 +49,7 @@ public class LanTcpPluginTest extends BrambleTestCase {
@Before
public void setUp() {
callback = new Callback();
plugin = new LanTcpPlugin(ioExecutor, ioExecutor, backoff, callback,
0, 0, 1000) {
plugin = new LanTcpPlugin(ioExecutor, callback, 0, 0, 0, 1000) {
@Override
protected boolean canConnectToOwnAddress() {
return true;
@@ -323,11 +318,6 @@ public class LanTcpPluginTest extends BrambleTestCase {
return local;
}
@Override
public Collection<TransportProperties> getRemoteProperties() {
return emptyList();
}
@Override
public void mergeSettings(Settings s) {
}
@@ -355,20 +345,4 @@ public class LanTcpPluginTest extends BrambleTestCase {
public void handleWriter(TransportConnectionWriter w) {
}
}
private static class TestBackoff implements Backoff {
@Override
public int getPollingInterval() {
return 60 * 1000;
}
@Override
public void increment() {
}
@Override
public void reset() {
}
}
}

View File

@@ -8,15 +8,11 @@ import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfEntry;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.MetadataParser;
import org.briarproject.bramble.api.db.CommitAction;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.EventAction;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.properties.event.RemoteTransportPropertiesUpdatedEvent;
import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
@@ -49,7 +45,6 @@ import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
@@ -64,28 +59,23 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
private final Clock clock = context.mock(Clock.class);
private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
private final BdfDictionary fooPropertiesDict, barPropertiesDict;
private final BdfDictionary discoveredPropertiesDict, mergedPropertiesDict;
private final BdfDictionary fooPropertiesDict = BdfDictionary.of(
new BdfEntry("fooKey1", "fooValue1"),
new BdfEntry("fooKey2", "fooValue2")
);
private final BdfDictionary barPropertiesDict = BdfDictionary.of(
new BdfEntry("barKey1", "barValue1"),
new BdfEntry("barKey2", "barValue2")
);
private final TransportProperties fooProperties, barProperties;
private final TransportProperties discoveredProperties;
public TransportPropertyManagerImplTest() {
public TransportPropertyManagerImplTest() throws Exception {
fooProperties = new TransportProperties();
fooProperties.put("fooKey1", "fooValue1");
fooProperties.put("fooKey2", "fooValue2");
fooPropertiesDict = new BdfDictionary(fooProperties);
for (String key : fooPropertiesDict.keySet())
fooProperties.put(key, fooPropertiesDict.getString(key));
barProperties = new TransportProperties();
barProperties.put("barKey1", "barValue1");
barProperties.put("barKey2", "barValue2");
barPropertiesDict = new BdfDictionary(barProperties);
discoveredProperties = new TransportProperties();
discoveredProperties.put("fooKey3", "fooValue3");
discoveredPropertiesDict = new BdfDictionary(discoveredProperties);
mergedPropertiesDict = new BdfDictionary(fooProperties);
mergedPropertiesDict.put("u:fooKey3", "fooValue3");
for (String key : barPropertiesDict.keySet())
barProperties.put(key, barPropertiesDict.getString(key));
}
private TransportPropertyManagerImpl createInstance() {
@@ -231,7 +221,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
TransportPropertyManagerImpl t = createInstance();
assertFalse(t.incomingMessage(txn, message, meta));
assertTrue(hasEvent(txn, RemoteTransportPropertiesUpdatedEvent.class));
}
@Test
@@ -270,7 +259,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
TransportPropertyManagerImpl t = createInstance();
assertFalse(t.incomingMessage(txn, message, meta));
assertTrue(hasEvent(txn, RemoteTransportPropertiesUpdatedEvent.class));
}
@Test
@@ -304,12 +292,10 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
// The update being delivered (version 3) should be deleted
oneOf(db).deleteMessage(txn, message.getId());
oneOf(db).deleteMessageMetadata(txn, message.getId());
// No event should be broadcast
}});
TransportPropertyManagerImpl t = createInstance();
assertFalse(t.incomingMessage(txn, message, meta));
assertFalse(hasEvent(txn, RemoteTransportPropertiesUpdatedEvent.class));
}
@Test
@@ -602,9 +588,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(emptyMap()));
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(new BdfDictionary()));
expectStoreMessage(txn, contactGroup.getId(), "foo",
fooPropertiesDict, 1, true, true);
}});
@@ -613,49 +596,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
t.mergeLocalProperties(new TransportId("foo"), properties);
}
@Test
public void testMergingNewPropertiesCreatesUpdateWithReflectedProperties()
throws Exception {
Transaction txn = new Transaction(null, false);
Contact contact = getContact();
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
BdfDictionary contactGroupMeta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_DISCOVERED, discoveredPropertiesDict)
);
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
// There are no existing properties to merge with
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(emptyMap()));
// Store the new properties in the local group, version 1
expectStoreMessage(txn, localGroup.getId(), "foo",
fooPropertiesDict, 1, true, false);
// Store the new properties in each contact's group, version 1
oneOf(db).getContacts(txn);
will(returnValue(singletonList(contact)));
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
MAJOR_VERSION, contact);
will(returnValue(contactGroup));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(emptyMap()));
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(contactGroupMeta));
// Reflect discovered properties
oneOf(clientHelper).parseAndValidateTransportProperties(
discoveredPropertiesDict);
will(returnValue(discoveredProperties));
expectStoreMessage(txn, contactGroup.getId(), "foo",
mergedPropertiesDict, 1, true, true);
}});
TransportPropertyManagerImpl t = createInstance();
t.mergeLocalProperties(new TransportId("foo"), fooProperties);
}
@Test
public void testMergingUpdatedPropertiesCreatesUpdate() throws Exception {
Transaction txn = new Transaction(null, false);
@@ -712,9 +652,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(contactGroupMessageMetadata));
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(new BdfDictionary()));
expectStoreMessage(txn, contactGroup.getId(), "foo",
fooPropertiesDict, 2, true, true);
// Delete the previous update
@@ -725,75 +662,6 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
t.mergeLocalProperties(new TransportId("foo"), properties);
}
@Test
public void testMergingUpdatedPropertiesCreatesUpdateWithReflectedProperties()
throws Exception {
Transaction txn = new Transaction(null, false);
Contact contact = getContact();
Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION);
BdfDictionary contactGroupMeta = BdfDictionary.of(
new BdfEntry(GROUP_KEY_DISCOVERED, discoveredPropertiesDict)
);
BdfDictionary oldMetadata = BdfDictionary.of(
new BdfEntry(MSG_KEY_TRANSPORT_ID, "foo"),
new BdfEntry(MSG_KEY_VERSION, 1),
new BdfEntry(MSG_KEY_LOCAL, true)
);
MessageId localGroupUpdateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> localGroupMessageMetadata =
singletonMap(localGroupUpdateId, oldMetadata);
MessageId contactGroupUpdateId = new MessageId(getRandomId());
Map<MessageId, BdfDictionary> contactGroupMessageMetadata =
singletonMap(contactGroupUpdateId, oldMetadata);
TransportProperties oldProperties = new TransportProperties();
oldProperties.put("fooKey1", "oldFooValue1");
BdfDictionary oldPropertiesDict = BdfDictionary.of(
new BdfEntry("fooKey1", "oldFooValue1")
);
BdfList oldUpdate = BdfList.of("foo", 1, oldPropertiesDict);
context.checking(new DbExpectations() {{
oneOf(db).transaction(with(false), withDbRunnable(txn));
// Merge the new properties with the existing properties
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict);
will(returnValue(oldProperties));
// Store the merged properties in the local group, version 2
expectStoreMessage(txn, localGroup.getId(), "foo",
fooPropertiesDict, 2, true, false);
// Delete the previous update
oneOf(db).removeMessage(txn, localGroupUpdateId);
// Store the merged properties in each contact's group, version 2
oneOf(db).getContacts(txn);
will(returnValue(singletonList(contact)));
oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
MAJOR_VERSION, contact);
will(returnValue(contactGroup));
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(contactGroupMessageMetadata));
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(contactGroupMeta));
// Reflect discovered properties
oneOf(clientHelper).parseAndValidateTransportProperties(
discoveredPropertiesDict);
will(returnValue(discoveredProperties));
expectStoreMessage(txn, contactGroup.getId(), "foo",
mergedPropertiesDict, 2, true, true);
// Delete the previous update
oneOf(db).removeMessage(txn, contactGroupUpdateId);
}});
TransportPropertyManagerImpl t = createInstance();
t.mergeLocalProperties(new TransportId("foo"), fooProperties);
}
private void expectGetLocalProperties(Transaction txn) throws Exception {
Map<MessageId, BdfDictionary> messageMetadata = new LinkedHashMap<>();
// The latest update for transport "foo" should be returned
@@ -851,15 +719,4 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
false);
}});
}
private boolean hasEvent(Transaction txn,
Class<? extends Event> eventClass) {
for (CommitAction action : txn.getActions()) {
if (action instanceof EventAction) {
Event event = ((EventAction) action).getEvent();
if (eventClass.isInstance(event)) return true;
}
}
return false;
}
}

View File

@@ -26,8 +26,6 @@ import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedE
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousPollEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.system.TaskScheduler.Cancellable;
import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.CaptureArgumentAction;
import org.briarproject.bramble.test.DbExpectations;
@@ -39,6 +37,7 @@ import org.junit.Test;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import static java.util.Collections.emptyList;
@@ -61,7 +60,8 @@ import static org.briarproject.bramble.test.TestUtils.getTransportProperties;
public class RendezvousPollerImplTest extends BrambleMockTestCase {
private final TaskScheduler scheduler = context.mock(TaskScheduler.class);
private final ScheduledExecutorService scheduler =
context.mock(ScheduledExecutorService.class);
private final DatabaseComponent db = context.mock(DatabaseComponent.class);
private final IdentityManager identityManager =
context.mock(IdentityManager.class);
@@ -80,7 +80,6 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
context.mock(KeyMaterialSource.class);
private final RendezvousEndpoint rendezvousEndpoint =
context.mock(RendezvousEndpoint.class);
private final Cancellable cancellable = context.mock(Cancellable.class);
private final Executor ioExecutor = new ImmediateExecutor();
private final PendingContact pendingContact = getPendingContact();
@@ -109,7 +108,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
long beforeExpiry = pendingContact.getTimestamp()
+ RENDEZVOUS_TIMEOUT_MS - 1000;
long afterExpiry = beforeExpiry + POLLING_INTERVAL_MS;
AtomicReference<Runnable> capturePollTask;
AtomicReference<Runnable> capturePollTask = new AtomicReference<>();
// Start the service
context.checking(new DbExpectations() {{
@@ -123,17 +122,21 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == OFFLINE)));
// Capture the poll task
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
with(MILLISECONDS));
will(new CaptureArgumentAction<>(capturePollTask, Runnable.class,
0));
}});
expectDeriveRendezvousKey();
capturePollTask = expectSchedulePolling();
rendezvousPoller.startService();
context.assertIsSatisfied();
// Run the poll task - pending contact expires, polling is cancelled
// Run the poll task - pending contact expires
expectPendingContactExpires(afterExpiry);
expectCancelPolling();
capturePollTask.get().run();
}
@@ -155,6 +158,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == FAILED)));
// Schedule the poll task
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
with(MILLISECONDS));
}});
rendezvousPoller.startService();
@@ -177,8 +184,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
rendezvousPoller.eventOccurred(new TransportActiveEvent(transportId));
context.assertIsSatisfied();
// Add the pending contact - endpoint should be created and polled,
// polling should be scheduled
// Add the pending contact - endpoint should be created and polled
expectAddPendingContact(beforeExpiry, WAITING_FOR_CONNECTION);
expectDeriveRendezvousKey();
expectCreateEndpoint();
@@ -195,16 +201,12 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
any(ConnectionHandler.class)))));
}});
expectSchedulePolling();
rendezvousPoller.eventOccurred(
new PendingContactAddedEvent(pendingContact));
context.assertIsSatisfied();
// Remove the pending contact - endpoint should be closed,
// polling should be cancelled
// Remove the pending contact - endpoint should be closed
expectCloseEndpoint();
expectCancelPolling();
rendezvousPoller.eventOccurred(
new PendingContactRemovedEvent(pendingContact.getId()));
@@ -220,10 +222,10 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
long beforeExpiry = pendingContact.getTimestamp()
+ RENDEZVOUS_TIMEOUT_MS - 1000;
long afterExpiry = beforeExpiry + POLLING_INTERVAL_MS;
AtomicReference<Runnable> capturePollTask;
// Start the service
expectStartupWithNoPendingContacts();
// Start the service, capturing the poll task
AtomicReference<Runnable> capturePollTask =
expectStartupWithNoPendingContacts();
rendezvousPoller.startService();
context.assertIsSatisfied();
@@ -234,8 +236,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
rendezvousPoller.eventOccurred(new TransportActiveEvent(transportId));
context.assertIsSatisfied();
// Add the pending contact - endpoint should be created and polled,
// polling should be scheduled
// Add the pending contact - endpoint should be created and polled
expectAddPendingContact(beforeExpiry, WAITING_FOR_CONNECTION);
expectDeriveRendezvousKey();
expectCreateEndpoint();
@@ -252,17 +253,13 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
any(ConnectionHandler.class)))));
}});
capturePollTask = expectSchedulePolling();
rendezvousPoller.eventOccurred(
new PendingContactAddedEvent(pendingContact));
context.assertIsSatisfied();
// Run the poll task - pending contact expires, endpoint is closed,
// polling is cancelled
// Run the poll task - pending contact expires, endpoint is closed
expectPendingContactExpires(afterExpiry);
expectCloseEndpoint();
expectCancelPolling();
capturePollTask.get().run();
context.assertIsSatisfied();
@@ -290,7 +287,6 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
// Add the pending contact - no endpoints should be created yet
expectAddPendingContact(beforeExpiry, OFFLINE);
expectDeriveRendezvousKey();
expectSchedulePolling();
rendezvousPoller.eventOccurred(
new PendingContactAddedEvent(pendingContact));
@@ -312,8 +308,6 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
context.assertIsSatisfied();
// Remove the pending contact - endpoint is already closed
expectCancelPolling();
rendezvousPoller.eventOccurred(
new PendingContactRemovedEvent(pendingContact.getId()));
}
@@ -355,9 +349,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
rendezvousPoller.startService();
context.assertIsSatisfied();
// Run the poll task - pending contact expires, polling is cancelled
// Run the poll task - pending contact expires
expectPendingContactExpires(afterExpiry);
expectCancelPolling();
capturePollTask.get().run();
context.assertIsSatisfied();
@@ -393,9 +386,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
new RendezvousConnectionOpenedEvent(pendingContact.getId()));
context.assertIsSatisfied();
// Run the poll task - pending contact expires, polling is cancelled
// Run the poll task - pending contact expires
expectPendingContactExpires(afterExpiry);
expectCancelPolling();
capturePollTask.get().run();
context.assertIsSatisfied();
@@ -426,9 +418,8 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
new RendezvousConnectionOpenedEvent(pendingContact.getId()));
context.assertIsSatisfied();
// Run the poll task - pending contact expires, polling is cancelled
// Run the poll task - pending contact expires
expectPendingContactExpires(afterExpiry);
expectCancelPolling();
capturePollTask.get().run();
context.assertIsSatisfied();
@@ -457,8 +448,6 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
context.assertIsSatisfied();
// Pending contact is removed - no event should be broadcast
expectCancelPolling();
rendezvousPoller.eventOccurred(
new PendingContactRemovedEvent(pendingContact.getId()));
context.assertIsSatisfied();
@@ -468,35 +457,25 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
pendingContact.getId(), false));
}
private AtomicReference<Runnable> expectSchedulePolling() {
AtomicReference<Runnable> capturePollTask = new AtomicReference<>();
context.checking(new Expectations() {{
oneOf(scheduler).scheduleWithFixedDelay(with(any(Runnable.class)),
with(any(Executor.class)), with(POLLING_INTERVAL_MS),
with(POLLING_INTERVAL_MS), with(MILLISECONDS));
will(doAll(new CaptureArgumentAction<>(capturePollTask,
Runnable.class, 0), returnValue(cancellable)));
}});
return capturePollTask;
}
private void expectCancelPolling() {
context.checking(new Expectations() {{
oneOf(cancellable).cancel();
}});
}
private void expectStartupWithNoPendingContacts() throws Exception {
private AtomicReference<Runnable> expectStartupWithNoPendingContacts()
throws Exception {
Transaction txn = new Transaction(null, true);
AtomicReference<Runnable> capturePollTask = new AtomicReference<>();
context.checking(new DbExpectations() {{
// Load the pending contacts
oneOf(db).transaction(with(true), withDbRunnable(txn));
oneOf(db).getPendingContacts(txn);
will(returnValue(emptyList()));
// Capture the poll task
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
with(MILLISECONDS));
will(new CaptureArgumentAction<>(capturePollTask, Runnable.class,
0));
}});
return capturePollTask;
}
private void expectAddPendingContact(long now,
@@ -552,6 +531,7 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
private AtomicReference<Runnable> expectStartupWithPendingContact(long now)
throws Exception {
Transaction txn = new Transaction(null, true);
AtomicReference<Runnable> capturePollTask = new AtomicReference<>();
context.checking(new DbExpectations() {{
// Load the pending contacts
@@ -564,10 +544,17 @@ public class RendezvousPollerImplTest extends BrambleMockTestCase {
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == OFFLINE)));
// Capture the poll task
oneOf(scheduler).scheduleAtFixedRate(with(any(Runnable.class)),
with(POLLING_INTERVAL_MS), with(POLLING_INTERVAL_MS),
with(MILLISECONDS));
will(new CaptureArgumentAction<>(capturePollTask, Runnable.class,
0));
}});
expectDeriveRendezvousKey();
return expectSchedulePolling();
return capturePollTask;
}
private void expectPendingContactExpires(long now) {

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.sync;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.BrambleCoreEagerSingletons;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.TransportCrypto;
@@ -73,8 +73,7 @@ public class SyncIntegrationTest extends BrambleTestCase {
SyncIntegrationTestComponent component =
DaggerSyncIntegrationTestComponent.builder().build();
BrambleCoreIntegrationTestEagerSingletons.Helper
.injectEagerSingletons(component);
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(component);
component.inject(this);
contactId = getContactId();

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.sync;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.BrambleCoreEagerSingletons;
import org.briarproject.bramble.BrambleCoreModule;
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
@@ -13,8 +13,7 @@ import dagger.Component;
BrambleCoreIntegrationTestModule.class,
BrambleCoreModule.class
})
interface SyncIntegrationTestComponent extends
BrambleCoreIntegrationTestEagerSingletons {
interface SyncIntegrationTestComponent extends BrambleCoreEagerSingletons {
void inject(SyncIntegrationTest testCase);
}

View File

@@ -3,8 +3,6 @@ package org.briarproject.bramble.test;
import org.briarproject.bramble.api.FeatureFlags;
import org.briarproject.bramble.battery.DefaultBatteryManagerModule;
import org.briarproject.bramble.event.DefaultEventExecutorModule;
import org.briarproject.bramble.system.DefaultTaskSchedulerModule;
import org.briarproject.bramble.system.DefaultWakefulIoExecutorModule;
import dagger.Module;
import dagger.Provides;
@@ -12,8 +10,6 @@ import dagger.Provides;
@Module(includes = {
DefaultBatteryManagerModule.class,
DefaultEventExecutorModule.class,
DefaultTaskSchedulerModule.class,
DefaultWakefulIoExecutorModule.class,
TestDatabaseConfigModule.class,
TestPluginConfigModule.class,
TestSecureRandomModule.class

View File

@@ -8,7 +8,6 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.TaskScheduler;
import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.OutgoingKeys;
@@ -30,6 +29,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@@ -55,7 +55,8 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
private final TransportCrypto transportCrypto =
context.mock(TransportCrypto.class);
private final Executor dbExecutor = context.mock(Executor.class);
private final TaskScheduler scheduler = context.mock(TaskScheduler.class);
private final ScheduledExecutorService scheduler =
context.mock(ScheduledExecutorService.class);
private final Clock clock = context.mock(Clock.class);
private final TransportId transportId = getTransportId();
@@ -117,8 +118,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
new TransportKeySet(keySetId, contactId, null, updated)));
// Schedule a key update at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(dbExecutor), with(timePeriodLength - 1),
with(MILLISECONDS));
with(timePeriodLength - 1), with(MILLISECONDS));
}});
transportKeyManager.start(txn);
@@ -421,8 +421,9 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
}
// Schedule a key update at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(dbExecutor), with(timePeriodLength),
with(MILLISECONDS));
with(timePeriodLength), with(MILLISECONDS));
will(new RunAction());
oneOf(dbExecutor).execute(with(any(Runnable.class)));
will(new RunAction());
// Start a transaction for updating keys
oneOf(db).transaction(with(false), withDbRunnable(txn1));
@@ -445,8 +446,7 @@ public class TransportKeyManagerImplTest extends BrambleMockTestCase {
new TransportKeySet(keySetId, contactId, null, updated)));
// Schedule a key update at the start of the next time period
oneOf(scheduler).schedule(with(any(Runnable.class)),
with(dbExecutor), with(timePeriodLength),
with(MILLISECONDS));
with(timePeriodLength), with(MILLISECONDS));
}});
transportKeyManager.start(txn);

View File

@@ -1,5 +1,9 @@
package org.briarproject.bramble.plugin;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.BluetoothConstants;
import org.briarproject.bramble.api.plugin.LanTcpConstants;
@@ -7,14 +11,17 @@ import org.briarproject.bramble.api.plugin.PluginConfig;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory;
import org.briarproject.bramble.plugin.bluetooth.JavaBluetoothPluginFactory;
import org.briarproject.bramble.plugin.modem.ModemPluginFactory;
import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory;
import org.briarproject.bramble.plugin.tcp.WanTcpPluginFactory;
import java.security.SecureRandom;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import dagger.Module;
import dagger.Provides;
@@ -28,15 +35,25 @@ import static java.util.Collections.singletonMap;
public class DesktopPluginModule extends PluginModule {
@Provides
PluginConfig getPluginConfig(JavaBluetoothPluginFactory bluetooth,
ModemPluginFactory modem, LanTcpPluginFactory lan,
WanTcpPluginFactory wan) {
PluginConfig getPluginConfig(@IoExecutor Executor ioExecutor,
SecureRandom random, ReliabilityLayerFactory reliabilityFactory,
ShutdownManager shutdownManager, EventBus eventBus,
TimeoutMonitor timeoutMonitor) {
DuplexPluginFactory bluetooth = new JavaBluetoothPluginFactory(
ioExecutor, random, eventBus, timeoutMonitor);
DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor,
reliabilityFactory);
DuplexPluginFactory lan = new LanTcpPluginFactory(ioExecutor, eventBus);
DuplexPluginFactory wan = new WanTcpPluginFactory(ioExecutor, eventBus,
shutdownManager);
Collection<DuplexPluginFactory> duplex =
asList(bluetooth, modem, lan, wan);
@NotNullByDefault
PluginConfig pluginConfig = new PluginConfig() {
@Override
public Collection<DuplexPluginFactory> getDuplexFactories() {
return asList(bluetooth, modem, lan, wan);
return duplex;
}
@Override

View File

@@ -1,34 +0,0 @@
package org.briarproject.bramble.plugin.bluetooth;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import java.io.IOException;
import javax.annotation.concurrent.Immutable;
import javax.microedition.io.StreamConnection;
@Immutable
@NotNullByDefault
class JavaBluetoothConnectionFactory
implements BluetoothConnectionFactory<StreamConnection> {
private final BluetoothConnectionLimiter connectionLimiter;
private final TimeoutMonitor timeoutMonitor;
JavaBluetoothConnectionFactory(
BluetoothConnectionLimiter connectionLimiter,
TimeoutMonitor timeoutMonitor) {
this.connectionLimiter = connectionLimiter;
this.timeoutMonitor = timeoutMonitor;
}
@Override
public DuplexTransportConnection wrapSocket(DuplexPlugin plugin,
StreamConnection socket) throws IOException {
return new JavaBluetoothTransportConnection(plugin, connectionLimiter,
timeoutMonitor, socket);
}
}

View File

@@ -1,8 +1,8 @@
package org.briarproject.bramble.plugin.bluetooth;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
@@ -25,8 +25,7 @@ import static org.briarproject.bramble.util.StringUtils.isValidMac;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
class JavaBluetoothPlugin
extends BluetoothPlugin<StreamConnection, StreamConnectionNotifier> {
class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
private static final Logger LOG =
getLogger(JavaBluetoothPlugin.class.getName());
@@ -35,17 +34,11 @@ class JavaBluetoothPlugin
private volatile LocalDevice localDevice = null;
JavaBluetoothPlugin(BluetoothConnectionLimiter connectionManager,
BluetoothConnectionFactory<StreamConnection> connectionFactory,
Executor ioExecutor,
Executor wakefulIoExecutor,
SecureRandom secureRandom,
Backoff backoff,
PluginCallback callback,
int maxLatency,
int maxIdleTime) {
super(connectionManager, connectionFactory, ioExecutor,
wakefulIoExecutor, secureRandom, backoff, callback,
maxLatency, maxIdleTime);
TimeoutMonitor timeoutMonitor, Executor ioExecutor,
SecureRandom secureRandom, PluginCallback callback, int maxLatency,
int maxIdleTime, int pollingInterval) {
super(connectionManager, timeoutMonitor, ioExecutor, secureRandom,
callback, maxLatency, maxIdleTime, pollingInterval);
}
@Override
@@ -62,6 +55,22 @@ class JavaBluetoothPlugin
return localDevice != null && LocalDevice.isPowerOn();
}
@Override
void enableAdapter() {
// Nothing we can do on this platform
LOG.info("Could not enable Bluetooth");
}
@Override
void disableAdapterIfEnabledByUs() {
// We didn't enable it so we don't need to disable it
}
@Override
void setEnabledByUs() {
// Irrelevant on this platform
}
@Nullable
@Override
String getBluetoothAddress() {
@@ -86,7 +95,7 @@ class JavaBluetoothPlugin
@Override
DuplexTransportConnection acceptConnection(StreamConnectionNotifier ss)
throws IOException {
return connectionFactory.wrapSocket(this, ss.acceptAndOpen());
return wrapSocket(ss.acceptAndOpen());
}
@Override
@@ -98,8 +107,7 @@ class JavaBluetoothPlugin
DuplexTransportConnection connectTo(String address, String uuid)
throws IOException {
String url = makeUrl(address, uuid);
StreamConnection s = (StreamConnection) Connector.open(url);
return connectionFactory.wrapSocket(this, s);
return wrapSocket((StreamConnection) Connector.open(url));
}
@Override
@@ -111,4 +119,10 @@ class JavaBluetoothPlugin
private String makeUrl(String address, String uuid) {
return "btspp://" + address + ":" + uuid + ";name=RFCOMM";
}
private DuplexTransportConnection wrapSocket(StreamConnection s)
throws IOException {
return new JavaBluetoothTransportConnection(this, connectionLimiter,
timeoutMonitor, s);
}
}

View File

@@ -2,54 +2,41 @@ package org.briarproject.bramble.plugin.bluetooth;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.io.TimeoutMonitor;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import java.security.SecureRandom;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.microedition.io.StreamConnection;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
@Immutable
@NotNullByDefault
public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private static final int MAX_LATENCY = (int) SECONDS.toMillis(30);
private static final int MAX_IDLE_TIME = (int) SECONDS.toMillis(30);
private static final int POLLING_INTERVAL = (int) MINUTES.toMillis(2);
private final Executor ioExecutor, wakefulIoExecutor;
private final Executor ioExecutor;
private final SecureRandom secureRandom;
private final EventBus eventBus;
private final TimeoutMonitor timeoutMonitor;
private final BackoffFactory backoffFactory;
@Inject
public JavaBluetoothPluginFactory(@IoExecutor Executor ioExecutor,
@WakefulIoExecutor Executor wakefulIoExecutor,
SecureRandom secureRandom,
EventBus eventBus,
TimeoutMonitor timeoutMonitor,
BackoffFactory backoffFactory) {
public JavaBluetoothPluginFactory(Executor ioExecutor,
SecureRandom secureRandom, EventBus eventBus,
TimeoutMonitor timeoutMonitor) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.secureRandom = secureRandom;
this.eventBus = eventBus;
this.timeoutMonitor = timeoutMonitor;
this.backoffFactory = backoffFactory;
}
@Override
@@ -66,14 +53,9 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
public DuplexPlugin createPlugin(PluginCallback callback) {
BluetoothConnectionLimiter connectionLimiter =
new BluetoothConnectionLimiterImpl(eventBus);
BluetoothConnectionFactory<StreamConnection> connectionFactory =
new JavaBluetoothConnectionFactory(connectionLimiter,
timeoutMonitor);
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(connectionLimiter,
connectionFactory, ioExecutor, wakefulIoExecutor, secureRandom,
backoff, callback, MAX_LATENCY, MAX_IDLE_TIME);
timeoutMonitor, ioExecutor, secureRandom, callback, MAX_LATENCY,
MAX_IDLE_TIME, POLLING_INTERVAL);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -16,20 +16,18 @@ class JavaBluetoothTransportConnection
extends AbstractDuplexTransportConnection {
private final BluetoothConnectionLimiter connectionLimiter;
private final StreamConnection socket;
private final StreamConnection stream;
private final InputStream in;
private final OutputStream out;
JavaBluetoothTransportConnection(Plugin plugin,
BluetoothConnectionLimiter connectionLimiter,
TimeoutMonitor timeoutMonitor,
StreamConnection socket) throws IOException {
StreamConnection stream) throws IOException {
super(plugin);
this.connectionLimiter = connectionLimiter;
this.socket = socket;
this.stream = stream;
in = timeoutMonitor.createTimeoutInputStream(
socket.openInputStream(), plugin.getMaxIdleTime() * 2);
out = socket.openOutputStream();
stream.openInputStream(), plugin.getMaxIdleTime() * 2);
}
@Override
@@ -38,15 +36,14 @@ class JavaBluetoothTransportConnection
}
@Override
protected OutputStream getOutputStream() {
return out;
protected OutputStream getOutputStream() throws IOException {
return stream.openOutputStream();
}
@Override
protected void closeConnection(boolean exception) throws IOException {
try {
socket.close();
in.close();
stream.close();
} finally {
connectionLimiter.connectionClosed(this);
}

View File

@@ -1,6 +1,5 @@
package org.briarproject.bramble.plugin.modem;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TransportId;
@@ -12,7 +11,6 @@ import org.briarproject.bramble.util.StringUtils;
import java.util.concurrent.Executor;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
@Immutable
@NotNullByDefault
@@ -23,8 +21,7 @@ public class ModemPluginFactory implements DuplexPluginFactory {
private final ModemFactory modemFactory;
private final SerialPortList serialPortList;
@Inject
public ModemPluginFactory(@IoExecutor Executor ioExecutor,
public ModemPluginFactory(Executor ioExecutor,
ReliabilityLayerFactory reliabilityFactory) {
modemFactory = new ModemFactoryImpl(ioExecutor, reliabilityFactory);
serialPortList = new SerialPortListImpl();

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
@@ -20,27 +19,20 @@ import javax.net.SocketFactory;
@NotNullByDefault
abstract class JavaTorPlugin extends TorPlugin {
JavaTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
JavaTorPlugin(Executor ioExecutor, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
int maxLatency,
int maxIdleTime,
File torDirectory) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
torRendezvousCrypto, callback, architecture,
maxLatency, maxIdleTime, torDirectory);
PluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, int initialPollingInterval,
int stablePollingInterval, File torDirectory) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
torRendezvousCrypto, callback, architecture, maxLatency,
maxIdleTime, initialPollingInterval, stablePollingInterval,
torDirectory);
}
@Override

View File

@@ -6,7 +6,6 @@ import com.sun.jna.Native;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
@@ -20,27 +19,20 @@ import javax.net.SocketFactory;
@NotNullByDefault
class UnixTorPlugin extends JavaTorPlugin {
UnixTorPlugin(Executor ioExecutor,
Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
SocketFactory torSocketFactory,
Clock clock,
ResourceProvider resourceProvider,
UnixTorPlugin(Executor ioExecutor, NetworkManager networkManager,
LocationUtils locationUtils, SocketFactory torSocketFactory,
Clock clock, ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Backoff backoff,
TorRendezvousCrypto torRendezvousCrypto,
PluginCallback callback,
String architecture,
int maxLatency,
int maxIdleTime,
File torDirectory) {
super(ioExecutor, wakefulIoExecutor, networkManager, locationUtils,
torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, backoff,
PluginCallback callback, String architecture, int maxLatency,
int maxIdleTime, int initialPollingInterval,
int stablePollingInterval, File torDirectory) {
super(ioExecutor, networkManager, locationUtils, torSocketFactory,
clock, resourceProvider, circumventionProvider, batteryManager,
torRendezvousCrypto, callback, architecture,
maxLatency, maxIdleTime, torDirectory);
maxLatency, maxIdleTime, initialPollingInterval,
stablePollingInterval, torDirectory);
}
@Override

View File

@@ -2,14 +2,10 @@ package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.Backoff;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.PluginCallback;
import org.briarproject.bramble.api.plugin.TorConstants;
import org.briarproject.bramble.api.plugin.TorDirectory;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
@@ -22,9 +18,10 @@ import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import javax.net.SocketFactory;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.OsUtils.isLinux;
@@ -35,44 +32,45 @@ public class UnixTorPluginFactory implements DuplexPluginFactory {
private static final Logger LOG =
getLogger(UnixTorPluginFactory.class.getName());
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
private static final int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
private static final double BACKOFF_BASE = 1.2;
private static final int MAX_LATENCY = (int) SECONDS.toMillis(30);
private static final int MAX_IDLE_TIME = (int) SECONDS.toMillis(30);
private final Executor ioExecutor, wakefulIoExecutor;
/**
* How often to poll before our hidden service becomes reachable.
*/
private static final int INITIAL_POLLING_INTERVAL =
(int) MINUTES.toMillis(1);
/**
* How often to poll when our hidden service is reachable. Our contacts
* will poll when they come online, so our polling is just a fallback in
* case of repeated connection failures.
*/
private static final int STABLE_POLLING_INTERVAL =
(int) MINUTES.toMillis(15);
private final Executor ioExecutor;
private final NetworkManager networkManager;
private final LocationUtils locationUtils;
private final EventBus eventBus;
private final SocketFactory torSocketFactory;
private final BackoffFactory backoffFactory;
private final ResourceProvider resourceProvider;
private final CircumventionProvider circumventionProvider;
private final BatteryManager batteryManager;
private final Clock clock;
private final File torDirectory;
@Inject
public UnixTorPluginFactory(@IoExecutor Executor ioExecutor,
@IoExecutor Executor wakefulIoExecutor,
NetworkManager networkManager,
LocationUtils locationUtils,
EventBus eventBus,
SocketFactory torSocketFactory,
BackoffFactory backoffFactory,
public UnixTorPluginFactory(Executor ioExecutor,
NetworkManager networkManager, LocationUtils locationUtils,
EventBus eventBus, SocketFactory torSocketFactory,
ResourceProvider resourceProvider,
CircumventionProvider circumventionProvider,
BatteryManager batteryManager,
Clock clock,
@TorDirectory File torDirectory) {
BatteryManager batteryManager, Clock clock, File torDirectory) {
this.ioExecutor = ioExecutor;
this.wakefulIoExecutor = wakefulIoExecutor;
this.networkManager = networkManager;
this.locationUtils = locationUtils;
this.eventBus = eventBus;
this.torSocketFactory = torSocketFactory;
this.backoffFactory = backoffFactory;
this.resourceProvider = resourceProvider;
this.circumventionProvider = circumventionProvider;
this.batteryManager = batteryManager;
@@ -105,14 +103,13 @@ public class UnixTorPluginFactory implements DuplexPluginFactory {
return null;
}
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
MAX_POLLING_INTERVAL, BACKOFF_BASE);
TorRendezvousCrypto torRendezvousCrypto = new TorRendezvousCryptoImpl();
UnixTorPlugin plugin = new UnixTorPlugin(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, torSocketFactory, clock,
resourceProvider, circumventionProvider, batteryManager,
backoff, torRendezvousCrypto, callback, architecture,
MAX_LATENCY, MAX_IDLE_TIME, torDirectory);
UnixTorPlugin plugin = new UnixTorPlugin(ioExecutor, networkManager,
locationUtils, torSocketFactory, clock, resourceProvider,
circumventionProvider, batteryManager, torRendezvousCrypto,
callback, architecture, MAX_LATENCY, MAX_IDLE_TIME,
INITIAL_POLLING_INTERVAL, STABLE_POLLING_INTERVAL,
torDirectory);
eventBus.addListener(plugin);
return plugin;
}

View File

@@ -1,16 +1,14 @@
package org.briarproject.bramble.plugin.tor;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.BrambleCoreEagerSingletons;
import org.briarproject.bramble.api.battery.BatteryManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.network.NetworkManager;
import org.briarproject.bramble.api.plugin.BackoffFactory;
import org.briarproject.bramble.api.plugin.duplex.DuplexPlugin;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.LocationUtils;
import org.briarproject.bramble.api.system.ResourceProvider;
import org.briarproject.bramble.api.system.WakefulIoExecutor;
import org.briarproject.bramble.test.BrambleJavaIntegrationTestComponent;
import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.test.DaggerBrambleJavaIntegrationTestComponent;
@@ -48,8 +46,7 @@ public class BridgeTest extends BrambleTestCase {
public static Iterable<String> data() {
BrambleJavaIntegrationTestComponent component =
DaggerBrambleJavaIntegrationTestComponent.builder().build();
BrambleCoreIntegrationTestEagerSingletons.Helper
.injectEagerSingletons(component);
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(component);
return component.getCircumventionProvider().getBridges(false);
}
@@ -61,9 +58,6 @@ public class BridgeTest extends BrambleTestCase {
@IoExecutor
Executor ioExecutor;
@Inject
@WakefulIoExecutor
Executor wakefulIoExecutor;
@Inject
NetworkManager networkManager;
@Inject
ResourceProvider resourceProvider;
@@ -74,8 +68,6 @@ public class BridgeTest extends BrambleTestCase {
@Inject
EventBus eventBus;
@Inject
BackoffFactory backoffFactory;
@Inject
Clock clock;
private final File torDir = getTestDirectory();
@@ -97,8 +89,7 @@ public class BridgeTest extends BrambleTestCase {
BrambleJavaIntegrationTestComponent component =
DaggerBrambleJavaIntegrationTestComponent.builder().build();
BrambleCoreIntegrationTestEagerSingletons.Helper
.injectEagerSingletons(component);
BrambleCoreEagerSingletons.Helper.injectEagerSingletons(component);
component.inject(this);
LocationUtils locationUtils = () -> "US";
@@ -125,10 +116,9 @@ public class BridgeTest extends BrambleTestCase {
return singletonList(bridge);
}
};
factory = new UnixTorPluginFactory(ioExecutor, wakefulIoExecutor,
networkManager, locationUtils, eventBus, torSocketFactory,
backoffFactory, resourceProvider, bridgeProvider,
batteryManager, clock, torDir);
factory = new UnixTorPluginFactory(ioExecutor, networkManager,
locationUtils, eventBus, torSocketFactory, resourceProvider,
bridgeProvider, batteryManager, clock, torDir);
}
@After

View File

@@ -9,10 +9,6 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings;
import java.util.Collection;
import static java.util.Collections.emptyList;
@NotNullByDefault
public class TestPluginCallback implements PluginCallback {
@@ -26,11 +22,6 @@ public class TestPluginCallback implements PluginCallback {
return new TransportProperties();
}
@Override
public Collection<TransportProperties> getRemoteProperties() {
return emptyList();
}
@Override
public void mergeSettings(Settings s) {
}

View File

@@ -1,6 +1,6 @@
package org.briarproject.bramble.test;
import org.briarproject.bramble.BrambleCoreIntegrationTestEagerSingletons;
import org.briarproject.bramble.BrambleCoreEagerSingletons;
import org.briarproject.bramble.BrambleCoreModule;
import org.briarproject.bramble.BrambleJavaModule;
import org.briarproject.bramble.plugin.tor.BridgeTest;
@@ -17,7 +17,7 @@ import dagger.Component;
BrambleJavaModule.class
})
public interface BrambleJavaIntegrationTestComponent
extends BrambleCoreIntegrationTestEagerSingletons {
extends BrambleCoreEagerSingletons {
void inject(BridgeTest init);

View File

@@ -22,8 +22,8 @@ android {
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
versionCode 10210
versionName "1.2.10"
versionCode 10207
versionName "1.2.7"
applicationId "org.briarproject.briar.android"
buildConfigField "String", "GitHash",
"\"${getStdout(['git', 'rev-parse', '--short=7', 'HEAD'], 'No commit hash')}\""

Some files were not shown because too many files have changed in this diff Show More