mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Limit the number of open Bluetooth connections.
This commit is contained in:
@@ -55,10 +55,12 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
// Non-null if the plugin started successfully
|
||||
private volatile BluetoothAdapter adapter = null;
|
||||
|
||||
AndroidBluetoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor,
|
||||
AndroidBluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||
Executor ioExecutor, AndroidExecutor androidExecutor,
|
||||
Context appContext, SecureRandom secureRandom, Backoff backoff,
|
||||
DuplexPluginCallback callback, int maxLatency) {
|
||||
super(ioExecutor, secureRandom, backoff, callback, maxLatency);
|
||||
super(connectionManager, ioExecutor, secureRandom, backoff, callback,
|
||||
maxLatency);
|
||||
this.androidExecutor = androidExecutor;
|
||||
this.appContext = appContext;
|
||||
}
|
||||
@@ -154,7 +156,8 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
||||
}
|
||||
|
||||
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
|
||||
return new AndroidBluetoothTransportConnection(this, s);
|
||||
return new AndroidBluetoothTransportConnection(this,
|
||||
connectionManager, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -59,11 +59,13 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
||||
|
||||
@Override
|
||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||
BluetoothConnectionManager connectionManager =
|
||||
new BluetoothConnectionManagerImpl();
|
||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(ioExecutor,
|
||||
androidExecutor, appContext, secureRandom, backoff, callback,
|
||||
MAX_LATENCY);
|
||||
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
|
||||
connectionManager, ioExecutor, androidExecutor, appContext,
|
||||
secureRandom, backoff, callback, MAX_LATENCY);
|
||||
eventBus.addListener(plugin);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,14 @@ import java.io.OutputStream;
|
||||
class AndroidBluetoothTransportConnection
|
||||
extends AbstractDuplexTransportConnection {
|
||||
|
||||
private final BluetoothConnectionManager connectionManager;
|
||||
private final BluetoothSocket socket;
|
||||
|
||||
AndroidBluetoothTransportConnection(Plugin plugin, BluetoothSocket socket) {
|
||||
AndroidBluetoothTransportConnection(Plugin plugin,
|
||||
BluetoothConnectionManager connectionManager,
|
||||
BluetoothSocket socket) {
|
||||
super(plugin);
|
||||
this.connectionManager = connectionManager;
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
@@ -33,6 +37,10 @@ class AndroidBluetoothTransportConnection
|
||||
|
||||
@Override
|
||||
protected void closeConnection(boolean exception) throws IOException {
|
||||
socket.close();
|
||||
try {
|
||||
socket.close();
|
||||
} finally {
|
||||
connectionManager.connectionClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.briarproject.bramble.plugin.bluetooth;
|
||||
|
||||
interface BluetoothConnectionManager {
|
||||
|
||||
/**
|
||||
* Returns true if a contact connection can be opened without exceeding
|
||||
* the connection limit.
|
||||
*/
|
||||
boolean canOpenConnection();
|
||||
|
||||
/**
|
||||
* Increments the number of open connections and returns true if the new
|
||||
* connection can be kept open without exceeding the connection limit.
|
||||
*/
|
||||
boolean connectionOpened();
|
||||
|
||||
/**
|
||||
* Decrements the number of open connections.
|
||||
*/
|
||||
void connectionClosed();
|
||||
|
||||
/**
|
||||
* Resets the number of open connections.
|
||||
*/
|
||||
void allConnectionsClosed();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.briarproject.bramble.plugin.bluetooth;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
|
||||
class BluetoothConnectionManagerImpl implements BluetoothConnectionManager {
|
||||
|
||||
private static final int MAX_OPEN_CONNECTIONS = 5;
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(BluetoothConnectionManagerImpl.class.getName());
|
||||
|
||||
private final AtomicInteger openConnections = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public boolean canOpenConnection() {
|
||||
int open = openConnections.get();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(open + " open connections");
|
||||
return open < MAX_OPEN_CONNECTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean connectionOpened() {
|
||||
int open = openConnections.incrementAndGet();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connection opened, " + open + " open");
|
||||
return open <= MAX_OPEN_CONNECTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
int open = openConnections.decrementAndGet();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connection closed, " + open + " open");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void allConnectionsClosed() {
|
||||
LOG.info("All connections closed");
|
||||
openConnections.set(0);
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(BluetoothPlugin.class.getName());
|
||||
|
||||
protected final BluetoothConnectionManager connectionManager;
|
||||
|
||||
private final Executor ioExecutor;
|
||||
private final SecureRandom secureRandom;
|
||||
private final Backoff backoff;
|
||||
@@ -92,8 +94,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
abstract DuplexTransportConnection connectTo(String address, String uuid)
|
||||
throws IOException;
|
||||
|
||||
BluetoothPlugin(Executor ioExecutor, SecureRandom secureRandom,
|
||||
BluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||
Executor ioExecutor, SecureRandom secureRandom,
|
||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||
this.connectionManager = connectionManager;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.secureRandom = secureRandom;
|
||||
this.backoff = backoff;
|
||||
@@ -111,6 +115,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
void onAdapterDisabled() {
|
||||
LOG.info("Bluetooth disabled");
|
||||
tryToClose(socket);
|
||||
connectionManager.allConnectionsClosed();
|
||||
callback.transportDisabled();
|
||||
}
|
||||
|
||||
@@ -214,11 +219,25 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
return;
|
||||
}
|
||||
backoff.reset();
|
||||
callback.incomingConnectionCreated(conn);
|
||||
if (connectionManager.connectionOpened()) {
|
||||
callback.incomingConnectionCreated(conn);
|
||||
} else {
|
||||
LOG.info("Closing incoming connection");
|
||||
tryToCloseUnusedConnection(conn);
|
||||
}
|
||||
if (!running) return;
|
||||
}
|
||||
}
|
||||
|
||||
private void tryToCloseUnusedConnection(DuplexTransportConnection conn) {
|
||||
try {
|
||||
conn.getWriter().dispose(false);
|
||||
conn.getReader().dispose(false, false);
|
||||
} catch (IOException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
running = false;
|
||||
@@ -258,10 +277,19 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||
ioExecutor.execute(() -> {
|
||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||
if (!connectionManager.canOpenConnection()) {
|
||||
LOG.info("Not connecting, too many open connections");
|
||||
return;
|
||||
}
|
||||
DuplexTransportConnection conn = connect(address, uuid);
|
||||
if (conn != null) {
|
||||
backoff.reset();
|
||||
callback.outgoingConnectionCreated(c, conn);
|
||||
if (connectionManager.connectionOpened()) {
|
||||
callback.outgoingConnectionCreated(c, conn);
|
||||
} else {
|
||||
LOG.info("Closing outgoing connection");
|
||||
tryToCloseUnusedConnection(conn);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -301,12 +329,25 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
@Override
|
||||
public DuplexTransportConnection createConnection(ContactId c) {
|
||||
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
||||
if (!connectionManager.canOpenConnection()) {
|
||||
LOG.info("Not connecting, too many open connections");
|
||||
return null;
|
||||
}
|
||||
TransportProperties p = callback.getRemoteProperties(c);
|
||||
String address = p.get(PROP_ADDRESS);
|
||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||
String uuid = p.get(PROP_UUID);
|
||||
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
||||
return connect(address, uuid);
|
||||
DuplexTransportConnection conn = connect(address, uuid);
|
||||
if (conn == null) return null;
|
||||
// TODO: Why don't we reset the backoff here?
|
||||
if (connectionManager.connectionOpened()) {
|
||||
return conn;
|
||||
} else {
|
||||
LOG.info("Closing outgoing connection");
|
||||
tryToCloseUnusedConnection(conn);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -356,7 +397,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info("Connecting to key agreement UUID " + uuid);
|
||||
return connect(address, uuid);
|
||||
DuplexTransportConnection conn = connect(address, uuid);
|
||||
// The connection limit doesn't apply to key agreement
|
||||
if (conn != null) connectionManager.connectionOpened();
|
||||
return conn;
|
||||
}
|
||||
|
||||
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||
@@ -411,6 +455,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
||||
DuplexTransportConnection conn = acceptConnection(ss);
|
||||
if (LOG.isLoggable(INFO))
|
||||
LOG.info(ID.getString() + ": Incoming connection");
|
||||
// The connection limit doesn't apply to key agreement
|
||||
connectionManager.connectionOpened();
|
||||
return new KeyAgreementConnection(conn, ID);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,9 +31,11 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
||||
// Non-null if the plugin started successfully
|
||||
private volatile LocalDevice localDevice = null;
|
||||
|
||||
JavaBluetoothPlugin(Executor ioExecutor, SecureRandom secureRandom,
|
||||
JavaBluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||
Executor ioExecutor, SecureRandom secureRandom,
|
||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||
super(ioExecutor, secureRandom, backoff, callback, maxLatency);
|
||||
super(connectionManager, ioExecutor, secureRandom, backoff, callback,
|
||||
maxLatency);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,6 +112,6 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
||||
}
|
||||
|
||||
private DuplexTransportConnection wrapSocket(StreamConnection s) {
|
||||
return new JavaBluetoothTransportConnection(this, s);
|
||||
return new JavaBluetoothTransportConnection(this, connectionManager, s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,10 +51,12 @@ public class JavaBluetoothPluginFactory implements DuplexPluginFactory {
|
||||
|
||||
@Override
|
||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||
BluetoothConnectionManager connectionManager =
|
||||
new BluetoothConnectionManagerImpl();
|
||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(ioExecutor,
|
||||
secureRandom, backoff, callback, MAX_LATENCY);
|
||||
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(connectionManager,
|
||||
ioExecutor, secureRandom, backoff, callback, MAX_LATENCY);
|
||||
eventBus.addListener(plugin);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,15 @@ import javax.microedition.io.StreamConnection;
|
||||
class JavaBluetoothTransportConnection
|
||||
extends AbstractDuplexTransportConnection {
|
||||
|
||||
private final BluetoothConnectionManager connectionManager;
|
||||
private final StreamConnection stream;
|
||||
|
||||
JavaBluetoothTransportConnection(Plugin plugin, StreamConnection stream) {
|
||||
JavaBluetoothTransportConnection(Plugin plugin,
|
||||
BluetoothConnectionManager connectionManager,
|
||||
StreamConnection stream) {
|
||||
super(plugin);
|
||||
this.stream = stream;
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,6 +37,10 @@ class JavaBluetoothTransportConnection
|
||||
|
||||
@Override
|
||||
protected void closeConnection(boolean exception) throws IOException {
|
||||
stream.close();
|
||||
try {
|
||||
stream.close();
|
||||
} finally {
|
||||
connectionManager.connectionClosed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user