Ensure that Plugin instances aren't reused.

This commit is contained in:
akwizgran
2016-05-05 18:05:53 +01:00
parent 69f23ead9b
commit 2ecccc66d1
11 changed files with 153 additions and 35 deletions

View File

@@ -282,8 +282,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
public void showForumPostNotification(final GroupId g) { public void showForumPostNotification(final GroupId g) {
androidExecutor.execute(new Runnable() { androidExecutor.execute(new Runnable() {
@Override @Override
public void public void run() {
run() {
Integer count = forumCounts.get(g); Integer count = forumCounts.get(g);
if (count == null) forumCounts.put(g, 1); if (count == null) forumCounts.put(g, 1);
else forumCounts.put(g, count + 1); else forumCounts.put(g, count + 1);

View File

@@ -9,9 +9,9 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.android.util.AndroidUtils; import org.briarproject.android.util.AndroidUtils;
import org.briarproject.api.TransportId; import org.briarproject.api.TransportId;
import org.briarproject.android.api.AndroidExecutor;
import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactId;
import org.briarproject.api.crypto.PseudoRandom; import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.keyagreement.KeyAgreementConnection; import org.briarproject.api.keyagreement.KeyAgreementConnection;
@@ -41,6 +41,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED; import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
@@ -80,6 +81,7 @@ class DroidtoothPlugin implements DuplexPlugin {
private final Backoff backoff; private final Backoff backoff;
private final DuplexPluginCallback callback; private final DuplexPluginCallback callback;
private final int maxLatency; private final int maxLatency;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false; private volatile boolean running = false;
private volatile boolean wasEnabledByUs = false; private volatile boolean wasEnabledByUs = false;
@@ -101,24 +103,30 @@ class DroidtoothPlugin implements DuplexPlugin {
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
} }
@Override
public TransportId getId() { public TransportId getId() {
return ID; return ID;
} }
@Override
public int getMaxLatency() { public int getMaxLatency() {
return maxLatency; return maxLatency;
} }
@Override
public int getMaxIdleTime() { public int getMaxIdleTime() {
// Bluetooth detects dead connections so we don't need keepalives // Bluetooth detects dead connections so we don't need keepalives
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} }
@Override
public boolean start() throws IOException { public boolean start() throws IOException {
if (used.getAndSet(true)) throw new IllegalStateException();
// BluetoothAdapter.getDefaultAdapter() must be called on a thread // BluetoothAdapter.getDefaultAdapter() must be called on a thread
// with a message queue, so submit it to the AndroidExecutor // with a message queue, so submit it to the AndroidExecutor
try { try {
adapter = androidExecutor.submit(new Callable<BluetoothAdapter>() { adapter = androidExecutor.submit(new Callable<BluetoothAdapter>() {
@Override
public BluetoothAdapter call() throws Exception { public BluetoothAdapter call() throws Exception {
return BluetoothAdapter.getDefaultAdapter(); return BluetoothAdapter.getDefaultAdapter();
} }
@@ -158,6 +166,7 @@ class DroidtoothPlugin implements DuplexPlugin {
private void bind() { private void bind() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
if (!isRunning()) return; if (!isRunning()) return;
String address = AndroidUtils.getBluetoothAddress(appContext, String address = AndroidUtils.getBluetoothAddress(appContext,
@@ -238,6 +247,7 @@ class DroidtoothPlugin implements DuplexPlugin {
return new DroidtoothTransportConnection(this, s); return new DroidtoothTransportConnection(this, s);
} }
@Override
public void stop() { public void stop() {
running = false; running = false;
if (receiver != null) appContext.unregisterReceiver(receiver); if (receiver != null) appContext.unregisterReceiver(receiver);
@@ -249,18 +259,22 @@ class DroidtoothPlugin implements DuplexPlugin {
} }
} }
@Override
public boolean isRunning() { public boolean isRunning() {
return running && adapter.isEnabled(); return running && adapter.isEnabled();
} }
@Override
public boolean shouldPoll() { public boolean shouldPoll() {
return true; return true;
} }
@Override
public int getPollingInterval() { public int getPollingInterval() {
return backoff.getPollingInterval(); return backoff.getPollingInterval();
} }
@Override
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
if (!isRunning()) return; if (!isRunning()) return;
backoff.increment(); backoff.increment();
@@ -275,6 +289,7 @@ class DroidtoothPlugin implements DuplexPlugin {
final String uuid = e.getValue().get(PROP_UUID); final String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue; if (StringUtils.isNullOrEmpty(uuid)) continue;
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
if (!running) return; if (!running) return;
BluetoothSocket s = connect(address, uuid); BluetoothSocket s = connect(address, uuid);
@@ -327,6 +342,7 @@ class DroidtoothPlugin implements DuplexPlugin {
} }
} }
@Override
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null; if (!isRunning()) return null;
TransportProperties p = callback.getRemoteProperties().get(c); TransportProperties p = callback.getRemoteProperties().get(c);
@@ -340,10 +356,12 @@ class DroidtoothPlugin implements DuplexPlugin {
return new DroidtoothTransportConnection(this, s); return new DroidtoothTransportConnection(this, s);
} }
@Override
public boolean supportsInvitations() { public boolean supportsInvitations() {
return true; return true;
} }
@Override
public DuplexTransportConnection createInvitationConnection(PseudoRandom r, public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice) { long timeout, boolean alice) {
if (!isRunning()) return null; if (!isRunning()) return null;
@@ -361,9 +379,8 @@ class DroidtoothPlugin implements DuplexPlugin {
} }
// Create the background tasks // Create the background tasks
CompletionService<BluetoothSocket> complete = CompletionService<BluetoothSocket> complete =
new ExecutorCompletionService<BluetoothSocket>(ioExecutor); new ExecutorCompletionService<>(ioExecutor);
List<Future<BluetoothSocket>> futures = List<Future<BluetoothSocket>> futures = new ArrayList<>();
new ArrayList<Future<BluetoothSocket>>();
if (alice) { if (alice) {
// Return the first connected socket // Return the first connected socket
futures.add(complete.submit(new ListeningTask(ss))); futures.add(complete.submit(new ListeningTask(ss)));
@@ -398,6 +415,7 @@ class DroidtoothPlugin implements DuplexPlugin {
private void closeSockets(final List<Future<BluetoothSocket>> futures, private void closeSockets(final List<Future<BluetoothSocket>> futures,
final BluetoothSocket chosen) { final BluetoothSocket chosen) {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
for (Future<BluetoothSocket> f : futures) { for (Future<BluetoothSocket> f : futures) {
try { try {
@@ -413,9 +431,7 @@ class DroidtoothPlugin implements DuplexPlugin {
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.info("Interrupted while closing sockets"); LOG.info("Interrupted while closing sockets");
return; return;
} catch (ExecutionException e) { } catch (ExecutionException | IOException e) {
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
} catch (IOException e) {
if (LOG.isLoggable(INFO)) LOG.info(e.toString()); if (LOG.isLoggable(INFO)) LOG.info(e.toString());
} }
} }
@@ -423,14 +439,15 @@ class DroidtoothPlugin implements DuplexPlugin {
}); });
} }
@Override
public boolean supportsKeyAgreement() { public boolean supportsKeyAgreement() {
return true; return true;
} }
public KeyAgreementListener createKeyAgreementListener( @Override
byte[] localCommitment) { public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
// No truncation necessary because COMMIT_LENGTH = 16 // No truncation necessary because COMMIT_LENGTH = 16
UUID uuid = UUID.nameUUIDFromBytes(localCommitment); UUID uuid = UUID.nameUUIDFromBytes(commitment);
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid); if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
// Bind a server socket for receiving invitation connections // Bind a server socket for receiving invitation connections
BluetoothServerSocket ss; BluetoothServerSocket ss;
@@ -448,8 +465,9 @@ class DroidtoothPlugin implements DuplexPlugin {
return new BluetoothKeyAgreementListener(d, ss); return new BluetoothKeyAgreementListener(d, ss);
} }
@Override
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] remoteCommitment, TransportDescriptor d, long timeout) { byte[] commitment, TransportDescriptor d, long timeout) {
if (!isRunning()) return null; if (!isRunning()) return null;
if (!ID.equals(d.getIdentifier())) return null; if (!ID.equals(d.getIdentifier())) return null;
TransportProperties p = d.getProperties(); TransportProperties p = d.getProperties();
@@ -457,7 +475,7 @@ class DroidtoothPlugin implements DuplexPlugin {
String address = p.get(PROP_ADDRESS); String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) return null; if (StringUtils.isNullOrEmpty(address)) return null;
// No truncation necessary because COMMIT_LENGTH = 16 // No truncation necessary because COMMIT_LENGTH = 16
UUID uuid = UUID.nameUUIDFromBytes(remoteCommitment); UUID uuid = UUID.nameUUIDFromBytes(commitment);
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Connecting to key agreement UUID " + uuid); LOG.info("Connecting to key agreement UUID " + uuid);
BluetoothSocket s = connect(address, uuid.toString()); BluetoothSocket s = connect(address, uuid.toString());
@@ -533,7 +551,7 @@ class DroidtoothPlugin implements DuplexPlugin {
private static class DiscoveryReceiver extends BroadcastReceiver { private static class DiscoveryReceiver extends BroadcastReceiver {
private final CountDownLatch finished = new CountDownLatch(1); private final CountDownLatch finished = new CountDownLatch(1);
private final List<String> addresses = new ArrayList<String>(); private final List<String> addresses = new ArrayList<>();
@Override @Override
public void onReceive(Context ctx, Intent intent) { public void onReceive(Context ctx, Intent intent) {

View File

@@ -35,6 +35,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
@Override @Override
public boolean start() { public boolean start() {
if (used.getAndSet(true)) throw new IllegalStateException();
running = true; running = true;
// Register to receive network status events // Register to receive network status events
networkStateReceiver = new NetworkStateReceiver(); networkStateReceiver = new NetworkStateReceiver();

View File

@@ -51,6 +51,7 @@ import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@@ -94,6 +95,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private final File torDirectory, torFile, geoIpFile, configFile; private final File torDirectory, torFile, geoIpFile, configFile;
private final File doneFile, cookieFile; private final File doneFile, cookieFile;
private final PowerManager.WakeLock wakeLock; private final PowerManager.WakeLock wakeLock;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false; private volatile boolean running = false;
private volatile ServerSocket socket = null; private volatile ServerSocket socket = null;
@@ -130,19 +132,24 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
wakeLock.setReferenceCounted(false); wakeLock.setReferenceCounted(false);
} }
@Override
public TransportId getId() { public TransportId getId() {
return ID; return ID;
} }
@Override
public int getMaxLatency() { public int getMaxLatency() {
return maxLatency; return maxLatency;
} }
@Override
public int getMaxIdleTime() { public int getMaxIdleTime() {
return maxIdleTime; return maxIdleTime;
} }
@Override
public boolean start() throws IOException { public boolean start() throws IOException {
if (used.getAndSet(true)) throw new IllegalStateException();
// Try to connect to an existing Tor process if there is one // Try to connect to an existing Tor process if there is one
boolean startProcess = false; boolean startProcess = false;
try { try {
@@ -369,6 +376,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void bind() { private void bind() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
// If there's already a port number stored in config, reuse it // If there's already a port number stored in config, reuse it
String portString = callback.getSettings().get("port"); String portString = callback.getSettings().get("port");
@@ -398,6 +406,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
callback.mergeSettings(s); callback.mergeSettings(s);
// Create a hidden service if necessary // Create a hidden service if necessary
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
publishHiddenService(localPort); publishHiddenService(localPort);
} }
@@ -486,6 +495,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
@Override
public void stop() throws IOException { public void stop() throws IOException {
running = false; running = false;
tryToClose(socket); tryToClose(socket);
@@ -508,18 +518,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
wakeLock.release(); wakeLock.release();
} }
@Override
public boolean isRunning() { public boolean isRunning() {
return running && connectionStatus.isConnected(); return running && connectionStatus.isConnected();
} }
@Override
public boolean shouldPoll() { public boolean shouldPoll() {
return true; return true;
} }
@Override
public int getPollingInterval() { public int getPollingInterval() {
return backoff.getPollingInterval(); return backoff.getPollingInterval();
} }
@Override
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
if (!isRunning()) return; if (!isRunning()) return;
backoff.increment(); backoff.increment();
@@ -530,6 +544,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void connectAndCallBack(final ContactId c) { private void connectAndCallBack(final ContactId c) {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
DuplexTransportConnection d = createConnection(c); DuplexTransportConnection d = createConnection(c);
if (d != null) { if (d != null) {
@@ -540,6 +555,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
}); });
} }
@Override
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null; if (!isRunning()) return null;
TransportProperties p = callback.getRemoteProperties().get(c); TransportProperties p = callback.getRemoteProperties().get(c);
@@ -566,29 +582,34 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
@Override
public boolean supportsInvitations() { public boolean supportsInvitations() {
return false; return false;
} }
@Override
public DuplexTransportConnection createInvitationConnection(PseudoRandom r, public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice) { long timeout, boolean alice) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean supportsKeyAgreement() { public boolean supportsKeyAgreement() {
return false; return false;
} }
public KeyAgreementListener createKeyAgreementListener( @Override
byte[] commitment) { public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, TransportDescriptor d, long timeout) { byte[] commitment, TransportDescriptor d, long timeout) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void circuitStatus(String status, String id, String path) { public void circuitStatus(String status, String id, String path) {
if (status.equals("BUILT") && if (status.equals("BUILT") &&
connectionStatus.getAndSetCircuitBuilt()) { connectionStatus.getAndSetCircuitBuilt()) {
@@ -598,19 +619,24 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
@Override
public void streamStatus(String status, String id, String target) { public void streamStatus(String status, String id, String target) {
} }
@Override
public void orConnStatus(String status, String orName) { public void orConnStatus(String status, String orName) {
if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status); if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
} }
@Override
public void bandwidthUsed(long read, long written) { public void bandwidthUsed(long read, long written) {
} }
@Override
public void newDescriptors(List<String> orList) { public void newDescriptors(List<String> orList) {
} }
@Override
public void message(String severity, String msg) { public void message(String severity, String msg) {
if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg); if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) { if (severity.equals("NOTICE") && msg.startsWith("Bootstrapped 100%")) {
@@ -621,6 +647,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
@Override
public void unrecognized(String type, String msg) { public void unrecognized(String type, String msg) {
if (type.equals("HS_DESC") && msg.startsWith("UPLOADED")) if (type.equals("HS_DESC") && msg.startsWith("UPLOADED"))
LOG.info("Descriptor uploaded"); LOG.info("Descriptor uploaded");
@@ -642,6 +669,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
} }
@Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof SettingsUpdatedEvent) { if (e instanceof SettingsUpdatedEvent) {
if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) { if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) {
@@ -653,6 +681,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
private void updateConnectionStatus() { private void updateConnectionStatus() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
if (!running) return; if (!running) return;

View File

@@ -14,6 +14,7 @@ import java.io.OutputStream;
import java.util.Collection; import java.util.Collection;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
@@ -27,6 +28,7 @@ public abstract class FilePlugin implements SimplexPlugin {
protected final Executor ioExecutor; protected final Executor ioExecutor;
protected final SimplexPluginCallback callback; protected final SimplexPluginCallback callback;
protected final int maxLatency; protected final int maxLatency;
protected final AtomicBoolean used = new AtomicBoolean(false);
protected volatile boolean running = false; protected volatile boolean running = false;
@@ -42,22 +44,27 @@ public abstract class FilePlugin implements SimplexPlugin {
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
} }
@Override
public int getMaxLatency() { public int getMaxLatency() {
return maxLatency; return maxLatency;
} }
@Override
public int getMaxIdleTime() { public int getMaxIdleTime() {
return Integer.MAX_VALUE; // We don't need keepalives return Integer.MAX_VALUE; // We don't need keepalives
} }
@Override
public boolean isRunning() { public boolean isRunning() {
return running; return running;
} }
@Override
public TransportConnectionReader createReader(ContactId c) { public TransportConnectionReader createReader(ContactId c) {
return null; return null;
} }
@Override
public TransportConnectionWriter createWriter(ContactId c) { public TransportConnectionWriter createWriter(ContactId c) {
if (!running) return null; if (!running) return null;
return createWriter(createConnectionFilename()); return createWriter(createConnectionFilename());
@@ -105,6 +112,7 @@ public abstract class FilePlugin implements SimplexPlugin {
this.file = file; this.file = file;
} }
@Override
public void run() { public void run() {
if (isPossibleConnectionFilename(file.getName())) { if (isPossibleConnectionFilename(file.getName())) {
try { try {

View File

@@ -22,6 +22,7 @@ class LanTcpPlugin extends TcpPlugin {
super(ioExecutor, backoff, callback, maxLatency, maxIdleTime); super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
} }
@Override
public TransportId getId() { public TransportId getId() {
return ID; return ID;
} }

View File

@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -42,6 +43,7 @@ abstract class TcpPlugin implements DuplexPlugin {
protected final Backoff backoff; protected final Backoff backoff;
protected final DuplexPluginCallback callback; protected final DuplexPluginCallback callback;
protected final int maxLatency, maxIdleTime, socketTimeout; protected final int maxLatency, maxIdleTime, socketTimeout;
protected final AtomicBoolean used = new AtomicBoolean(false);
protected volatile boolean running = false; protected volatile boolean running = false;
protected volatile ServerSocket socket = null; protected volatile ServerSocket socket = null;
@@ -67,15 +69,19 @@ abstract class TcpPlugin implements DuplexPlugin {
else socketTimeout = maxIdleTime * 2; else socketTimeout = maxIdleTime * 2;
} }
@Override
public int getMaxLatency() { public int getMaxLatency() {
return maxLatency; return maxLatency;
} }
@Override
public int getMaxIdleTime() { public int getMaxIdleTime() {
return maxIdleTime; return maxIdleTime;
} }
@Override
public boolean start() { public boolean start() {
if (used.getAndSet(true)) throw new IllegalStateException();
running = true; running = true;
bind(); bind();
return true; return true;
@@ -83,6 +89,7 @@ abstract class TcpPlugin implements DuplexPlugin {
protected void bind() { protected void bind() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
if (!running) return; if (!running) return;
ServerSocket ss = null; ServerSocket ss = null;
@@ -158,23 +165,28 @@ abstract class TcpPlugin implements DuplexPlugin {
} }
} }
@Override
public void stop() { public void stop() {
running = false; running = false;
tryToClose(socket); tryToClose(socket);
} }
@Override
public boolean isRunning() { public boolean isRunning() {
return running && socket != null && !socket.isClosed(); return running && socket != null && !socket.isClosed();
} }
@Override
public boolean shouldPoll() { public boolean shouldPoll() {
return true; return true;
} }
@Override
public int getPollingInterval() { public int getPollingInterval() {
return backoff.getPollingInterval(); return backoff.getPollingInterval();
} }
@Override
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
if (!isRunning()) return; if (!isRunning()) return;
backoff.increment(); backoff.increment();
@@ -185,6 +197,7 @@ abstract class TcpPlugin implements DuplexPlugin {
private void connectAndCallBack(final ContactId c) { private void connectAndCallBack(final ContactId c) {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
DuplexTransportConnection d = createConnection(c); DuplexTransportConnection d = createConnection(c);
if (d != null) { if (d != null) {
@@ -195,6 +208,7 @@ abstract class TcpPlugin implements DuplexPlugin {
}); });
} }
@Override
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if (!isRunning()) return null; if (!isRunning()) return null;
InetSocketAddress remote = getRemoteSocketAddress(c); InetSocketAddress remote = getRemoteSocketAddress(c);
@@ -243,24 +257,28 @@ abstract class TcpPlugin implements DuplexPlugin {
} }
} }
@Override
public boolean supportsInvitations() { public boolean supportsInvitations() {
return false; return false;
} }
@Override
public DuplexTransportConnection createInvitationConnection(PseudoRandom r, public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice) { long timeout, boolean alice) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean supportsKeyAgreement() { public boolean supportsKeyAgreement() {
return false; return false;
} }
public KeyAgreementListener createKeyAgreementListener( @Override
byte[] commitment) { public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, TransportDescriptor d, long timeout) { byte[] commitment, TransportDescriptor d, long timeout) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

View File

@@ -27,6 +27,7 @@ class WanTcpPlugin extends TcpPlugin {
this.portMapper = portMapper; this.portMapper = portMapper;
} }
@Override
public TransportId getId() { public TransportId getId() {
return ID; return ID;
} }

View File

@@ -30,6 +30,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.bluetooth.BluetoothStateException; import javax.bluetooth.BluetoothStateException;
@@ -62,6 +63,7 @@ class BluetoothPlugin implements DuplexPlugin {
private final DuplexPluginCallback callback; private final DuplexPluginCallback callback;
private final int maxLatency; private final int maxLatency;
private final Semaphore discoverySemaphore = new Semaphore(1); private final Semaphore discoverySemaphore = new Semaphore(1);
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false; private volatile boolean running = false;
private volatile StreamConnectionNotifier socket = null; private volatile StreamConnectionNotifier socket = null;
@@ -76,20 +78,25 @@ class BluetoothPlugin implements DuplexPlugin {
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
} }
@Override
public TransportId getId() { public TransportId getId() {
return ID; return ID;
} }
@Override
public int getMaxLatency() { public int getMaxLatency() {
return maxLatency; return maxLatency;
} }
@Override
public int getMaxIdleTime() { public int getMaxIdleTime() {
// Bluetooth detects dead connections so we don't need keepalives // Bluetooth detects dead connections so we don't need keepalives
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} }
@Override
public boolean start() throws IOException { public boolean start() throws IOException {
if (used.getAndSet(true)) throw new IllegalStateException();
// Initialise the Bluetooth stack // Initialise the Bluetooth stack
try { try {
localDevice = LocalDevice.getLocalDevice(); localDevice = LocalDevice.getLocalDevice();
@@ -108,6 +115,7 @@ class BluetoothPlugin implements DuplexPlugin {
private void bind() { private void bind() {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
if (!running) return; if (!running) return;
// Advertise the Bluetooth address to contacts // Advertise the Bluetooth address to contacts
@@ -183,23 +191,28 @@ class BluetoothPlugin implements DuplexPlugin {
return new BluetoothTransportConnection(this, s); return new BluetoothTransportConnection(this, s);
} }
@Override
public void stop() { public void stop() {
running = false; running = false;
tryToClose(socket); tryToClose(socket);
} }
@Override
public boolean isRunning() { public boolean isRunning() {
return running; return running;
} }
@Override
public boolean shouldPoll() { public boolean shouldPoll() {
return true; return true;
} }
@Override
public int getPollingInterval() { public int getPollingInterval() {
return backoff.getPollingInterval(); return backoff.getPollingInterval();
} }
@Override
public void poll(final Collection<ContactId> connected) { public void poll(final Collection<ContactId> connected) {
if (!running) return; if (!running) return;
backoff.increment(); backoff.increment();
@@ -214,6 +227,7 @@ class BluetoothPlugin implements DuplexPlugin {
final String uuid = e.getValue().get(PROP_UUID); final String uuid = e.getValue().get(PROP_UUID);
if (StringUtils.isNullOrEmpty(uuid)) continue; if (StringUtils.isNullOrEmpty(uuid)) continue;
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
if (!running) return; if (!running) return;
StreamConnection s = connect(makeUrl(address, uuid)); StreamConnection s = connect(makeUrl(address, uuid));
@@ -238,6 +252,7 @@ class BluetoothPlugin implements DuplexPlugin {
} }
} }
@Override
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if (!running) return null; if (!running) return null;
TransportProperties p = callback.getRemoteProperties().get(c); TransportProperties p = callback.getRemoteProperties().get(c);
@@ -252,10 +267,12 @@ class BluetoothPlugin implements DuplexPlugin {
return new BluetoothTransportConnection(this, s); return new BluetoothTransportConnection(this, s);
} }
@Override
public boolean supportsInvitations() { public boolean supportsInvitations() {
return true; return true;
} }
@Override
public DuplexTransportConnection createInvitationConnection(PseudoRandom r, public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice) { long timeout, boolean alice) {
if (!running) return null; if (!running) return null;
@@ -279,9 +296,8 @@ class BluetoothPlugin implements DuplexPlugin {
} }
// Create the background tasks // Create the background tasks
CompletionService<StreamConnection> complete = CompletionService<StreamConnection> complete =
new ExecutorCompletionService<StreamConnection>(ioExecutor); new ExecutorCompletionService<>(ioExecutor);
List<Future<StreamConnection>> futures = List<Future<StreamConnection>> futures = new ArrayList<>();
new ArrayList<Future<StreamConnection>>();
if (alice) { if (alice) {
// Return the first connected socket // Return the first connected socket
futures.add(complete.submit(new ListeningTask(ss))); futures.add(complete.submit(new ListeningTask(ss)));
@@ -316,6 +332,7 @@ class BluetoothPlugin implements DuplexPlugin {
private void closeSockets(final List<Future<StreamConnection>> futures, private void closeSockets(final List<Future<StreamConnection>> futures,
final StreamConnection chosen) { final StreamConnection chosen) {
ioExecutor.execute(new Runnable() { ioExecutor.execute(new Runnable() {
@Override
public void run() { public void run() {
for (Future<StreamConnection> f : futures) { for (Future<StreamConnection> f : futures) {
try { try {
@@ -331,9 +348,7 @@ class BluetoothPlugin implements DuplexPlugin {
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.info("Interrupted while closing sockets"); LOG.info("Interrupted while closing sockets");
return; return;
} catch (ExecutionException e) { } catch (ExecutionException | IOException e) {
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
} catch (IOException e) {
if (LOG.isLoggable(INFO)) LOG.info(e.toString()); if (LOG.isLoggable(INFO)) LOG.info(e.toString());
} }
} }
@@ -341,14 +356,15 @@ class BluetoothPlugin implements DuplexPlugin {
}); });
} }
@Override
public boolean supportsKeyAgreement() { public boolean supportsKeyAgreement() {
return true; return true;
} }
public KeyAgreementListener createKeyAgreementListener( @Override
byte[] localCommitment) { public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
// No truncation necessary because COMMIT_LENGTH = 16 // No truncation necessary because COMMIT_LENGTH = 16
String uuid = UUID.nameUUIDFromBytes(localCommitment).toString(); String uuid = UUID.nameUUIDFromBytes(commitment).toString();
if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid); if (LOG.isLoggable(INFO)) LOG.info("Key agreement UUID " + uuid);
String url = makeUrl("localhost", uuid); String url = makeUrl("localhost", uuid);
// Make the device discoverable if possible // Make the device discoverable if possible
@@ -371,8 +387,9 @@ class BluetoothPlugin implements DuplexPlugin {
return new BluetoothKeyAgreementListener(d, ss); return new BluetoothKeyAgreementListener(d, ss);
} }
@Override
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] remoteCommitment, TransportDescriptor d, long timeout) { byte[] commitment, TransportDescriptor d, long timeout) {
if (!isRunning()) return null; if (!isRunning()) return null;
if (!ID.equals(d.getIdentifier())) return null; if (!ID.equals(d.getIdentifier())) return null;
TransportProperties p = d.getProperties(); TransportProperties p = d.getProperties();
@@ -380,7 +397,7 @@ class BluetoothPlugin implements DuplexPlugin {
String address = p.get(PROP_ADDRESS); String address = p.get(PROP_ADDRESS);
if (StringUtils.isNullOrEmpty(address)) return null; if (StringUtils.isNullOrEmpty(address)) return null;
// No truncation necessary because COMMIT_LENGTH = 16 // No truncation necessary because COMMIT_LENGTH = 16
String uuid = UUID.nameUUIDFromBytes(remoteCommitment).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);
String url = makeUrl(address, uuid); String url = makeUrl(address, uuid);

View File

@@ -34,29 +34,36 @@ implements RemovableDriveMonitor.Callback {
this.monitor = monitor; this.monitor = monitor;
} }
@Override
public TransportId getId() { public TransportId getId() {
return ID; return ID;
} }
@Override
public boolean start() throws IOException { public boolean start() throws IOException {
if (used.getAndSet(true)) throw new IllegalStateException();
running = true; running = true;
monitor.start(this); monitor.start(this);
return true; return true;
} }
@Override
public void stop() throws IOException { public void stop() throws IOException {
running = false; running = false;
monitor.stop(); monitor.stop();
} }
@Override
public boolean shouldPoll() { public boolean shouldPoll() {
return false; return false;
} }
@Override
public int getPollingInterval() { public int getPollingInterval() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -64,8 +71,7 @@ implements RemovableDriveMonitor.Callback {
@Override @Override
protected File chooseOutputDirectory() { protected File chooseOutputDirectory() {
try { try {
List<File> drives = List<File> drives = new ArrayList<>(finder.findRemovableDrives());
new ArrayList<File>(finder.findRemovableDrives());
if (drives.isEmpty()) return null; if (drives.isEmpty()) return null;
String[] paths = new String[drives.size()]; String[] paths = new String[drives.size()];
for (int i = 0; i < paths.length; i++) { for (int i = 0; i < paths.length; i++) {
@@ -92,7 +98,7 @@ implements RemovableDriveMonitor.Callback {
@Override @Override
protected Collection<File> findFilesByName(String filename) { protected Collection<File> findFilesByName(String filename) {
List<File> matches = new ArrayList<File>(); List<File> matches = new ArrayList<>();
try { try {
for (File drive : finder.findRemovableDrives()) { for (File drive : finder.findRemovableDrives()) {
File[] files = drive.listFiles(); File[] files = drive.listFiles();
@@ -109,6 +115,7 @@ implements RemovableDriveMonitor.Callback {
return Collections.unmodifiableList(matches); return Collections.unmodifiableList(matches);
} }
@Override
public void driveInserted(File root) { public void driveInserted(File root) {
File[] files = root.listFiles(); File[] files = root.listFiles();
if (files != null) { if (files != null) {
@@ -116,6 +123,7 @@ implements RemovableDriveMonitor.Callback {
} }
} }
@Override
public void exceptionThrown(IOException e) { public void exceptionThrown(IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }

View File

@@ -16,6 +16,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
@@ -32,6 +33,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
private final SerialPortList serialPortList; private final SerialPortList serialPortList;
private final DuplexPluginCallback callback; private final DuplexPluginCallback callback;
private final int maxLatency; private final int maxLatency;
private final AtomicBoolean used = new AtomicBoolean(false);
private volatile boolean running = false; private volatile boolean running = false;
private volatile Modem modem = null; private volatile Modem modem = null;
@@ -44,20 +46,25 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
this.maxLatency = maxLatency; this.maxLatency = maxLatency;
} }
@Override
public TransportId getId() { public TransportId getId() {
return ID; return ID;
} }
@Override
public int getMaxLatency() { public int getMaxLatency() {
return maxLatency; return maxLatency;
} }
@Override
public int getMaxIdleTime() { public int getMaxIdleTime() {
// FIXME: Do we need keepalives for this transport? // FIXME: Do we need keepalives for this transport?
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} }
@Override
public boolean start() { public boolean start() {
if (used.getAndSet(true)) throw new IllegalStateException();
for (String portName : serialPortList.getPortNames()) { for (String portName : serialPortList.getPortNames()) {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Trying to initialise modem on " + portName); LOG.info("Trying to initialise modem on " + portName);
@@ -75,6 +82,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
return false; return false;
} }
@Override
public void stop() { public void stop() {
running = false; running = false;
if (modem != null) { if (modem != null) {
@@ -86,18 +94,22 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
} }
} }
@Override
public boolean isRunning() { public boolean isRunning() {
return running; return running;
} }
@Override
public boolean shouldPoll() { public boolean shouldPoll() {
return false; return false;
} }
@Override
public int getPollingInterval() { public int getPollingInterval() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void poll(Collection<ContactId> connected) { public void poll(Collection<ContactId> connected) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -121,6 +133,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
return false; return false;
} }
@Override
public DuplexTransportConnection createConnection(ContactId c) { public DuplexTransportConnection createConnection(ContactId c) {
if (!running) return null; if (!running) return null;
// Get the ISO 3166 code for the caller's country // Get the ISO 3166 code for the caller's country
@@ -148,29 +161,34 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
return new ModemTransportConnection(); return new ModemTransportConnection();
} }
@Override
public boolean supportsInvitations() { public boolean supportsInvitations() {
return false; return false;
} }
@Override
public DuplexTransportConnection createInvitationConnection(PseudoRandom r, public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
long timeout, boolean alice) { long timeout, boolean alice) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public boolean supportsKeyAgreement() { public boolean supportsKeyAgreement() {
return false; return false;
} }
public KeyAgreementListener createKeyAgreementListener( @Override
byte[] commitment) { public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, TransportDescriptor d, long timeout) { byte[] commitment, TransportDescriptor d, long timeout) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public void incomingCallConnected() { public void incomingCallConnected() {
LOG.info("Incoming call connected"); LOG.info("Incoming call connected");
callback.incomingConnectionCreated(new ModemTransportConnection()); callback.incomingConnectionCreated(new ModemTransportConnection());