mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Compare commits
7 Commits
integratio
...
1712-bluet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80fa7d29b2 | ||
|
|
0db14bd9ad | ||
|
|
dd049012ce | ||
|
|
c382ce921c | ||
|
|
639dd43388 | ||
|
|
99adf37deb | ||
|
|
78391c604b |
@@ -9,6 +9,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.io.TimeoutMonitor;
|
||||||
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
@@ -30,6 +31,7 @@ import java.util.concurrent.BlockingQueue;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -76,11 +78,13 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
private volatile BluetoothAdapter adapter = null;
|
private volatile BluetoothAdapter adapter = null;
|
||||||
|
|
||||||
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
|
AndroidBluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
|
||||||
Executor ioExecutor, AndroidExecutor androidExecutor,
|
TimeoutMonitor timeoutMonitor, Executor ioExecutor,
|
||||||
Context appContext, SecureRandom secureRandom, Clock clock,
|
ScheduledExecutorService scheduler, SecureRandom secureRandom,
|
||||||
Backoff backoff, PluginCallback callback, int maxLatency) {
|
AndroidExecutor androidExecutor, Context appContext, Clock clock,
|
||||||
super(connectionLimiter, ioExecutor, secureRandom, backoff, callback,
|
Backoff backoff, PluginCallback callback, int maxLatency,
|
||||||
maxLatency);
|
int maxIdleTime) {
|
||||||
|
super(connectionLimiter, timeoutMonitor, ioExecutor, scheduler,
|
||||||
|
secureRandom, backoff, callback, maxLatency, maxIdleTime);
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
@@ -172,9 +176,10 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
return wrapSocket(ss.accept());
|
return wrapSocket(ss.accept());
|
||||||
}
|
}
|
||||||
|
|
||||||
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
|
private DuplexTransportConnection wrapSocket(BluetoothSocket s)
|
||||||
return new AndroidBluetoothTransportConnection(this,
|
throws IOException {
|
||||||
connectionLimiter, s);
|
return new AndroidBluetoothTransportConnection(this, connectionLimiter,
|
||||||
|
timeoutMonitor, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.plugin.bluetooth;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.io.TimeoutMonitor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
@@ -15,6 +16,7 @@ import org.briarproject.bramble.api.system.Clock;
|
|||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
@@ -25,28 +27,34 @@ import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
|
|||||||
public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
||||||
|
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
||||||
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
|
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 int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
|
||||||
private static final double BACKOFF_BASE = 1.2;
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
private final TimeoutMonitor timeoutMonitor;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
|
|
||||||
public AndroidBluetoothPluginFactory(Executor ioExecutor,
|
public AndroidBluetoothPluginFactory(Executor ioExecutor,
|
||||||
AndroidExecutor androidExecutor, Context appContext,
|
ScheduledExecutorService scheduler, AndroidExecutor androidExecutor,
|
||||||
SecureRandom secureRandom, EventBus eventBus, Clock clock,
|
Context appContext, SecureRandom secureRandom, EventBus eventBus,
|
||||||
|
Clock clock, TimeoutMonitor timeoutMonitor,
|
||||||
BackoffFactory backoffFactory) {
|
BackoffFactory backoffFactory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.scheduler = scheduler;
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
|
this.timeoutMonitor = timeoutMonitor;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,8 +75,9 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
|
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
|
||||||
connectionLimiter, ioExecutor, androidExecutor, appContext,
|
connectionLimiter, timeoutMonitor, ioExecutor, scheduler,
|
||||||
secureRandom, clock, backoff, callback, MAX_LATENCY);
|
secureRandom, androidExecutor, appContext, clock, backoff,
|
||||||
|
callback, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.plugin.bluetooth;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothSocket;
|
import android.bluetooth.BluetoothSocket;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.io.TimeoutMonitor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
|
||||||
@@ -17,22 +18,26 @@ import static org.briarproject.bramble.util.AndroidUtils.isValidBluetoothAddress
|
|||||||
class AndroidBluetoothTransportConnection
|
class AndroidBluetoothTransportConnection
|
||||||
extends AbstractDuplexTransportConnection {
|
extends AbstractDuplexTransportConnection {
|
||||||
|
|
||||||
private final BluetoothConnectionLimiter connectionManager;
|
private final BluetoothConnectionLimiter connectionLimiter;
|
||||||
private final BluetoothSocket socket;
|
private final BluetoothSocket socket;
|
||||||
|
private final InputStream in;
|
||||||
|
|
||||||
AndroidBluetoothTransportConnection(Plugin plugin,
|
AndroidBluetoothTransportConnection(Plugin plugin,
|
||||||
BluetoothConnectionLimiter connectionManager,
|
BluetoothConnectionLimiter connectionLimiter,
|
||||||
BluetoothSocket socket) {
|
TimeoutMonitor timeoutMonitor, BluetoothSocket socket)
|
||||||
|
throws IOException {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
this.connectionManager = connectionManager;
|
this.connectionLimiter = connectionLimiter;
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
|
in = timeoutMonitor.createTimeoutInputStream(
|
||||||
|
socket.getInputStream(), plugin.getMaxIdleTime() * 2);
|
||||||
String address = socket.getRemoteDevice().getAddress();
|
String address = socket.getRemoteDevice().getAddress();
|
||||||
if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address);
|
if (isValidBluetoothAddress(address)) remote.put(PROP_ADDRESS, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InputStream getInputStream() throws IOException {
|
protected InputStream getInputStream() {
|
||||||
return socket.getInputStream();
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -45,7 +50,7 @@ class AndroidBluetoothTransportConnection
|
|||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
} finally {
|
} finally {
|
||||||
connectionManager.connectionClosed(this);
|
connectionLimiter.connectionClosed(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.briarproject.bramble.api.io;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public interface TimeoutMonitor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link InputStream} that wraps the given stream and allows
|
||||||
|
* read timeouts to be detected.
|
||||||
|
*
|
||||||
|
* @param timeoutMs The read timeout in milliseconds. Timeouts will be
|
||||||
|
* detected eventually but are not guaranteed to be detected immediately.
|
||||||
|
*/
|
||||||
|
InputStream createTimeoutInputStream(InputStream in, long timeoutMs);
|
||||||
|
}
|
||||||
@@ -11,6 +11,11 @@ public interface Clock {
|
|||||||
*/
|
*/
|
||||||
long currentTimeMillis();
|
long currentTimeMillis();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see System#nanoTime()
|
||||||
|
*/
|
||||||
|
long nanoTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Thread#sleep(long)
|
* @see Thread#sleep(long)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ public class ArrayClock implements Clock {
|
|||||||
return times[index++];
|
return times[index++];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nanoTime() {
|
||||||
|
return times[index++] * 1_000_000;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sleep(long milliseconds) throws InterruptedException {
|
public void sleep(long milliseconds) throws InterruptedException {
|
||||||
Thread.sleep(milliseconds);
|
Thread.sleep(milliseconds);
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ public class SettableClock implements Clock {
|
|||||||
return time.get();
|
return time.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nanoTime() {
|
||||||
|
return time.get() * 1_000_000;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sleep(long milliseconds) throws InterruptedException {
|
public void sleep(long milliseconds) throws InterruptedException {
|
||||||
Thread.sleep(milliseconds);
|
Thread.sleep(milliseconds);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.briarproject.bramble.db.DatabaseExecutorModule;
|
|||||||
import org.briarproject.bramble.db.DatabaseModule;
|
import org.briarproject.bramble.db.DatabaseModule;
|
||||||
import org.briarproject.bramble.event.EventModule;
|
import org.briarproject.bramble.event.EventModule;
|
||||||
import org.briarproject.bramble.identity.IdentityModule;
|
import org.briarproject.bramble.identity.IdentityModule;
|
||||||
|
import org.briarproject.bramble.io.IoModule;
|
||||||
import org.briarproject.bramble.keyagreement.KeyAgreementModule;
|
import org.briarproject.bramble.keyagreement.KeyAgreementModule;
|
||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.bramble.plugin.PluginModule;
|
import org.briarproject.bramble.plugin.PluginModule;
|
||||||
@@ -35,6 +36,7 @@ import dagger.Module;
|
|||||||
DatabaseExecutorModule.class,
|
DatabaseExecutorModule.class,
|
||||||
EventModule.class,
|
EventModule.class,
|
||||||
IdentityModule.class,
|
IdentityModule.class,
|
||||||
|
IoModule.class,
|
||||||
KeyAgreementModule.class,
|
KeyAgreementModule.class,
|
||||||
LifecycleModule.class,
|
LifecycleModule.class,
|
||||||
PluginModule.class,
|
PluginModule.class,
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.briarproject.bramble.io;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.io.TimeoutMonitor;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class IoModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
TimeoutMonitor provideTimeoutMonitor(TimeoutMonitorImpl timeoutMonitor) {
|
||||||
|
return timeoutMonitor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package org.briarproject.bramble.io;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.system.Clock;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
|
class TimeoutInputStream extends InputStream {
|
||||||
|
|
||||||
|
private final Clock clock;
|
||||||
|
private final InputStream in;
|
||||||
|
private final long timeoutNs;
|
||||||
|
private final CloseListener listener;
|
||||||
|
private final Object lock = new Object();
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private long readStartedNs = -1;
|
||||||
|
|
||||||
|
TimeoutInputStream(Clock clock, InputStream in, long timeoutNs,
|
||||||
|
CloseListener listener) {
|
||||||
|
this.clock = clock;
|
||||||
|
this.in = in;
|
||||||
|
this.timeoutNs = timeoutNs;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
synchronized (lock) {
|
||||||
|
readStartedNs = clock.nanoTime();
|
||||||
|
}
|
||||||
|
int input = in.read();
|
||||||
|
synchronized (lock) {
|
||||||
|
readStartedNs = -1;
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b) throws IOException {
|
||||||
|
return read(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
synchronized (lock) {
|
||||||
|
readStartedNs = clock.nanoTime();
|
||||||
|
}
|
||||||
|
int read = in.read(b, off, len);
|
||||||
|
synchronized (lock) {
|
||||||
|
readStartedNs = -1;
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} finally {
|
||||||
|
listener.onClose(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int available() throws IOException {
|
||||||
|
return in.available();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mark(int readlimit) {
|
||||||
|
in.mark(readlimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean markSupported() {
|
||||||
|
return in.markSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() throws IOException {
|
||||||
|
in.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
return in.skip(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasTimedOut() {
|
||||||
|
synchronized (lock) {
|
||||||
|
return readStartedNs != -1 &&
|
||||||
|
clock.nanoTime() - readStartedNs > timeoutNs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CloseListener {
|
||||||
|
|
||||||
|
void onClose(TimeoutInputStream closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
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.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;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
|
import static java.util.logging.Logger.getLogger;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
class TimeoutMonitorImpl implements TimeoutMonitor {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
getLogger(TimeoutMonitorImpl.class.getName());
|
||||||
|
|
||||||
|
private static final long CHECK_INTERVAL_MS = SECONDS.toMillis(10);
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
|
private final Executor ioExecutor;
|
||||||
|
private final Clock clock;
|
||||||
|
private final Object lock = new Object();
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private final List<TimeoutInputStream> streams = new ArrayList<>();
|
||||||
|
|
||||||
|
@GuardedBy("lock")
|
||||||
|
private Future<?> task = null;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
TimeoutMonitorImpl(@Scheduler ScheduledExecutorService scheduler,
|
||||||
|
@IoExecutor Executor ioExecutor, Clock clock) {
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.clock = clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream createTimeoutInputStream(InputStream in,
|
||||||
|
long timeoutMs) {
|
||||||
|
TimeoutInputStream stream = new TimeoutInputStream(clock, in,
|
||||||
|
timeoutMs * 1_000_000, this::removeStream);
|
||||||
|
synchronized (lock) {
|
||||||
|
if (streams.isEmpty()) {
|
||||||
|
task = scheduler.scheduleWithFixedDelay(this::checkTimeouts,
|
||||||
|
CHECK_INTERVAL_MS, CHECK_INTERVAL_MS, MILLISECONDS);
|
||||||
|
}
|
||||||
|
streams.add(stream);
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeStream(TimeoutInputStream stream) {
|
||||||
|
Future<?> toCancel = null;
|
||||||
|
synchronized (lock) {
|
||||||
|
if (streams.remove(stream) && streams.isEmpty()) {
|
||||||
|
toCancel = task;
|
||||||
|
task = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toCancel != null) toCancel.cancel(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduler
|
||||||
|
private void checkTimeouts() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import org.briarproject.bramble.api.Pair;
|
|||||||
import org.briarproject.bramble.api.data.BdfList;
|
import org.briarproject.bramble.api.data.BdfList;
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
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.KeyAgreementConnection;
|
||||||
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
import org.briarproject.bramble.api.keyagreement.KeyAgreementListener;
|
||||||
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
|
import org.briarproject.bramble.api.keyagreement.event.KeyAgreementListeningEvent;
|
||||||
@@ -30,13 +31,17 @@ import org.briarproject.bramble.api.settings.event.SettingsUpdatedEvent;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
@@ -59,13 +64,22 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(BluetoothPlugin.class.getName());
|
getLogger(BluetoothPlugin.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The delay between connection attempts when polling. This reduces
|
||||||
|
* interference between Bluetooth and wifi.
|
||||||
|
*/
|
||||||
|
private static final long CONNECTION_ATTEMPT_INTERVAL_MS =
|
||||||
|
SECONDS.toMillis(5);
|
||||||
|
|
||||||
final BluetoothConnectionLimiter connectionLimiter;
|
final BluetoothConnectionLimiter connectionLimiter;
|
||||||
|
final TimeoutMonitor timeoutMonitor;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
private final PluginCallback callback;
|
private final PluginCallback callback;
|
||||||
private final int maxLatency;
|
private final int maxLatency, maxIdleTime;
|
||||||
private final AtomicBoolean used = new AtomicBoolean(false);
|
private final AtomicBoolean used = new AtomicBoolean(false);
|
||||||
|
|
||||||
private volatile boolean running = false, contactConnections = false;
|
private volatile boolean running = false, contactConnections = false;
|
||||||
@@ -105,14 +119,19 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
abstract DuplexTransportConnection discoverAndConnect(String uuid);
|
abstract DuplexTransportConnection discoverAndConnect(String uuid);
|
||||||
|
|
||||||
BluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
|
BluetoothPlugin(BluetoothConnectionLimiter connectionLimiter,
|
||||||
Executor ioExecutor, SecureRandom secureRandom,
|
TimeoutMonitor timeoutMonitor, Executor ioExecutor,
|
||||||
Backoff backoff, PluginCallback callback, int maxLatency) {
|
ScheduledExecutorService scheduler, SecureRandom secureRandom,
|
||||||
|
Backoff backoff, PluginCallback callback, int maxLatency,
|
||||||
|
int maxIdleTime) {
|
||||||
this.connectionLimiter = connectionLimiter;
|
this.connectionLimiter = connectionLimiter;
|
||||||
|
this.timeoutMonitor = timeoutMonitor;
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.scheduler = scheduler;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
|
this.maxIdleTime = maxIdleTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAdapterEnabled() {
|
void onAdapterEnabled() {
|
||||||
@@ -141,8 +160,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxIdleTime() {
|
public int getMaxIdleTime() {
|
||||||
// Bluetooth detects dead connections so we don't need keepalives
|
return maxIdleTime;
|
||||||
return Integer.MAX_VALUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -264,21 +282,31 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
properties) {
|
properties) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
backoff.increment();
|
backoff.increment();
|
||||||
for (Pair<TransportProperties, ConnectionHandler> p : properties) {
|
LinkedList<Pair<TransportProperties, ConnectionHandler>> connectable =
|
||||||
connect(p.getFirst(), p.getSecond());
|
new LinkedList<>();
|
||||||
|
for (Pair<TransportProperties, ConnectionHandler> pair : properties) {
|
||||||
|
TransportProperties p = pair.getFirst();
|
||||||
|
if (isNullOrEmpty(p.get(PROP_ADDRESS))) continue;
|
||||||
|
if (isNullOrEmpty(p.get(PROP_UUID))) continue;
|
||||||
|
connectable.add(pair);
|
||||||
}
|
}
|
||||||
|
if (!connectable.isEmpty()) poll(connectable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connect(TransportProperties p, ConnectionHandler h) {
|
private void poll(LinkedList<Pair<TransportProperties, ConnectionHandler>>
|
||||||
String address = p.get(PROP_ADDRESS);
|
connectable) {
|
||||||
if (isNullOrEmpty(address)) return;
|
|
||||||
String uuid = p.get(PROP_UUID);
|
|
||||||
if (isNullOrEmpty(uuid)) return;
|
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
DuplexTransportConnection d = createConnection(p);
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
|
Pair<TransportProperties, ConnectionHandler> pair =
|
||||||
|
connectable.removeFirst();
|
||||||
|
DuplexTransportConnection d = createConnection(pair.getFirst());
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
h.handleConnection(d);
|
pair.getSecond().handleConnection(d);
|
||||||
|
}
|
||||||
|
if (!connectable.isEmpty()) {
|
||||||
|
scheduler.schedule(() -> poll(connectable),
|
||||||
|
CONNECTION_ATTEMPT_INTERVAL_MS, MILLISECONDS);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ public class SystemClock implements Clock {
|
|||||||
return System.currentTimeMillis();
|
return System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nanoTime() {
|
||||||
|
return System.nanoTime();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sleep(long milliseconds) throws InterruptedException {
|
public void sleep(long milliseconds) throws InterruptedException {
|
||||||
Thread.sleep(milliseconds);
|
Thread.sleep(milliseconds);
|
||||||
|
|||||||
@@ -2420,6 +2420,11 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nanoTime() {
|
||||||
|
return time * 1_000_000;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sleep(long milliseconds) throws InterruptedException {
|
public void sleep(long milliseconds) throws InterruptedException {
|
||||||
Thread.sleep(milliseconds);
|
Thread.sleep(milliseconds);
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
package org.briarproject.bramble.io;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.test.BrambleTestCase;
|
||||||
|
import org.briarproject.bramble.test.SettableClock;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public class TimeoutInputStreamTest extends BrambleTestCase {
|
||||||
|
|
||||||
|
private static final long TIMEOUT_MS = MINUTES.toMillis(1);
|
||||||
|
|
||||||
|
private final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
private AtomicLong time;
|
||||||
|
private UnresponsiveInputStream in;
|
||||||
|
private AtomicBoolean listenerCalled;
|
||||||
|
private TimeoutInputStream stream;
|
||||||
|
private CountDownLatch readReturned;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
time = new AtomicLong(now);
|
||||||
|
in = new UnresponsiveInputStream();
|
||||||
|
listenerCalled = new AtomicBoolean(false);
|
||||||
|
stream = new TimeoutInputStream(new SettableClock(time), in,
|
||||||
|
TIMEOUT_MS * 1_000_000, stream -> listenerCalled.set(true));
|
||||||
|
readReturned = new CountDownLatch(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeoutIsReportedIfReadDoesNotReturn() throws Exception {
|
||||||
|
startReading();
|
||||||
|
try {
|
||||||
|
// The stream should not report a timeout
|
||||||
|
assertFalse(stream.hasTimedOut());
|
||||||
|
|
||||||
|
// Time passes
|
||||||
|
time.set(now + TIMEOUT_MS);
|
||||||
|
|
||||||
|
// The stream still shouldn't report a timeout
|
||||||
|
assertFalse(stream.hasTimedOut());
|
||||||
|
|
||||||
|
// Time passes
|
||||||
|
time.set(now + TIMEOUT_MS + 1);
|
||||||
|
|
||||||
|
// The stream should report a timeout
|
||||||
|
assertTrue(stream.hasTimedOut());
|
||||||
|
|
||||||
|
// The listener should not have been called yet
|
||||||
|
assertFalse(listenerCalled.get());
|
||||||
|
|
||||||
|
// Close the stream
|
||||||
|
stream.close();
|
||||||
|
|
||||||
|
// The listener should have been called
|
||||||
|
assertTrue(listenerCalled.get());
|
||||||
|
} finally {
|
||||||
|
// Allow the read to return
|
||||||
|
in.readFinished.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeoutIsNotReportedIfReadReturns() throws Exception {
|
||||||
|
startReading();
|
||||||
|
try {
|
||||||
|
// The stream should not report a timeout
|
||||||
|
assertFalse(stream.hasTimedOut());
|
||||||
|
|
||||||
|
// Time passes
|
||||||
|
time.set(now + TIMEOUT_MS);
|
||||||
|
|
||||||
|
// The stream still shouldn't report a timeout
|
||||||
|
assertFalse(stream.hasTimedOut());
|
||||||
|
|
||||||
|
// Allow the read to finish and wait for it to return
|
||||||
|
in.readFinished.countDown();
|
||||||
|
readReturned.await(10, SECONDS);
|
||||||
|
|
||||||
|
// Time passes
|
||||||
|
time.set(now + TIMEOUT_MS + 1);
|
||||||
|
|
||||||
|
// The stream should not report a timeout as the read has returned
|
||||||
|
assertFalse(stream.hasTimedOut());
|
||||||
|
|
||||||
|
// The listener should not have been called yet
|
||||||
|
assertFalse(listenerCalled.get());
|
||||||
|
|
||||||
|
// Close the stream
|
||||||
|
stream.close();
|
||||||
|
|
||||||
|
// The listener should have been called
|
||||||
|
assertTrue(listenerCalled.get());
|
||||||
|
} finally {
|
||||||
|
// Allow the read to return in case an assertion was thrown
|
||||||
|
in.readFinished.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startReading() throws Exception {
|
||||||
|
// Start a background thread to read from the unresponsive stream
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
assertEquals(123, stream.read());
|
||||||
|
readReturned.countDown();
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
// Wait for the background thread to start reading
|
||||||
|
assertTrue(in.readStarted.await(10, SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UnresponsiveInputStream extends InputStream {
|
||||||
|
|
||||||
|
private final CountDownLatch readStarted = new CountDownLatch(1);
|
||||||
|
private final CountDownLatch readFinished = new CountDownLatch(1);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
readStarted.countDown();
|
||||||
|
try {
|
||||||
|
readFinished.await();
|
||||||
|
return 123;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.plugin;
|
package org.briarproject.bramble.plugin;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
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.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
@@ -9,6 +10,7 @@ import org.briarproject.bramble.api.plugin.PluginConfig;
|
|||||||
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
import org.briarproject.bramble.api.plugin.simplex.SimplexPluginFactory;
|
||||||
import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory;
|
import org.briarproject.bramble.api.reliability.ReliabilityLayerFactory;
|
||||||
|
import org.briarproject.bramble.api.system.Scheduler;
|
||||||
import org.briarproject.bramble.plugin.bluetooth.JavaBluetoothPluginFactory;
|
import org.briarproject.bramble.plugin.bluetooth.JavaBluetoothPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.modem.ModemPluginFactory;
|
import org.briarproject.bramble.plugin.modem.ModemPluginFactory;
|
||||||
import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory;
|
import org.briarproject.bramble.plugin.tcp.LanTcpPluginFactory;
|
||||||
@@ -17,6 +19,7 @@ import org.briarproject.bramble.plugin.tcp.WanTcpPluginFactory;
|
|||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
@@ -29,12 +32,14 @@ public class DesktopPluginModule extends PluginModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
PluginConfig getPluginConfig(@IoExecutor Executor ioExecutor,
|
PluginConfig getPluginConfig(@IoExecutor Executor ioExecutor,
|
||||||
|
@Scheduler ScheduledExecutorService scheduler,
|
||||||
SecureRandom random, BackoffFactory backoffFactory,
|
SecureRandom random, BackoffFactory backoffFactory,
|
||||||
ReliabilityLayerFactory reliabilityFactory,
|
ReliabilityLayerFactory reliabilityFactory,
|
||||||
ShutdownManager shutdownManager, EventBus eventBus) {
|
ShutdownManager shutdownManager, EventBus eventBus,
|
||||||
DuplexPluginFactory bluetooth =
|
TimeoutMonitor timeoutMonitor) {
|
||||||
new JavaBluetoothPluginFactory(ioExecutor, random, eventBus,
|
DuplexPluginFactory bluetooth = new JavaBluetoothPluginFactory(
|
||||||
backoffFactory);
|
ioExecutor, scheduler, random, eventBus, timeoutMonitor,
|
||||||
|
backoffFactory);
|
||||||
DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor,
|
DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor,
|
||||||
reliabilityFactory);
|
reliabilityFactory);
|
||||||
DuplexPluginFactory lan = new LanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory lan = new LanTcpPluginFactory(ioExecutor,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.plugin.bluetooth;
|
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.MethodsNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
@@ -9,6 +10,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -34,10 +36,12 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
|||||||
private volatile LocalDevice localDevice = null;
|
private volatile LocalDevice localDevice = null;
|
||||||
|
|
||||||
JavaBluetoothPlugin(BluetoothConnectionLimiter connectionManager,
|
JavaBluetoothPlugin(BluetoothConnectionLimiter connectionManager,
|
||||||
Executor ioExecutor, SecureRandom secureRandom,
|
TimeoutMonitor timeoutMonitor, Executor ioExecutor,
|
||||||
Backoff backoff, PluginCallback callback, int maxLatency) {
|
ScheduledExecutorService scheduler, SecureRandom secureRandom,
|
||||||
super(connectionManager, ioExecutor, secureRandom, backoff, callback,
|
Backoff backoff, PluginCallback callback, int maxLatency,
|
||||||
maxLatency);
|
int maxIdleTime) {
|
||||||
|
super(connectionManager, timeoutMonitor, ioExecutor, scheduler,
|
||||||
|
secureRandom, backoff, callback, maxLatency, maxIdleTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -119,7 +123,9 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
|||||||
return "btspp://" + address + ":" + uuid + ";name=RFCOMM";
|
return "btspp://" + address + ":" + uuid + ";name=RFCOMM";
|
||||||
}
|
}
|
||||||
|
|
||||||
private DuplexTransportConnection wrapSocket(StreamConnection s) {
|
private DuplexTransportConnection wrapSocket(StreamConnection s)
|
||||||
return new JavaBluetoothTransportConnection(this, connectionLimiter, s);
|
throws IOException {
|
||||||
|
return new JavaBluetoothTransportConnection(this, connectionLimiter,
|
||||||
|
timeoutMonitor, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.plugin.bluetooth;
|
package org.briarproject.bramble.plugin.bluetooth;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
import org.briarproject.bramble.api.io.TimeoutMonitor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Backoff;
|
import org.briarproject.bramble.api.plugin.Backoff;
|
||||||
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
import org.briarproject.bramble.api.plugin.BackoffFactory;
|
||||||
@@ -11,6 +12,7 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexPluginFactory;
|
|||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
@@ -21,22 +23,28 @@ import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID;
|
|||||||
public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
|
public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
||||||
|
private static final int MAX_IDLE_TIME = 30 * 1000; // 30 seconds
|
||||||
private static final int MIN_POLLING_INTERVAL = 60 * 1000; // 1 minute
|
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 int MAX_POLLING_INTERVAL = 10 * 60 * 1000; // 10 mins
|
||||||
private static final double BACKOFF_BASE = 1.2;
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
private final BackoffFactory backoffFactory;
|
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
private final TimeoutMonitor timeoutMonitor;
|
||||||
|
private final BackoffFactory backoffFactory;
|
||||||
|
|
||||||
public JavaBluetoothPluginFactory(Executor ioExecutor,
|
public JavaBluetoothPluginFactory(Executor ioExecutor,
|
||||||
SecureRandom secureRandom, EventBus eventBus,
|
ScheduledExecutorService scheduler, SecureRandom secureRandom,
|
||||||
|
EventBus eventBus, TimeoutMonitor timeoutMonitor,
|
||||||
BackoffFactory backoffFactory) {
|
BackoffFactory backoffFactory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.scheduler = scheduler;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
this.backoffFactory = backoffFactory;
|
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.timeoutMonitor = timeoutMonitor;
|
||||||
|
this.backoffFactory = backoffFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -56,7 +64,8 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(connectionLimiter,
|
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(connectionLimiter,
|
||||||
ioExecutor, secureRandom, backoff, callback, MAX_LATENCY);
|
timeoutMonitor, ioExecutor, scheduler, secureRandom, backoff,
|
||||||
|
callback, MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.plugin.bluetooth;
|
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.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.plugin.Plugin;
|
import org.briarproject.bramble.api.plugin.Plugin;
|
||||||
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
|
import org.briarproject.bramble.api.plugin.duplex.AbstractDuplexTransportConnection;
|
||||||
@@ -14,20 +15,24 @@ import javax.microedition.io.StreamConnection;
|
|||||||
class JavaBluetoothTransportConnection
|
class JavaBluetoothTransportConnection
|
||||||
extends AbstractDuplexTransportConnection {
|
extends AbstractDuplexTransportConnection {
|
||||||
|
|
||||||
private final BluetoothConnectionLimiter connectionManager;
|
private final BluetoothConnectionLimiter connectionLimiter;
|
||||||
private final StreamConnection stream;
|
private final StreamConnection stream;
|
||||||
|
private final InputStream in;
|
||||||
|
|
||||||
JavaBluetoothTransportConnection(Plugin plugin,
|
JavaBluetoothTransportConnection(Plugin plugin,
|
||||||
BluetoothConnectionLimiter connectionManager,
|
BluetoothConnectionLimiter connectionLimiter,
|
||||||
StreamConnection stream) {
|
TimeoutMonitor timeoutMonitor,
|
||||||
|
StreamConnection stream) throws IOException {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
|
this.connectionLimiter = connectionLimiter;
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
this.connectionManager = connectionManager;
|
in = timeoutMonitor.createTimeoutInputStream(
|
||||||
|
stream.openInputStream(), plugin.getMaxIdleTime() * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InputStream getInputStream() throws IOException {
|
protected InputStream getInputStream() {
|
||||||
return stream.openInputStream();
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -40,7 +45,7 @@ class JavaBluetoothTransportConnection
|
|||||||
try {
|
try {
|
||||||
stream.close();
|
stream.close();
|
||||||
} finally {
|
} finally {
|
||||||
connectionManager.connectionClosed(this);
|
connectionLimiter.connectionClosed(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.crypto.KeyStrengthener;
|
|||||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
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.IoExecutor;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.api.network.NetworkManager;
|
import org.briarproject.bramble.api.network.NetworkManager;
|
||||||
@@ -122,11 +123,12 @@ public class AppModule {
|
|||||||
LocationUtils locationUtils, EventBus eventBus,
|
LocationUtils locationUtils, EventBus eventBus,
|
||||||
ResourceProvider resourceProvider,
|
ResourceProvider resourceProvider,
|
||||||
CircumventionProvider circumventionProvider,
|
CircumventionProvider circumventionProvider,
|
||||||
BatteryManager batteryManager, Clock clock) {
|
BatteryManager batteryManager, Clock clock,
|
||||||
|
TimeoutMonitor timeoutMonitor) {
|
||||||
Context appContext = app.getApplicationContext();
|
Context appContext = app.getApplicationContext();
|
||||||
DuplexPluginFactory bluetooth =
|
DuplexPluginFactory bluetooth = new AndroidBluetoothPluginFactory(
|
||||||
new AndroidBluetoothPluginFactory(ioExecutor, androidExecutor,
|
ioExecutor, scheduler, androidExecutor, appContext, random,
|
||||||
appContext, random, eventBus, clock, backoffFactory);
|
eventBus, clock, timeoutMonitor, backoffFactory);
|
||||||
DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor,
|
DuplexPluginFactory tor = new AndroidTorPluginFactory(ioExecutor,
|
||||||
scheduler, appContext, networkManager, locationUtils, eventBus,
|
scheduler, appContext, networkManager, locationUtils, eventBus,
|
||||||
torSocketFactory, backoffFactory, resourceProvider,
|
torSocketFactory, backoffFactory, resourceProvider,
|
||||||
|
|||||||
Reference in New Issue
Block a user