mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 04:18:53 +01:00
Limit the number of open Bluetooth connections.
This commit is contained in:
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user