From 2ecccc66d10de7003d6bbeddef6faa9120fd156b Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Thu, 5 May 2016 18:05:53 +0100
Subject: [PATCH] Ensure that Plugin instances aren't reused.

---
 .../AndroidNotificationManagerImpl.java       |  3 +-
 .../plugins/droidtooth/DroidtoothPlugin.java  | 44 +++++++++++++------
 .../plugins/tcp/AndroidLanTcpPlugin.java      |  1 +
 .../briarproject/plugins/tor/TorPlugin.java   | 33 +++++++++++++-
 .../briarproject/plugins/file/FilePlugin.java |  8 ++++
 .../plugins/tcp/LanTcpPlugin.java             |  1 +
 .../briarproject/plugins/tcp/TcpPlugin.java   | 22 +++++++++-
 .../plugins/tcp/WanTcpPlugin.java             |  1 +
 .../plugins/bluetooth/BluetoothPlugin.java    | 39 +++++++++++-----
 .../plugins/file/RemovableDrivePlugin.java    | 14 ++++--
 .../plugins/modem/ModemPlugin.java            | 22 +++++++++-
 11 files changed, 153 insertions(+), 35 deletions(-)

diff --git a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java
index ee487ebc1c..669722b1d5 100644
--- a/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java
+++ b/briar-android/src/org/briarproject/android/AndroidNotificationManagerImpl.java
@@ -282,8 +282,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 	public void showForumPostNotification(final GroupId g) {
 		androidExecutor.execute(new Runnable() {
 			@Override
-			public void
-			run() {
+			public void run() {
 				Integer count = forumCounts.get(g);
 				if (count == null) forumCounts.put(g, 1);
 				else forumCounts.put(g, count + 1);
diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
index 40a8a04106..a89216505b 100644
--- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPlugin.java
@@ -9,9 +9,9 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 
+import org.briarproject.android.api.AndroidExecutor;
 import org.briarproject.android.util.AndroidUtils;
 import org.briarproject.api.TransportId;
-import org.briarproject.android.api.AndroidExecutor;
 import org.briarproject.api.contact.ContactId;
 import org.briarproject.api.crypto.PseudoRandom;
 import org.briarproject.api.keyagreement.KeyAgreementConnection;
@@ -41,6 +41,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorCompletionService;
 import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 
 import static android.bluetooth.BluetoothAdapter.ACTION_SCAN_MODE_CHANGED;
@@ -80,6 +81,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 	private final Backoff backoff;
 	private final DuplexPluginCallback callback;
 	private final int maxLatency;
+	private final AtomicBoolean used = new AtomicBoolean(false);
 
 	private volatile boolean running = false;
 	private volatile boolean wasEnabledByUs = false;
@@ -101,24 +103,30 @@ class DroidtoothPlugin implements DuplexPlugin {
 		this.maxLatency = maxLatency;
 	}
 
+	@Override
 	public TransportId getId() {
 		return ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return maxLatency;
 	}
 
+	@Override
 	public int getMaxIdleTime() {
 		// Bluetooth detects dead connections so we don't need keepalives
 		return Integer.MAX_VALUE;
 	}
 
+	@Override
 	public boolean start() throws IOException {
+		if (used.getAndSet(true)) throw new IllegalStateException();
 		// BluetoothAdapter.getDefaultAdapter() must be called on a thread
 		// with a message queue, so submit it to the AndroidExecutor
 		try {
 			adapter = androidExecutor.submit(new Callable<BluetoothAdapter>() {
+				@Override
 				public BluetoothAdapter call() throws Exception {
 					return BluetoothAdapter.getDefaultAdapter();
 				}
@@ -158,6 +166,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 
 	private void bind() {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				if (!isRunning()) return;
 				String address = AndroidUtils.getBluetoothAddress(appContext,
@@ -238,6 +247,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 		return new DroidtoothTransportConnection(this, s);
 	}
 
+	@Override
 	public void stop() {
 		running = false;
 		if (receiver != null) appContext.unregisterReceiver(receiver);
@@ -249,18 +259,22 @@ class DroidtoothPlugin implements DuplexPlugin {
 		}
 	}
 
+	@Override
 	public boolean isRunning() {
 		return running && adapter.isEnabled();
 	}
 
+	@Override
 	public boolean shouldPoll() {
 		return true;
 	}
 
+	@Override
 	public int getPollingInterval() {
 		return backoff.getPollingInterval();
 	}
 
+	@Override
 	public void poll(Collection<ContactId> connected) {
 		if (!isRunning()) return;
 		backoff.increment();
@@ -275,6 +289,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 			final String uuid = e.getValue().get(PROP_UUID);
 			if (StringUtils.isNullOrEmpty(uuid)) continue;
 			ioExecutor.execute(new Runnable() {
+				@Override
 				public void run() {
 					if (!running) return;
 					BluetoothSocket s = connect(address, uuid);
@@ -327,6 +342,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 		}
 	}
 
+	@Override
 	public DuplexTransportConnection createConnection(ContactId c) {
 		if (!isRunning()) return null;
 		TransportProperties p = callback.getRemoteProperties().get(c);
@@ -340,10 +356,12 @@ class DroidtoothPlugin implements DuplexPlugin {
 		return new DroidtoothTransportConnection(this, s);
 	}
 
+	@Override
 	public boolean supportsInvitations() {
 		return true;
 	}
 
+	@Override
 	public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
 			long timeout, boolean alice) {
 		if (!isRunning()) return null;
@@ -361,9 +379,8 @@ class DroidtoothPlugin implements DuplexPlugin {
 		}
 		// Create the background tasks
 		CompletionService<BluetoothSocket> complete =
-				new ExecutorCompletionService<BluetoothSocket>(ioExecutor);
-		List<Future<BluetoothSocket>> futures =
-				new ArrayList<Future<BluetoothSocket>>();
+				new ExecutorCompletionService<>(ioExecutor);
+		List<Future<BluetoothSocket>> futures = new ArrayList<>();
 		if (alice) {
 			// Return the first connected socket
 			futures.add(complete.submit(new ListeningTask(ss)));
@@ -398,6 +415,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 	private void closeSockets(final List<Future<BluetoothSocket>> futures,
 			final BluetoothSocket chosen) {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				for (Future<BluetoothSocket> f : futures) {
 					try {
@@ -413,9 +431,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 					} catch (InterruptedException e) {
 						LOG.info("Interrupted while closing sockets");
 						return;
-					} catch (ExecutionException e) {
-						if (LOG.isLoggable(INFO)) LOG.info(e.toString());
-					} catch (IOException e) {
+					} catch (ExecutionException | IOException e) {
 						if (LOG.isLoggable(INFO)) LOG.info(e.toString());
 					}
 				}
@@ -423,14 +439,15 @@ class DroidtoothPlugin implements DuplexPlugin {
 		});
 	}
 
+	@Override
 	public boolean supportsKeyAgreement() {
 		return true;
 	}
 
-	public KeyAgreementListener createKeyAgreementListener(
-			byte[] localCommitment) {
+	@Override
+	public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
 		// 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);
 		// Bind a server socket for receiving invitation connections
 		BluetoothServerSocket ss;
@@ -448,8 +465,9 @@ class DroidtoothPlugin implements DuplexPlugin {
 		return new BluetoothKeyAgreementListener(d, ss);
 	}
 
+	@Override
 	public DuplexTransportConnection createKeyAgreementConnection(
-			byte[] remoteCommitment, TransportDescriptor d, long timeout) {
+			byte[] commitment, TransportDescriptor d, long timeout) {
 		if (!isRunning()) return null;
 		if (!ID.equals(d.getIdentifier())) return null;
 		TransportProperties p = d.getProperties();
@@ -457,7 +475,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 		String address = p.get(PROP_ADDRESS);
 		if (StringUtils.isNullOrEmpty(address)) return null;
 		// No truncation necessary because COMMIT_LENGTH = 16
-		UUID uuid = UUID.nameUUIDFromBytes(remoteCommitment);
+		UUID uuid = UUID.nameUUIDFromBytes(commitment);
 		if (LOG.isLoggable(INFO))
 			LOG.info("Connecting to key agreement UUID " + uuid);
 		BluetoothSocket s = connect(address, uuid.toString());
@@ -533,7 +551,7 @@ class DroidtoothPlugin implements DuplexPlugin {
 	private static class DiscoveryReceiver extends BroadcastReceiver {
 
 		private final CountDownLatch finished = new CountDownLatch(1);
-		private final List<String> addresses = new ArrayList<String>();
+		private final List<String> addresses = new ArrayList<>();
 
 		@Override
 		public void onReceive(Context ctx, Intent intent) {
diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java
index e04e2f4fcb..598e914b6d 100644
--- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPlugin.java
@@ -35,6 +35,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
 
 	@Override
 	public boolean start() {
+		if (used.getAndSet(true)) throw new IllegalStateException();
 		running = true;
 		// Register to receive network status events
 		networkStateReceiver = new NetworkStateReceiver();
diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
index 19499171b2..cd460d344b 100644
--- a/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
+++ b/briar-android/src/org/briarproject/plugins/tor/TorPlugin.java
@@ -51,6 +51,7 @@ import java.util.Map;
 import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
 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 doneFile, cookieFile;
 	private final PowerManager.WakeLock wakeLock;
+	private final AtomicBoolean used = new AtomicBoolean(false);
 
 	private volatile boolean running = false;
 	private volatile ServerSocket socket = null;
@@ -130,19 +132,24 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		wakeLock.setReferenceCounted(false);
 	}
 
+	@Override
 	public TransportId getId() {
 		return ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return maxLatency;
 	}
 
+	@Override
 	public int getMaxIdleTime() {
 		return maxIdleTime;
 	}
 
+	@Override
 	public boolean start() throws IOException {
+		if (used.getAndSet(true)) throw new IllegalStateException();
 		// Try to connect to an existing Tor process if there is one
 		boolean startProcess = false;
 		try {
@@ -369,6 +376,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 
 	private void bind() {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				// If there's already a port number stored in config, reuse it
 				String portString = callback.getSettings().get("port");
@@ -398,6 +406,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 				callback.mergeSettings(s);
 				// Create a hidden service if necessary
 				ioExecutor.execute(new Runnable() {
+					@Override
 					public void run() {
 						publishHiddenService(localPort);
 					}
@@ -486,6 +495,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		}
 	}
 
+	@Override
 	public void stop() throws IOException {
 		running = false;
 		tryToClose(socket);
@@ -508,18 +518,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		wakeLock.release();
 	}
 
+	@Override
 	public boolean isRunning() {
 		return running && connectionStatus.isConnected();
 	}
 
+	@Override
 	public boolean shouldPoll() {
 		return true;
 	}
 
+	@Override
 	public int getPollingInterval() {
 		return backoff.getPollingInterval();
 	}
 
+	@Override
 	public void poll(Collection<ContactId> connected) {
 		if (!isRunning()) return;
 		backoff.increment();
@@ -530,6 +544,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 
 	private void connectAndCallBack(final ContactId c) {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				DuplexTransportConnection d = createConnection(c);
 				if (d != null) {
@@ -540,6 +555,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		});
 	}
 
+	@Override
 	public DuplexTransportConnection createConnection(ContactId c) {
 		if (!isRunning()) return null;
 		TransportProperties p = callback.getRemoteProperties().get(c);
@@ -566,29 +582,34 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		}
 	}
 
+	@Override
 	public boolean supportsInvitations() {
 		return false;
 	}
 
+	@Override
 	public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
 			long timeout, boolean alice) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public boolean supportsKeyAgreement() {
 		return false;
 	}
 
-	public KeyAgreementListener createKeyAgreementListener(
-			byte[] commitment) {
+	@Override
+	public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public DuplexTransportConnection createKeyAgreementConnection(
 			byte[] commitment, TransportDescriptor d, long timeout) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public void circuitStatus(String status, String id, String path) {
 		if (status.equals("BUILT") &&
 				connectionStatus.getAndSetCircuitBuilt()) {
@@ -598,19 +619,24 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		}
 	}
 
+	@Override
 	public void streamStatus(String status, String id, String target) {
 	}
 
+	@Override
 	public void orConnStatus(String status, String orName) {
 		if (LOG.isLoggable(INFO)) LOG.info("OR connection " + status);
 	}
 
+	@Override
 	public void bandwidthUsed(long read, long written) {
 	}
 
+	@Override
 	public void newDescriptors(List<String> orList) {
 	}
 
+	@Override
 	public void message(String severity, String msg) {
 		if (LOG.isLoggable(INFO)) LOG.info(severity + " " + msg);
 		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) {
 		if (type.equals("HS_DESC") && msg.startsWith("UPLOADED"))
 			LOG.info("Descriptor uploaded");
@@ -642,6 +669,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 		}
 	}
 
+	@Override
 	public void eventOccurred(Event e) {
 		if (e instanceof SettingsUpdatedEvent) {
 			if (((SettingsUpdatedEvent) e).getNamespace().equals("tor")) {
@@ -653,6 +681,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
 
 	private void updateConnectionStatus() {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				if (!running) return;
 
diff --git a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java
index 3394995cfd..9819235539 100644
--- a/briar-core/src/org/briarproject/plugins/file/FilePlugin.java
+++ b/briar-core/src/org/briarproject/plugins/file/FilePlugin.java
@@ -14,6 +14,7 @@ import java.io.OutputStream;
 import java.util.Collection;
 import java.util.Locale;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 
 import static java.util.logging.Level.WARNING;
@@ -27,6 +28,7 @@ public abstract class FilePlugin implements SimplexPlugin {
 	protected final Executor ioExecutor;
 	protected final SimplexPluginCallback callback;
 	protected final int maxLatency;
+	protected final AtomicBoolean used = new AtomicBoolean(false);
 
 	protected volatile boolean running = false;
 
@@ -42,22 +44,27 @@ public abstract class FilePlugin implements SimplexPlugin {
 		this.maxLatency = maxLatency;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return maxLatency;
 	}
 
+	@Override
 	public int getMaxIdleTime() {
 		return Integer.MAX_VALUE; // We don't need keepalives
 	}
 
+	@Override
 	public boolean isRunning() {
 		return running;
 	}
 
+	@Override
 	public TransportConnectionReader createReader(ContactId c) {
 		return null;
 	}
 
+	@Override
 	public TransportConnectionWriter createWriter(ContactId c) {
 		if (!running) return null;
 		return createWriter(createConnectionFilename());
@@ -105,6 +112,7 @@ public abstract class FilePlugin implements SimplexPlugin {
 			this.file = file;
 		}
 
+		@Override
 		public void run() {
 			if (isPossibleConnectionFilename(file.getName())) {
 				try {
diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java
index 8a75a971e6..f50e967945 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPlugin.java
@@ -22,6 +22,7 @@ class LanTcpPlugin extends TcpPlugin {
 		super(ioExecutor, backoff, callback, maxLatency, maxIdleTime);
 	}
 
+	@Override
 	public TransportId getId() {
 		return ID;
 	}
diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
index d6effe2a72..fa3bd311ab 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/TcpPlugin.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
 
@@ -42,6 +43,7 @@ abstract class TcpPlugin implements DuplexPlugin {
 	protected final Backoff backoff;
 	protected final DuplexPluginCallback callback;
 	protected final int maxLatency, maxIdleTime, socketTimeout;
+	protected final AtomicBoolean used = new AtomicBoolean(false);
 
 	protected volatile boolean running = false;
 	protected volatile ServerSocket socket = null;
@@ -67,15 +69,19 @@ abstract class TcpPlugin implements DuplexPlugin {
 		else socketTimeout = maxIdleTime * 2;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return maxLatency;
 	}
 
+	@Override
 	public int getMaxIdleTime() {
 		return maxIdleTime;
 	}
 
+	@Override
 	public boolean start() {
+		if (used.getAndSet(true)) throw new IllegalStateException();
 		running = true;
 		bind();
 		return true;
@@ -83,6 +89,7 @@ abstract class TcpPlugin implements DuplexPlugin {
 
 	protected void bind() {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				if (!running) return;
 				ServerSocket ss = null;
@@ -158,23 +165,28 @@ abstract class TcpPlugin implements DuplexPlugin {
 		}
 	}
 
+	@Override
 	public void stop() {
 		running = false;
 		tryToClose(socket);
 	}
 
+	@Override
 	public boolean isRunning() {
 		return running && socket != null && !socket.isClosed();
 	}
 
+	@Override
 	public boolean shouldPoll() {
 		return true;
 	}
 
+	@Override
 	public int getPollingInterval() {
 		return backoff.getPollingInterval();
 	}
 
+	@Override
 	public void poll(Collection<ContactId> connected) {
 		if (!isRunning()) return;
 		backoff.increment();
@@ -185,6 +197,7 @@ abstract class TcpPlugin implements DuplexPlugin {
 
 	private void connectAndCallBack(final ContactId c) {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				DuplexTransportConnection d = createConnection(c);
 				if (d != null) {
@@ -195,6 +208,7 @@ abstract class TcpPlugin implements DuplexPlugin {
 		});
 	}
 
+	@Override
 	public DuplexTransportConnection createConnection(ContactId c) {
 		if (!isRunning()) return null;
 		InetSocketAddress remote = getRemoteSocketAddress(c);
@@ -243,24 +257,28 @@ abstract class TcpPlugin implements DuplexPlugin {
 		}
 	}
 
+	@Override
 	public boolean supportsInvitations() {
 		return false;
 	}
 
+	@Override
 	public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
 			long timeout, boolean alice) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public boolean supportsKeyAgreement() {
 		return false;
 	}
 
-	public KeyAgreementListener createKeyAgreementListener(
-			byte[] commitment) {
+	@Override
+	public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public DuplexTransportConnection createKeyAgreementConnection(
 			byte[] commitment, TransportDescriptor d, long timeout) {
 		throw new UnsupportedOperationException();
diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java
index beabc8bec5..cee16ac254 100644
--- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java
+++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPlugin.java
@@ -27,6 +27,7 @@ class WanTcpPlugin extends TcpPlugin {
 		this.portMapper = portMapper;
 	}
 
+	@Override
 	public TransportId getId() {
 		return ID;
 	}
diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
index 875112c5e8..b8a0418c07 100644
--- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
+++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPlugin.java
@@ -30,6 +30,7 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorCompletionService;
 import java.util.concurrent.Future;
 import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 
 import javax.bluetooth.BluetoothStateException;
@@ -62,6 +63,7 @@ class BluetoothPlugin implements DuplexPlugin {
 	private final DuplexPluginCallback callback;
 	private final int maxLatency;
 	private final Semaphore discoverySemaphore = new Semaphore(1);
+	private final AtomicBoolean used = new AtomicBoolean(false);
 
 	private volatile boolean running = false;
 	private volatile StreamConnectionNotifier socket = null;
@@ -76,20 +78,25 @@ class BluetoothPlugin implements DuplexPlugin {
 		this.maxLatency = maxLatency;
 	}
 
+	@Override
 	public TransportId getId() {
 		return ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return maxLatency;
 	}
 
+	@Override
 	public int getMaxIdleTime() {
 		// Bluetooth detects dead connections so we don't need keepalives
 		return Integer.MAX_VALUE;
 	}
 
+	@Override
 	public boolean start() throws IOException {
+		if (used.getAndSet(true)) throw new IllegalStateException();
 		// Initialise the Bluetooth stack
 		try {
 			localDevice = LocalDevice.getLocalDevice();
@@ -108,6 +115,7 @@ class BluetoothPlugin implements DuplexPlugin {
 
 	private void bind() {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				if (!running) return;
 				// Advertise the Bluetooth address to contacts
@@ -183,23 +191,28 @@ class BluetoothPlugin implements DuplexPlugin {
 		return new BluetoothTransportConnection(this, s);
 	}
 
+	@Override
 	public void stop() {
 		running = false;
 		tryToClose(socket);
 	}
 
+	@Override
 	public boolean isRunning() {
 		return running;
 	}
 
+	@Override
 	public boolean shouldPoll() {
 		return true;
 	}
 
+	@Override
 	public int getPollingInterval() {
 		return backoff.getPollingInterval();
 	}
 
+	@Override
 	public void poll(final Collection<ContactId> connected) {
 		if (!running) return;
 		backoff.increment();
@@ -214,6 +227,7 @@ class BluetoothPlugin implements DuplexPlugin {
 			final String uuid = e.getValue().get(PROP_UUID);
 			if (StringUtils.isNullOrEmpty(uuid)) continue;
 			ioExecutor.execute(new Runnable() {
+				@Override
 				public void run() {
 					if (!running) return;
 					StreamConnection s = connect(makeUrl(address, uuid));
@@ -238,6 +252,7 @@ class BluetoothPlugin implements DuplexPlugin {
 		}
 	}
 
+	@Override
 	public DuplexTransportConnection createConnection(ContactId c) {
 		if (!running) return null;
 		TransportProperties p = callback.getRemoteProperties().get(c);
@@ -252,10 +267,12 @@ class BluetoothPlugin implements DuplexPlugin {
 		return new BluetoothTransportConnection(this, s);
 	}
 
+	@Override
 	public boolean supportsInvitations() {
 		return true;
 	}
 
+	@Override
 	public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
 			long timeout, boolean alice) {
 		if (!running) return null;
@@ -279,9 +296,8 @@ class BluetoothPlugin implements DuplexPlugin {
 		}
 		// Create the background tasks
 		CompletionService<StreamConnection> complete =
-				new ExecutorCompletionService<StreamConnection>(ioExecutor);
-		List<Future<StreamConnection>> futures =
-				new ArrayList<Future<StreamConnection>>();
+				new ExecutorCompletionService<>(ioExecutor);
+		List<Future<StreamConnection>> futures = new ArrayList<>();
 		if (alice) {
 			// Return the first connected socket
 			futures.add(complete.submit(new ListeningTask(ss)));
@@ -316,6 +332,7 @@ class BluetoothPlugin implements DuplexPlugin {
 	private void closeSockets(final List<Future<StreamConnection>> futures,
 			final StreamConnection chosen) {
 		ioExecutor.execute(new Runnable() {
+			@Override
 			public void run() {
 				for (Future<StreamConnection> f : futures) {
 					try {
@@ -331,9 +348,7 @@ class BluetoothPlugin implements DuplexPlugin {
 					} catch (InterruptedException e) {
 						LOG.info("Interrupted while closing sockets");
 						return;
-					} catch (ExecutionException e) {
-						if (LOG.isLoggable(INFO)) LOG.info(e.toString());
-					} catch (IOException e) {
+					} catch (ExecutionException | IOException e) {
 						if (LOG.isLoggable(INFO)) LOG.info(e.toString());
 					}
 				}
@@ -341,14 +356,15 @@ class BluetoothPlugin implements DuplexPlugin {
 		});
 	}
 
+	@Override
 	public boolean supportsKeyAgreement() {
 		return true;
 	}
 
-	public KeyAgreementListener createKeyAgreementListener(
-			byte[] localCommitment) {
+	@Override
+	public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
 		// 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);
 		String url = makeUrl("localhost", uuid);
 		// Make the device discoverable if possible
@@ -371,8 +387,9 @@ class BluetoothPlugin implements DuplexPlugin {
 		return new BluetoothKeyAgreementListener(d, ss);
 	}
 
+	@Override
 	public DuplexTransportConnection createKeyAgreementConnection(
-			byte[] remoteCommitment, TransportDescriptor d, long timeout) {
+			byte[] commitment, TransportDescriptor d, long timeout) {
 		if (!isRunning()) return null;
 		if (!ID.equals(d.getIdentifier())) return null;
 		TransportProperties p = d.getProperties();
@@ -380,7 +397,7 @@ class BluetoothPlugin implements DuplexPlugin {
 		String address = p.get(PROP_ADDRESS);
 		if (StringUtils.isNullOrEmpty(address)) return null;
 		// No truncation necessary because COMMIT_LENGTH = 16
-		String uuid = UUID.nameUUIDFromBytes(remoteCommitment).toString();
+		String uuid = UUID.nameUUIDFromBytes(commitment).toString();
 		if (LOG.isLoggable(INFO))
 			LOG.info("Connecting to key agreement UUID " + uuid);
 		String url = makeUrl(address, uuid);
diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java
index 116143225f..926f8d3148 100644
--- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java
+++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePlugin.java
@@ -34,29 +34,36 @@ implements RemovableDriveMonitor.Callback {
 		this.monitor = monitor;
 	}
 
+	@Override
 	public TransportId getId() {
 		return ID;
 	}
 
+	@Override
 	public boolean start() throws IOException {
+		if (used.getAndSet(true)) throw new IllegalStateException();
 		running = true;
 		monitor.start(this);
 		return true;
 	}
 
+	@Override
 	public void stop() throws IOException {
 		running = false;
 		monitor.stop();
 	}
 
+	@Override
 	public boolean shouldPoll() {
 		return false;
 	}
 
+	@Override
 	public int getPollingInterval() {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public void poll(Collection<ContactId> connected) {
 		throw new UnsupportedOperationException();
 	}
@@ -64,8 +71,7 @@ implements RemovableDriveMonitor.Callback {
 	@Override
 	protected File chooseOutputDirectory() {
 		try {
-			List<File> drives =
-					new ArrayList<File>(finder.findRemovableDrives());
+			List<File> drives = new ArrayList<>(finder.findRemovableDrives());
 			if (drives.isEmpty()) return null;
 			String[] paths = new String[drives.size()];
 			for (int i = 0; i < paths.length; i++) {
@@ -92,7 +98,7 @@ implements RemovableDriveMonitor.Callback {
 
 	@Override
 	protected Collection<File> findFilesByName(String filename) {
-		List<File> matches = new ArrayList<File>();
+		List<File> matches = new ArrayList<>();
 		try {
 			for (File drive : finder.findRemovableDrives()) {
 				File[] files = drive.listFiles();
@@ -109,6 +115,7 @@ implements RemovableDriveMonitor.Callback {
 		return Collections.unmodifiableList(matches);
 	}
 
+	@Override
 	public void driveInserted(File root) {
 		File[] files = root.listFiles();
 		if (files != null) {
@@ -116,6 +123,7 @@ implements RemovableDriveMonitor.Callback {
 		}
 	}
 
+	@Override
 	public void exceptionThrown(IOException e) {
 		if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 	}
diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java
index 10a68aa56f..ce2d2d57e7 100644
--- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java
+++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java
@@ -16,6 +16,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Logger;
 
 import static java.util.logging.Level.INFO;
@@ -32,6 +33,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 	private final SerialPortList serialPortList;
 	private final DuplexPluginCallback callback;
 	private final int maxLatency;
+	private final AtomicBoolean used = new AtomicBoolean(false);
 
 	private volatile boolean running = false;
 	private volatile Modem modem = null;
@@ -44,20 +46,25 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 		this.maxLatency = maxLatency;
 	}
 
+	@Override
 	public TransportId getId() {
 		return ID;
 	}
 
+	@Override
 	public int getMaxLatency() {
 		return maxLatency;
 	}
 
+	@Override
 	public int getMaxIdleTime() {
 		// FIXME: Do we need keepalives for this transport?
 		return Integer.MAX_VALUE;
 	}
 
+	@Override
 	public boolean start() {
+		if (used.getAndSet(true)) throw new IllegalStateException();
 		for (String portName : serialPortList.getPortNames()) {
 			if (LOG.isLoggable(INFO))
 				LOG.info("Trying to initialise modem on " + portName);
@@ -75,6 +82,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 		return false;
 	}
 
+	@Override
 	public void stop() {
 		running = false;
 		if (modem != null) {
@@ -86,18 +94,22 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 		}
 	}
 
+	@Override
 	public boolean isRunning() {
 		return running;
 	}
 
+	@Override
 	public boolean shouldPoll() {
 		return false;
 	}
 
+	@Override
 	public int getPollingInterval() {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public void poll(Collection<ContactId> connected) {
 		throw new UnsupportedOperationException();
 	}
@@ -121,6 +133,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 		return false;
 	}
 
+	@Override
 	public DuplexTransportConnection createConnection(ContactId c) {
 		if (!running) return null;
 		// Get the ISO 3166 code for the caller's country
@@ -148,29 +161,34 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 		return new ModemTransportConnection();
 	}
 
+	@Override
 	public boolean supportsInvitations() {
 		return false;
 	}
 
+	@Override
 	public DuplexTransportConnection createInvitationConnection(PseudoRandom r,
 			long timeout, boolean alice) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public boolean supportsKeyAgreement() {
 		return false;
 	}
 
-	public KeyAgreementListener createKeyAgreementListener(
-			byte[] commitment) {
+	@Override
+	public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public DuplexTransportConnection createKeyAgreementConnection(
 			byte[] commitment, TransportDescriptor d, long timeout) {
 		throw new UnsupportedOperationException();
 	}
 
+	@Override
 	public void incomingCallConnected() {
 		LOG.info("Incoming call connected");
 		callback.incomingConnectionCreated(new ModemTransportConnection());
-- 
GitLab