mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 22:29:53 +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
|
// Non-null if the plugin started successfully
|
||||||
private volatile BluetoothAdapter adapter = null;
|
private volatile BluetoothAdapter adapter = null;
|
||||||
|
|
||||||
AndroidBluetoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor,
|
AndroidBluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||||
|
Executor ioExecutor, AndroidExecutor androidExecutor,
|
||||||
Context appContext, SecureRandom secureRandom, Backoff backoff,
|
Context appContext, SecureRandom secureRandom, Backoff backoff,
|
||||||
DuplexPluginCallback callback, int maxLatency) {
|
DuplexPluginCallback callback, int maxLatency) {
|
||||||
super(ioExecutor, secureRandom, backoff, callback, maxLatency);
|
super(connectionManager, ioExecutor, secureRandom, backoff, callback,
|
||||||
|
maxLatency);
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
}
|
}
|
||||||
@@ -154,7 +156,8 @@ class AndroidBluetoothPlugin extends BluetoothPlugin<BluetoothServerSocket> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
|
private DuplexTransportConnection wrapSocket(BluetoothSocket s) {
|
||||||
return new AndroidBluetoothTransportConnection(this, s);
|
return new AndroidBluetoothTransportConnection(this,
|
||||||
|
connectionManager, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -59,11 +59,13 @@ public class AndroidBluetoothPluginFactory implements DuplexPluginFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
|
BluetoothConnectionManager connectionManager =
|
||||||
|
new BluetoothConnectionManagerImpl();
|
||||||
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(ioExecutor,
|
AndroidBluetoothPlugin plugin = new AndroidBluetoothPlugin(
|
||||||
androidExecutor, appContext, secureRandom, backoff, callback,
|
connectionManager, ioExecutor, androidExecutor, appContext,
|
||||||
MAX_LATENCY);
|
secureRandom, backoff, callback, MAX_LATENCY);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ import java.io.OutputStream;
|
|||||||
class AndroidBluetoothTransportConnection
|
class AndroidBluetoothTransportConnection
|
||||||
extends AbstractDuplexTransportConnection {
|
extends AbstractDuplexTransportConnection {
|
||||||
|
|
||||||
|
private final BluetoothConnectionManager connectionManager;
|
||||||
private final BluetoothSocket socket;
|
private final BluetoothSocket socket;
|
||||||
|
|
||||||
AndroidBluetoothTransportConnection(Plugin plugin, BluetoothSocket socket) {
|
AndroidBluetoothTransportConnection(Plugin plugin,
|
||||||
|
BluetoothConnectionManager connectionManager,
|
||||||
|
BluetoothSocket socket) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +37,10 @@ class AndroidBluetoothTransportConnection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeConnection(boolean exception) throws IOException {
|
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 =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(BluetoothPlugin.class.getName());
|
Logger.getLogger(BluetoothPlugin.class.getName());
|
||||||
|
|
||||||
|
protected final BluetoothConnectionManager connectionManager;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
@@ -92,8 +94,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
abstract DuplexTransportConnection connectTo(String address, String uuid)
|
abstract DuplexTransportConnection connectTo(String address, String uuid)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
BluetoothPlugin(Executor ioExecutor, SecureRandom secureRandom,
|
BluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||||
|
Executor ioExecutor, SecureRandom secureRandom,
|
||||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
@@ -111,6 +115,7 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
void onAdapterDisabled() {
|
void onAdapterDisabled() {
|
||||||
LOG.info("Bluetooth disabled");
|
LOG.info("Bluetooth disabled");
|
||||||
tryToClose(socket);
|
tryToClose(socket);
|
||||||
|
connectionManager.allConnectionsClosed();
|
||||||
callback.transportDisabled();
|
callback.transportDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,11 +219,25 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
callback.incomingConnectionCreated(conn);
|
if (connectionManager.connectionOpened()) {
|
||||||
|
callback.incomingConnectionCreated(conn);
|
||||||
|
} else {
|
||||||
|
LOG.info("Closing incoming connection");
|
||||||
|
tryToCloseUnusedConnection(conn);
|
||||||
|
}
|
||||||
if (!running) return;
|
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
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
running = false;
|
running = false;
|
||||||
@@ -258,10 +277,19 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
if (StringUtils.isNullOrEmpty(uuid)) continue;
|
||||||
ioExecutor.execute(() -> {
|
ioExecutor.execute(() -> {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return;
|
if (!isRunning() || !shouldAllowContactConnections()) return;
|
||||||
|
if (!connectionManager.canOpenConnection()) {
|
||||||
|
LOG.info("Not connecting, too many open connections");
|
||||||
|
return;
|
||||||
|
}
|
||||||
DuplexTransportConnection conn = connect(address, uuid);
|
DuplexTransportConnection conn = connect(address, uuid);
|
||||||
if (conn != null) {
|
if (conn != null) {
|
||||||
backoff.reset();
|
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
|
@Override
|
||||||
public DuplexTransportConnection createConnection(ContactId c) {
|
public DuplexTransportConnection createConnection(ContactId c) {
|
||||||
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
if (!isRunning() || !shouldAllowContactConnections()) return null;
|
||||||
|
if (!connectionManager.canOpenConnection()) {
|
||||||
|
LOG.info("Not connecting, too many open connections");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
TransportProperties p = callback.getRemoteProperties(c);
|
TransportProperties p = callback.getRemoteProperties(c);
|
||||||
String address = p.get(PROP_ADDRESS);
|
String address = p.get(PROP_ADDRESS);
|
||||||
if (StringUtils.isNullOrEmpty(address)) return null;
|
if (StringUtils.isNullOrEmpty(address)) return null;
|
||||||
String uuid = p.get(PROP_UUID);
|
String uuid = p.get(PROP_UUID);
|
||||||
if (StringUtils.isNullOrEmpty(uuid)) return null;
|
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
|
@Override
|
||||||
@@ -356,7 +397,10 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
String uuid = UUID.nameUUIDFromBytes(commitment).toString();
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connecting to key agreement UUID " + uuid);
|
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 {
|
private String parseAddress(BdfList descriptor) throws FormatException {
|
||||||
@@ -411,6 +455,8 @@ abstract class BluetoothPlugin<SS> implements DuplexPlugin, EventListener {
|
|||||||
DuplexTransportConnection conn = acceptConnection(ss);
|
DuplexTransportConnection conn = acceptConnection(ss);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(ID.getString() + ": Incoming connection");
|
LOG.info(ID.getString() + ": Incoming connection");
|
||||||
|
// The connection limit doesn't apply to key agreement
|
||||||
|
connectionManager.connectionOpened();
|
||||||
return new KeyAgreementConnection(conn, ID);
|
return new KeyAgreementConnection(conn, ID);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,9 +31,11 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
|||||||
// Non-null if the plugin started successfully
|
// Non-null if the plugin started successfully
|
||||||
private volatile LocalDevice localDevice = null;
|
private volatile LocalDevice localDevice = null;
|
||||||
|
|
||||||
JavaBluetoothPlugin(Executor ioExecutor, SecureRandom secureRandom,
|
JavaBluetoothPlugin(BluetoothConnectionManager connectionManager,
|
||||||
|
Executor ioExecutor, SecureRandom secureRandom,
|
||||||
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||||
super(ioExecutor, secureRandom, backoff, callback, maxLatency);
|
super(connectionManager, ioExecutor, secureRandom, backoff, callback,
|
||||||
|
maxLatency);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -110,6 +112,6 @@ class JavaBluetoothPlugin extends BluetoothPlugin<StreamConnectionNotifier> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DuplexTransportConnection wrapSocket(StreamConnection s) {
|
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
|
@Override
|
||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
|
BluetoothConnectionManager connectionManager =
|
||||||
|
new BluetoothConnectionManagerImpl();
|
||||||
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(ioExecutor,
|
JavaBluetoothPlugin plugin = new JavaBluetoothPlugin(connectionManager,
|
||||||
secureRandom, backoff, callback, MAX_LATENCY);
|
ioExecutor, secureRandom, backoff, callback, MAX_LATENCY);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,15 @@ import javax.microedition.io.StreamConnection;
|
|||||||
class JavaBluetoothTransportConnection
|
class JavaBluetoothTransportConnection
|
||||||
extends AbstractDuplexTransportConnection {
|
extends AbstractDuplexTransportConnection {
|
||||||
|
|
||||||
|
private final BluetoothConnectionManager connectionManager;
|
||||||
private final StreamConnection stream;
|
private final StreamConnection stream;
|
||||||
|
|
||||||
JavaBluetoothTransportConnection(Plugin plugin, StreamConnection stream) {
|
JavaBluetoothTransportConnection(Plugin plugin,
|
||||||
|
BluetoothConnectionManager connectionManager,
|
||||||
|
StreamConnection stream) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -33,6 +37,10 @@ class JavaBluetoothTransportConnection
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeConnection(boolean exception) throws IOException {
|
protected void closeConnection(boolean exception) throws IOException {
|
||||||
stream.close();
|
try {
|
||||||
|
stream.close();
|
||||||
|
} finally {
|
||||||
|
connectionManager.connectionClosed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user