diff --git a/api/net/sf/briar/api/plugins/Plugin.java b/api/net/sf/briar/api/plugins/Plugin.java
index a3ae0b87dbfa1a584b03540c2343339be29820ec..1a303bcb049aa83852ccf14aa8783a09e3888c9d 100644
--- a/api/net/sf/briar/api/plugins/Plugin.java
+++ b/api/net/sf/briar/api/plugins/Plugin.java
@@ -1,7 +1,9 @@
 package net.sf.briar.api.plugins;
 
 import java.io.IOException;
+import java.util.Collection;
 
+import net.sf.briar.api.ContactId;
 import net.sf.briar.api.protocol.TransportId;
 
 public interface Plugin {
@@ -28,10 +30,11 @@ public interface Plugin {
 	long getPollingInterval();
 
 	/**
-	 * Attempts to establish connections to all contacts, passing any created
-	 * connections to the callback.
+	 * Attempts to establish connections to contacts, passing any created
+	 * connections to the callback. To avoid creating redundant connections,
+	 * the plugin may exclude the given contacts from polling.
 	 */
-	void poll();
+	void poll(Collection<ContactId> connected);
 
 	/** Returns true if the plugin supports exchanging invitations. */
 	boolean supportsInvitations();
diff --git a/api/net/sf/briar/api/protocol/batch/BatchConnectionFactory.java b/api/net/sf/briar/api/protocol/batch/BatchConnectionFactory.java
index 8f7bca029b12d4032c7513ed0141c89dfeaa2fa3..7f581ff8c17094fdc6487fe7fd8b8e660e69968b 100644
--- a/api/net/sf/briar/api/protocol/batch/BatchConnectionFactory.java
+++ b/api/net/sf/briar/api/protocol/batch/BatchConnectionFactory.java
@@ -1,6 +1,7 @@
 package net.sf.briar.api.protocol.batch;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.transport.BatchTransportReader;
 import net.sf.briar.api.transport.BatchTransportWriter;
@@ -8,9 +9,9 @@ import net.sf.briar.api.transport.ConnectionContext;
 
 public interface BatchConnectionFactory {
 
-	void createIncomingConnection(ConnectionContext ctx,
+	void createIncomingConnection(ConnectionContext ctx, TransportId t,
 			BatchTransportReader r, byte[] tag);
 
-	void createOutgoingConnection(ContactId c, TransportIndex i,
+	void createOutgoingConnection(ContactId c, TransportId t, TransportIndex i,
 			BatchTransportWriter w);
 }
diff --git a/api/net/sf/briar/api/protocol/stream/StreamConnectionFactory.java b/api/net/sf/briar/api/protocol/stream/StreamConnectionFactory.java
index 5cf78317e979b23e167bd88db12e09dd625dae2f..5b371c9147e3b1572b768dfc4b3f58a5187f9cbc 100644
--- a/api/net/sf/briar/api/protocol/stream/StreamConnectionFactory.java
+++ b/api/net/sf/briar/api/protocol/stream/StreamConnectionFactory.java
@@ -1,15 +1,16 @@
 package net.sf.briar.api.protocol.stream;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.StreamTransportConnection;
 
 public interface StreamConnectionFactory {
 
-	void createIncomingConnection(ConnectionContext ctx,
+	void createIncomingConnection(ConnectionContext ctx, TransportId t,
 			StreamTransportConnection s, byte[] tag);
 
-	void createOutgoingConnection(ContactId c, TransportIndex i,
+	void createOutgoingConnection(ContactId c, TransportId t, TransportIndex i,
 			StreamTransportConnection s);
 }
diff --git a/api/net/sf/briar/api/transport/ConnectionDispatcher.java b/api/net/sf/briar/api/transport/ConnectionDispatcher.java
index 4317983395d86add2ed93d9d29877eafa7b5f40b..81c26abfadac6eded98baf25ede6831907c22e75 100644
--- a/api/net/sf/briar/api/transport/ConnectionDispatcher.java
+++ b/api/net/sf/briar/api/transport/ConnectionDispatcher.java
@@ -8,10 +8,11 @@ public interface ConnectionDispatcher {
 
 	void dispatchReader(TransportId t, BatchTransportReader r);
 
-	void dispatchWriter(ContactId c, TransportIndex i, BatchTransportWriter w);
+	void dispatchWriter(ContactId c, TransportId t, TransportIndex i,
+			BatchTransportWriter w);
 
 	void dispatchIncomingConnection(TransportId t, StreamTransportConnection s);
 
-	void dispatchOutgoingConnection(ContactId c, TransportIndex i,
-			StreamTransportConnection s);
+	void dispatchOutgoingConnection(ContactId c, TransportId t,
+			TransportIndex i, StreamTransportConnection s);
 }
diff --git a/api/net/sf/briar/api/transport/ConnectionRegistry.java b/api/net/sf/briar/api/transport/ConnectionRegistry.java
new file mode 100644
index 0000000000000000000000000000000000000000..f9b3489cbfb3982e9f36a16a807babbaad976ac5
--- /dev/null
+++ b/api/net/sf/briar/api/transport/ConnectionRegistry.java
@@ -0,0 +1,18 @@
+package net.sf.briar.api.transport;
+
+import java.util.Collection;
+
+import net.sf.briar.api.ContactId;
+import net.sf.briar.api.protocol.TransportId;
+
+/**
+ * Keeps track of which contacts are currently connected by which transports.
+ */
+public interface ConnectionRegistry {
+
+	void registerConnection(ContactId c, TransportId t);
+
+	void unregisterConnection(ContactId c, TransportId t);
+
+	Collection<ContactId> getConnectedContacts(TransportId t);
+}
diff --git a/components/net/sf/briar/plugins/PluginManagerImpl.java b/components/net/sf/briar/plugins/PluginManagerImpl.java
index a3343b5c860c63807ee6ed97a5272de6bca0ccb5..83d5e1ef2ea360e53b7de94ed4946c386e06950c 100644
--- a/components/net/sf/briar/plugins/PluginManagerImpl.java
+++ b/components/net/sf/briar/plugins/PluginManagerImpl.java
@@ -51,8 +51,8 @@ class PluginManagerImpl implements PluginManager {
 		"net.sf.briar.plugins.socket.SimpleSocketPluginFactory"
 	};
 
-	private final DatabaseComponent db;
 	private final Executor pluginExecutor;
+	private final DatabaseComponent db;
 	private final Poller poller;
 	private final ConnectionDispatcher dispatcher;
 	private final UiCallback uiCallback;
@@ -60,11 +60,11 @@ class PluginManagerImpl implements PluginManager {
 	private final List<StreamPlugin> streamPlugins; // Locking: this
 
 	@Inject
-	PluginManagerImpl(DatabaseComponent db,
-			@PluginExecutor Executor pluginExecutor, Poller poller,
+	PluginManagerImpl(@PluginExecutor Executor pluginExecutor,
+			DatabaseComponent db, Poller poller,
 			ConnectionDispatcher dispatcher, UiCallback uiCallback) {
-		this.db = db;
 		this.pluginExecutor = pluginExecutor;
+		this.db = db;
 		this.poller = poller;
 		this.dispatcher = dispatcher;
 		this.uiCallback = uiCallback;
@@ -295,7 +295,7 @@ class PluginManagerImpl implements PluginManager {
 
 		public void writerCreated(ContactId c, BatchTransportWriter w) {
 			assert index != null;
-			dispatcher.dispatchWriter(c, index, w);
+			dispatcher.dispatchWriter(c, id, index, w);
 		}
 	}
 
@@ -310,7 +310,7 @@ class PluginManagerImpl implements PluginManager {
 		public void outgoingConnectionCreated(ContactId c,
 				StreamTransportConnection s) {
 			assert index != null;
-			dispatcher.dispatchOutgoingConnection(c, index, s);
+			dispatcher.dispatchOutgoingConnection(c, id, index, s);
 		}
 	}
 }
\ No newline at end of file
diff --git a/components/net/sf/briar/plugins/PollerImpl.java b/components/net/sf/briar/plugins/PollerImpl.java
index 75de03ae6dd0a08f2fbbe09e7d7fab7d7ff88a10..3245c08a693bacf84b43e05b83dd1c28a3dcd1bf 100644
--- a/components/net/sf/briar/plugins/PollerImpl.java
+++ b/components/net/sf/briar/plugins/PollerImpl.java
@@ -6,14 +6,25 @@ import java.util.TreeSet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import net.sf.briar.api.ContactId;
 import net.sf.briar.api.plugins.Plugin;
+import net.sf.briar.api.transport.ConnectionRegistry;
+
+import com.google.inject.Inject;
 
 class PollerImpl implements Poller, Runnable {
 
 	private static final Logger LOG =
 		Logger.getLogger(PollerImpl.class.getName());
 
-	private final SortedSet<PollTime> pollTimes = new TreeSet<PollTime>();
+	private final ConnectionRegistry connRegistry;
+	private final SortedSet<PollTime> pollTimes;
+
+	@Inject
+	PollerImpl(ConnectionRegistry connRegistry) {
+		this.connRegistry = connRegistry;
+		pollTimes = new TreeSet<PollTime>();
+	}
 
 	public synchronized void startPolling(Collection<Plugin> plugins) {
 		for(Plugin plugin : plugins) schedule(plugin);
@@ -41,8 +52,10 @@ class PollerImpl implements Poller, Runnable {
 				long now = System.currentTimeMillis();
 				if(now <= p.time) {
 					pollTimes.remove(p);
+					Collection<ContactId> connected =
+						connRegistry.getConnectedContacts(p.plugin.getId());
 					try {
-						p.plugin.poll();
+						p.plugin.poll(connected);
 					} catch(RuntimeException e) {
 						if(LOG.isLoggable(Level.WARNING))
 							LOG.warning("Plugin " + p.plugin.getId() + " " + e);
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
index d7156980107462d4291661e8269556a5bb768955..50b9d6216c16516f5db25505f7b3bc02cf2b9296 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
@@ -1,6 +1,7 @@
 package net.sf.briar.plugins.bluetooth;
 
 import java.io.IOException;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -178,18 +179,18 @@ class BluetoothPlugin implements StreamPlugin {
 		return pollingInterval;
 	}
 
-	public void poll() {
+	public void poll(final Collection<ContactId> connected) {
 		synchronized(this) {
 			if(!running) return;
 		}
 		pluginExecutor.execute(new Runnable() {
 			public void run() {
-				connectAndCallBack();
+				connectAndCallBack(connected);
 			}
 		});
 	}
 
-	private void connectAndCallBack() {
+	private void connectAndCallBack(Collection<ContactId> connected) {
 		synchronized(this) {
 			if(!running) return;
 		}
@@ -198,6 +199,8 @@ class BluetoothPlugin implements StreamPlugin {
 		Map<ContactId, String> discovered = discoverContactUrls(remote);
 		for(Entry<ContactId, String> e : discovered.entrySet()) {
 			ContactId c = e.getKey();
+			// Don't create redundant connections
+			if(connected.contains(c)) continue;
 			String url = e.getValue();
 			StreamTransportConnection s = connect(c, url);
 			if(s != null) callback.outgoingConnectionCreated(c, s);
diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
index 7609d25d0a91936175045d3a48bbecae63ebe7f1..930bea4059e1c71241942e51fe334f1ce367af44 100644
--- a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
+++ b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
@@ -10,6 +10,7 @@ import java.util.concurrent.Executor;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import net.sf.briar.api.ContactId;
 import net.sf.briar.api.plugins.BatchPluginCallback;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.protocol.TransportId;
@@ -59,7 +60,7 @@ implements RemovableDriveMonitor.Callback {
 		throw new UnsupportedOperationException();
 	}
 
-	public void poll() {
+	public void poll(Collection<ContactId> connected) {
 		throw new UnsupportedOperationException();
 	}
 
diff --git a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
index 247a943a091c8eeeca35e86726e8c838a53b356b..1a6bb99eb16f1ea6bb28d6eec084346a5eefa719 100644
--- a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
@@ -31,26 +31,15 @@ class SimpleSocketPlugin extends SocketPlugin {
 	private static final Logger LOG =
 		Logger.getLogger(SimpleSocketPlugin.class.getName());
 
-	private final long pollingInterval;
-
 	SimpleSocketPlugin(@PluginExecutor Executor pluginExecutor,
 			StreamPluginCallback callback, long pollingInterval) {
-		super(pluginExecutor, callback);
-		this.pollingInterval = pollingInterval;
+		super(pluginExecutor, callback, pollingInterval);
 	}
 
 	public TransportId getId() {
 		return id;
 	}
 
-	public boolean shouldPoll() {
-		return true;
-	}
-
-	public long getPollingInterval() {
-		return pollingInterval;
-	}
-
 	@Override
 	protected Socket createClientSocket() throws IOException {
 		assert running;
diff --git a/components/net/sf/briar/plugins/socket/SocketPlugin.java b/components/net/sf/briar/plugins/socket/SocketPlugin.java
index 77a2170bc47616c8a075398155b2c0e1992ab413..15b48f4ef381ace19bda53b25ca0adbca698c617 100644
--- a/components/net/sf/briar/plugins/socket/SocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/SocketPlugin.java
@@ -4,6 +4,7 @@ import java.io.IOException;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketAddress;
+import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.Executor;
 import java.util.logging.Level;
@@ -24,6 +25,8 @@ abstract class SocketPlugin implements StreamPlugin {
 	protected final Executor pluginExecutor;
 	protected final StreamPluginCallback callback;
 
+	private final long pollingInterval;
+
 	protected boolean running = false; // Locking: this
 	protected ServerSocket socket = null; // Locking: this
 
@@ -35,9 +38,10 @@ abstract class SocketPlugin implements StreamPlugin {
 	protected abstract SocketAddress getRemoteSocketAddress(ContactId c);
 
 	protected SocketPlugin(@PluginExecutor Executor pluginExecutor,
-			StreamPluginCallback callback) {
+			StreamPluginCallback callback, long pollingInterval) {
 		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
+		this.pollingInterval = pollingInterval;
 	}
 
 	public void start() throws IOException {
@@ -115,13 +119,22 @@ abstract class SocketPlugin implements StreamPlugin {
 		}
 	}
 
-	public void poll() {
+	public boolean shouldPoll() {
+		return true;
+	}
+
+	public long getPollingInterval() {
+		return pollingInterval;
+	}
+
+	public void poll(Collection<ContactId> connected) {
 		synchronized(this) {
 			if(!running) return;
 		}
 		Map<ContactId, TransportProperties> remote =
 			callback.getRemoteProperties();
 		for(final ContactId c : remote.keySet()) {
+			if(connected.contains(c)) continue;
 			pluginExecutor.execute(new Runnable() {
 				public void run() {
 					connectAndCallBack(c);
diff --git a/components/net/sf/briar/protocol/batch/BatchConnectionFactoryImpl.java b/components/net/sf/briar/protocol/batch/BatchConnectionFactoryImpl.java
index 6fba90348f671e0fdbab711db6724102b9eb96c3..5d52a90fb372667a65c652fd299879c4b48eea59 100644
--- a/components/net/sf/briar/protocol/batch/BatchConnectionFactoryImpl.java
+++ b/components/net/sf/briar/protocol/batch/BatchConnectionFactoryImpl.java
@@ -7,6 +7,7 @@ import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.protocol.VerificationExecutor;
 import net.sf.briar.api.protocol.batch.BatchConnectionFactory;
@@ -14,6 +15,7 @@ import net.sf.briar.api.transport.BatchTransportReader;
 import net.sf.briar.api.transport.BatchTransportWriter;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 
 import com.google.inject.Inject;
@@ -22,6 +24,7 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
 
 	private final Executor dbExecutor, verificationExecutor;
 	private final DatabaseComponent db;
+	private final ConnectionRegistry connRegistry;
 	private final ConnectionReaderFactory connReaderFactory;
 	private final ConnectionWriterFactory connWriterFactory;
 	private final ProtocolReaderFactory protoReaderFactory;
@@ -30,24 +33,26 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
 	@Inject
 	BatchConnectionFactoryImpl(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
-			DatabaseComponent db, ConnectionReaderFactory connReaderFactory,
+			DatabaseComponent db, ConnectionRegistry connRegistry,
+			ConnectionReaderFactory connReaderFactory,
 			ConnectionWriterFactory connWriterFactory,
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory) {
 		this.dbExecutor = dbExecutor;
 		this.verificationExecutor = verificationExecutor;
 		this.db = db;
+		this.connRegistry = connRegistry;
 		this.connReaderFactory = connReaderFactory;
 		this.connWriterFactory = connWriterFactory;
 		this.protoReaderFactory = protoReaderFactory;
 		this.protoWriterFactory = protoWriterFactory;
 	}
 
-	public void createIncomingConnection(ConnectionContext ctx,
+	public void createIncomingConnection(ConnectionContext ctx, TransportId t,
 			BatchTransportReader r, byte[] tag) {
 		final IncomingBatchConnection conn = new IncomingBatchConnection(
-				dbExecutor, verificationExecutor, db, connReaderFactory,
-				protoReaderFactory, ctx, r, tag);
+				dbExecutor, verificationExecutor, db, connRegistry,
+				connReaderFactory, protoReaderFactory, ctx, t, r, tag);
 		Runnable read = new Runnable() {
 			public void run() {
 				conn.read();
@@ -56,10 +61,11 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
 		new Thread(read).start();
 	}
 
-	public void createOutgoingConnection(ContactId c, TransportIndex i,
-			BatchTransportWriter w) {
+	public void createOutgoingConnection(ContactId c, TransportId t,
+			TransportIndex i, BatchTransportWriter w) {
 		final OutgoingBatchConnection conn = new OutgoingBatchConnection(db,
-				connWriterFactory, protoWriterFactory, c, i, w);
+				connRegistry, connWriterFactory, protoWriterFactory,
+				c, t, i, w);
 		Runnable write = new Runnable() {
 			public void run() {
 				conn.write();
diff --git a/components/net/sf/briar/protocol/batch/IncomingBatchConnection.java b/components/net/sf/briar/protocol/batch/IncomingBatchConnection.java
index e7f14c605448de451e794eb22363564567b4a75d..1f5327f996a4a26aad3b44fd85263fc50ecdf11c 100644
--- a/components/net/sf/briar/protocol/batch/IncomingBatchConnection.java
+++ b/components/net/sf/briar/protocol/batch/IncomingBatchConnection.java
@@ -17,6 +17,7 @@ import net.sf.briar.api.protocol.Batch;
 import net.sf.briar.api.protocol.ProtocolReader;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.SubscriptionUpdate;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.protocol.UnverifiedBatch;
 import net.sf.briar.api.protocol.VerificationExecutor;
@@ -24,6 +25,7 @@ import net.sf.briar.api.transport.BatchTransportReader;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionReader;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
+import net.sf.briar.api.transport.ConnectionRegistry;
 
 class IncomingBatchConnection {
 
@@ -31,31 +33,38 @@ class IncomingBatchConnection {
 		Logger.getLogger(IncomingBatchConnection.class.getName());
 
 	private final Executor dbExecutor, verificationExecutor;
-	private final ConnectionReaderFactory connFactory;
 	private final DatabaseComponent db;
+	private final ConnectionRegistry connRegistry;
+	private final ConnectionReaderFactory connFactory;
 	private final ProtocolReaderFactory protoFactory;
 	private final ConnectionContext ctx;
+	private final TransportId transportId;
 	private final BatchTransportReader transport;
 	private final byte[] tag;
 	private final ContactId contactId;
 
 	IncomingBatchConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
-			DatabaseComponent db, ConnectionReaderFactory connFactory,
+			DatabaseComponent db, ConnectionRegistry connRegistry,
+			ConnectionReaderFactory connFactory,
 			ProtocolReaderFactory protoFactory, ConnectionContext ctx,
-			BatchTransportReader transport, byte[] tag) {
+			TransportId transportId, BatchTransportReader transport,
+			byte[] tag) {
 		this.dbExecutor = dbExecutor;
 		this.verificationExecutor = verificationExecutor;
-		this.connFactory = connFactory;
 		this.db = db;
+		this.connRegistry = connRegistry;
+		this.connFactory = connFactory;
 		this.protoFactory = protoFactory;
 		this.ctx = ctx;
+		this.transportId = transportId;
 		this.transport = transport;
 		this.tag = tag;
 		contactId = ctx.getContactId();
 	}
 
 	void read() {
+		connRegistry.registerConnection(contactId, transportId);
 		try {
 			ConnectionReader conn = connFactory.createConnectionReader(
 					transport.getInputStream(), ctx.getSecret(), tag);
@@ -83,6 +92,8 @@ class IncomingBatchConnection {
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 			transport.dispose(true, true);
+		} finally {
+			connRegistry.unregisterConnection(contactId, transportId);
 		}
 	}
 
diff --git a/components/net/sf/briar/protocol/batch/OutgoingBatchConnection.java b/components/net/sf/briar/protocol/batch/OutgoingBatchConnection.java
index 720b0d32352b927c6ee2f2946754b00cd65b272a..14ef7268e0bd3a00ed9d6592efaac076494eb470 100644
--- a/components/net/sf/briar/protocol/batch/OutgoingBatchConnection.java
+++ b/components/net/sf/briar/protocol/batch/OutgoingBatchConnection.java
@@ -16,10 +16,12 @@ import net.sf.briar.api.protocol.ProtocolWriter;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
 import net.sf.briar.api.protocol.RawBatch;
 import net.sf.briar.api.protocol.SubscriptionUpdate;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.transport.BatchTransportWriter;
 import net.sf.briar.api.transport.ConnectionContext;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 
@@ -29,25 +31,32 @@ class OutgoingBatchConnection {
 		Logger.getLogger(OutgoingBatchConnection.class.getName());
 
 	private final DatabaseComponent db;
+	private final ConnectionRegistry connRegistry;
 	private final ConnectionWriterFactory connFactory;
 	private final ProtocolWriterFactory protoFactory;
 	private final ContactId contactId;
+	private final TransportId transportId;
 	private final TransportIndex transportIndex;
 	private final BatchTransportWriter transport;
 
 	OutgoingBatchConnection(DatabaseComponent db,
+			ConnectionRegistry connRegistry,
 			ConnectionWriterFactory connFactory,
 			ProtocolWriterFactory protoFactory, ContactId contactId,
-			TransportIndex transportIndex, BatchTransportWriter transport) {
+			TransportId transportId, TransportIndex transportIndex,
+			BatchTransportWriter transport) {
 		this.db = db;
+		this.connRegistry = connRegistry;
 		this.connFactory = connFactory;
 		this.protoFactory = protoFactory;
 		this.contactId = contactId;
+		this.transportId = transportId;
 		this.transportIndex = transportIndex;
 		this.transport = transport;
 	}
 
 	void write() {
+		connRegistry.registerConnection(contactId, transportId);
 		try {
 			ConnectionContext ctx = db.getConnectionContext(contactId,
 					transportIndex);
@@ -97,6 +106,8 @@ class OutgoingBatchConnection {
 		} catch(IOException e) {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 			transport.dispose(true);
+		} finally {
+			connRegistry.unregisterConnection(contactId, transportId);
 		}
 	}
 }
diff --git a/components/net/sf/briar/protocol/stream/IncomingStreamConnection.java b/components/net/sf/briar/protocol/stream/IncomingStreamConnection.java
index 846ac80de250fd110b0033d5ec9e672e8722438f..6a32c24850d38b3f61795fcd4903696720448097 100644
--- a/components/net/sf/briar/protocol/stream/IncomingStreamConnection.java
+++ b/components/net/sf/briar/protocol/stream/IncomingStreamConnection.java
@@ -7,10 +7,12 @@ import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.VerificationExecutor;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionReader;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.api.transport.StreamTransportConnection;
@@ -22,15 +24,16 @@ class IncomingStreamConnection extends StreamConnection {
 
 	IncomingStreamConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
-			DatabaseComponent db, ConnectionReaderFactory connReaderFactory,
+			DatabaseComponent db, ConnectionRegistry connRegistry,
+			ConnectionReaderFactory connReaderFactory,
 			ConnectionWriterFactory connWriterFactory,
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory,
-			ConnectionContext ctx, StreamTransportConnection transport,
-			byte[] tag) {
-		super(dbExecutor, verificationExecutor, db, connReaderFactory,
-				connWriterFactory, protoReaderFactory, protoWriterFactory,
-				ctx.getContactId(), transport);
+			ConnectionContext ctx, TransportId transportId,
+			StreamTransportConnection transport, byte[] tag) {
+		super(dbExecutor, verificationExecutor, db, connRegistry,
+				connReaderFactory, connWriterFactory, protoReaderFactory,
+				protoWriterFactory, ctx.getContactId(), transportId, transport);
 		this.ctx = ctx;
 		this.tag = tag;
 	}
diff --git a/components/net/sf/briar/protocol/stream/OutgoingStreamConnection.java b/components/net/sf/briar/protocol/stream/OutgoingStreamConnection.java
index 68c33157adea4ac25a0b68d9ce37aa56396b056f..84fa026653dde15febb958b42eadc4c10761a7d1 100644
--- a/components/net/sf/briar/protocol/stream/OutgoingStreamConnection.java
+++ b/components/net/sf/briar/protocol/stream/OutgoingStreamConnection.java
@@ -9,11 +9,13 @@ import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.db.DbException;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.protocol.VerificationExecutor;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionReader;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.api.transport.StreamTransportConnection;
@@ -26,15 +28,16 @@ class OutgoingStreamConnection extends StreamConnection {
 
 	OutgoingStreamConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
-			DatabaseComponent db, ConnectionReaderFactory connReaderFactory,
+			DatabaseComponent db, ConnectionRegistry connRegistry,
+			ConnectionReaderFactory connReaderFactory,
 			ConnectionWriterFactory connWriterFactory,
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory, ContactId contactId,
-			TransportIndex transportIndex,
+			TransportId transportId, TransportIndex transportIndex,
 			StreamTransportConnection transport) {
-		super(dbExecutor, verificationExecutor, db, connReaderFactory,
-				connWriterFactory, protoReaderFactory, protoWriterFactory,
-				contactId, transport);
+		super(dbExecutor, verificationExecutor, db, connRegistry,
+				connReaderFactory, connWriterFactory, protoReaderFactory,
+				protoWriterFactory, contactId, transportId, transport);
 		this.transportIndex = transportIndex;
 	}
 
diff --git a/components/net/sf/briar/protocol/stream/StreamConnection.java b/components/net/sf/briar/protocol/stream/StreamConnection.java
index 7d378db49fe3c49d59e33e1b296c23455e41cf54..c4e40aa30847f435f0eea64c51441347b758f268 100644
--- a/components/net/sf/briar/protocol/stream/StreamConnection.java
+++ b/components/net/sf/briar/protocol/stream/StreamConnection.java
@@ -40,11 +40,13 @@ import net.sf.briar.api.protocol.ProtocolWriterFactory;
 import net.sf.briar.api.protocol.RawBatch;
 import net.sf.briar.api.protocol.Request;
 import net.sf.briar.api.protocol.SubscriptionUpdate;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.protocol.UnverifiedBatch;
 import net.sf.briar.api.protocol.VerificationExecutor;
 import net.sf.briar.api.transport.ConnectionReader;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.api.transport.StreamTransportConnection;
@@ -59,11 +61,13 @@ abstract class StreamConnection implements DatabaseListener {
 	};
 
 	protected final DatabaseComponent db;
+	protected final ConnectionRegistry connRegistry;
 	protected final ConnectionReaderFactory connReaderFactory;
 	protected final ConnectionWriterFactory connWriterFactory;
 	protected final ProtocolReaderFactory protoReaderFactory;
 	protected final ProtocolWriterFactory protoWriterFactory;
 	protected final ContactId contactId;
+	protected final TransportId transportId;
 	protected final StreamTransportConnection transport;
 
 	private final Executor dbExecutor, verificationExecutor;
@@ -76,19 +80,22 @@ abstract class StreamConnection implements DatabaseListener {
 
 	StreamConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
-			DatabaseComponent db, ConnectionReaderFactory connReaderFactory,
+			DatabaseComponent db, ConnectionRegistry connRegistry,
+			ConnectionReaderFactory connReaderFactory,
 			ConnectionWriterFactory connWriterFactory,
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory, ContactId contactId,
-			StreamTransportConnection transport) {
+			TransportId transportId, StreamTransportConnection transport) {
 		this.dbExecutor = dbExecutor;
 		this.verificationExecutor = verificationExecutor;
 		this.db = db;
+		this.connRegistry = connRegistry;
 		this.connReaderFactory = connReaderFactory;
 		this.connWriterFactory = connWriterFactory;
 		this.protoReaderFactory = protoReaderFactory;
 		this.protoWriterFactory = protoWriterFactory;
 		this.contactId = contactId;
+		this.transportId = transportId;
 		this.transport = transport;
 		canSendOffer = new AtomicBoolean(false);
 		disposed = new AtomicBoolean(false);
@@ -188,8 +195,9 @@ abstract class StreamConnection implements DatabaseListener {
 	}
 
 	void write() {
+		connRegistry.registerConnection(contactId, transportId);
+		db.addListener(this);
 		try {
-			db.addListener(this);
 			OutputStream out = createConnectionWriter().getOutputStream();
 			writer = protoWriterFactory.createProtocolWriter(out,
 					transport.shouldFlush());
@@ -217,6 +225,7 @@ abstract class StreamConnection implements DatabaseListener {
 			if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 			if(!disposed.getAndSet(true)) transport.dispose(true, true);
 		} finally {
+			connRegistry.unregisterConnection(contactId, transportId);
 			db.removeListener(this);
 		}
 	}
diff --git a/components/net/sf/briar/protocol/stream/StreamConnectionFactoryImpl.java b/components/net/sf/briar/protocol/stream/StreamConnectionFactoryImpl.java
index 2b27c91eaa51a60f0d67479354e0091105dc9eb6..05e337c6af96c5383adfbda9872ffc3a3b9781ec 100644
--- a/components/net/sf/briar/protocol/stream/StreamConnectionFactoryImpl.java
+++ b/components/net/sf/briar/protocol/stream/StreamConnectionFactoryImpl.java
@@ -7,11 +7,13 @@ import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.protocol.VerificationExecutor;
 import net.sf.briar.api.protocol.stream.StreamConnectionFactory;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.api.transport.StreamTransportConnection;
 
@@ -21,6 +23,7 @@ class StreamConnectionFactoryImpl implements StreamConnectionFactory {
 
 	private final Executor dbExecutor, verificationExecutor;
 	private final DatabaseComponent db;
+	private final ConnectionRegistry connRegistry;
 	private final ConnectionReaderFactory connReaderFactory;
 	private final ConnectionWriterFactory connWriterFactory;
 	private final ProtocolReaderFactory protoReaderFactory;
@@ -29,24 +32,27 @@ class StreamConnectionFactoryImpl implements StreamConnectionFactory {
 	@Inject
 	StreamConnectionFactoryImpl(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
-			DatabaseComponent db, ConnectionReaderFactory connReaderFactory,
+			DatabaseComponent db, ConnectionRegistry connRegistry,
+			ConnectionReaderFactory connReaderFactory,
 			ConnectionWriterFactory connWriterFactory,
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory) {
 		this.dbExecutor = dbExecutor;
 		this.verificationExecutor = verificationExecutor;
 		this.db = db;
+		this.connRegistry = connRegistry;
 		this.connReaderFactory = connReaderFactory;
 		this.connWriterFactory = connWriterFactory;
 		this.protoReaderFactory = protoReaderFactory;
 		this.protoWriterFactory = protoWriterFactory;
 	}
 
-	public void createIncomingConnection(ConnectionContext ctx,
+	public void createIncomingConnection(ConnectionContext ctx, TransportId t,
 			StreamTransportConnection s, byte[] tag) {
 		final StreamConnection conn = new IncomingStreamConnection(dbExecutor,
-				verificationExecutor, db, connReaderFactory, connWriterFactory,
-				protoReaderFactory, protoWriterFactory, ctx, s, tag);
+				verificationExecutor, db, connRegistry, connReaderFactory,
+				connWriterFactory, protoReaderFactory, protoWriterFactory,
+				ctx, t, s, tag);
 		Runnable write = new Runnable() {
 			public void run() {
 				conn.write();
@@ -61,11 +67,12 @@ class StreamConnectionFactoryImpl implements StreamConnectionFactory {
 		new Thread(read).start();
 	}
 
-	public void createOutgoingConnection(ContactId c, TransportIndex i,
-			StreamTransportConnection s) {
+	public void createOutgoingConnection(ContactId c, TransportId t,
+			TransportIndex i, StreamTransportConnection s) {
 		final StreamConnection conn = new OutgoingStreamConnection(dbExecutor,
-				verificationExecutor, db, connReaderFactory, connWriterFactory,
-				protoReaderFactory, protoWriterFactory, c, i, s);
+				verificationExecutor, db, connRegistry, connReaderFactory,
+				connWriterFactory, protoReaderFactory, protoWriterFactory,
+				c, t, i, s);
 		Runnable write = new Runnable() {
 			public void run() {
 				conn.write();
diff --git a/components/net/sf/briar/transport/ConnectionDispatcherImpl.java b/components/net/sf/briar/transport/ConnectionDispatcherImpl.java
index 8a713928565b1cf168f22f04486f80fad8fa1da7..f390db3d6da486c847be190f074e73997a7f5388 100644
--- a/components/net/sf/briar/transport/ConnectionDispatcherImpl.java
+++ b/components/net/sf/briar/transport/ConnectionDispatcherImpl.java
@@ -49,9 +49,9 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
 		executor.execute(new DispatchBatchConnection(t, r));
 	}
 
-	public void dispatchWriter(ContactId c, TransportIndex i,
+	public void dispatchWriter(ContactId c, TransportId t, TransportIndex i,
 			BatchTransportWriter w) {
-		batchConnFactory.createOutgoingConnection(c, i, w);
+		batchConnFactory.createOutgoingConnection(c, t, i, w);
 	}
 
 	public void dispatchIncomingConnection(TransportId t,
@@ -59,9 +59,9 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
 		executor.execute(new DispatchStreamConnection(t, s));
 	}
 
-	public void dispatchOutgoingConnection(ContactId c, TransportIndex i,
-			StreamTransportConnection s) {
-		streamConnFactory.createOutgoingConnection(c, i, s);
+	public void dispatchOutgoingConnection(ContactId c, TransportId t,
+			TransportIndex i, StreamTransportConnection s) {
+		streamConnFactory.createOutgoingConnection(c, t, i, s);
 	}
 
 	private byte[] readTag(InputStream in) throws IOException {
@@ -92,8 +92,8 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
 				ConnectionContext ctx = recogniser.acceptConnection(transportId,
 						tag);
 				if(ctx == null) transport.dispose(false, false);
-				else batchConnFactory.createIncomingConnection(ctx, transport,
-						tag);
+				else batchConnFactory.createIncomingConnection(ctx, transportId,
+						transport, tag);
 			} catch(DbException e) {
 				if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 				transport.dispose(true, false);
@@ -121,8 +121,8 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
 				ConnectionContext ctx = recogniser.acceptConnection(transportId,
 						tag);
 				if(ctx == null) transport.dispose(false, false);
-				else streamConnFactory.createIncomingConnection(ctx, transport,
-						tag);
+				else streamConnFactory.createIncomingConnection(ctx,
+						transportId, transport, tag);
 			} catch(DbException e) {
 				if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 				transport.dispose(true, false);
diff --git a/components/net/sf/briar/transport/ConnectionRegistryImpl.java b/components/net/sf/briar/transport/ConnectionRegistryImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..65c2d3ef02e8195ef1709b2b53d994456142aef8
--- /dev/null
+++ b/components/net/sf/briar/transport/ConnectionRegistryImpl.java
@@ -0,0 +1,53 @@
+package net.sf.briar.transport;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.briar.api.ContactId;
+import net.sf.briar.api.protocol.TransportId;
+import net.sf.briar.api.transport.ConnectionRegistry;
+
+public class ConnectionRegistryImpl implements ConnectionRegistry {
+
+	// Locking: this
+	private final Map<TransportId, Map<ContactId, Integer>> connections;
+
+	ConnectionRegistryImpl() {
+		connections = new HashMap<TransportId, Map<ContactId, Integer>>();
+	}
+
+	public synchronized void registerConnection(ContactId c, TransportId t) {
+		Map<ContactId, Integer> m = connections.get(t);
+		if(m == null) {
+			m = new HashMap<ContactId, Integer>();
+			connections.put(t, m);
+		}
+		Integer count = m.get(c);
+		if(count == null) m.put(c, 1);
+		else m.put(c, count + 1);
+	}
+
+	public synchronized void unregisterConnection(ContactId c, TransportId t) {
+		Map<ContactId, Integer> m = connections.get(t);
+		if(m == null) throw new IllegalArgumentException();
+		Integer count = m.remove(c);
+		if(count == null) throw new IllegalArgumentException();
+		if(count == 1) {
+			if(m.isEmpty()) connections.remove(t);
+		} else {
+			m.put(c, count - 1);
+		}
+	}
+
+	public synchronized Collection<ContactId> getConnectedContacts(
+			TransportId t) {
+		Map<ContactId, Integer> m = connections.get(t);
+		if(m == null) return Collections.emptyList();
+		List<ContactId> keys = new ArrayList<ContactId>(m.keySet());
+		return Collections.unmodifiableList(keys);
+	}
+}
diff --git a/components/net/sf/briar/transport/TransportModule.java b/components/net/sf/briar/transport/TransportModule.java
index 876ec823873ee52fc6be75bcc73839006bff4639..a4e6ea18e08b2f037f6d71875ae4693a53f1c861 100644
--- a/components/net/sf/briar/transport/TransportModule.java
+++ b/components/net/sf/briar/transport/TransportModule.java
@@ -8,6 +8,7 @@ import net.sf.briar.api.transport.ConnectionDispatcher;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
 import net.sf.briar.api.transport.ConnectionRecogniser;
 import net.sf.briar.api.transport.ConnectionRecogniserExecutor;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWindowFactory;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 
@@ -23,6 +24,7 @@ public class TransportModule extends AbstractModule {
 		bind(ConnectionReaderFactory.class).to(
 				ConnectionReaderFactoryImpl.class);
 		bind(ConnectionRecogniser.class).to(ConnectionRecogniserImpl.class);
+		bind(ConnectionRegistry.class).toInstance(new ConnectionRegistryImpl());
 		bind(ConnectionWindowFactory.class).to(
 				ConnectionWindowFactoryImpl.class);
 		bind(ConnectionWriterFactory.class).to(
diff --git a/test/build.xml b/test/build.xml
index 2a0ca52a5453687ea5d2187afe1684ce55972087..3ee4485477db4dd32c4c613bf2c22b5fa001cbae 100644
--- a/test/build.xml
+++ b/test/build.xml
@@ -53,6 +53,7 @@
 			<test name='net.sf.briar.transport.ConnectionEncrypterImplTest'/>
 			<test name='net.sf.briar.transport.ConnectionReaderImplTest'/>
 			<test name='net.sf.briar.transport.ConnectionRecogniserImplTest'/>
+			<test name='net.sf.briar.transport.ConnectionRegistryImplTest'/>
 			<test name='net.sf.briar.transport.ConnectionWindowImplTest'/>
 			<test name='net.sf.briar.transport.ConnectionWriterImplTest'/>
 			<test name='net.sf.briar.transport.ConnectionWriterTest'/>
diff --git a/test/net/sf/briar/BriarTestCase.java b/test/net/sf/briar/BriarTestCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..171b620cde70768e3cfd44f57d30311acddeefd7
--- /dev/null
+++ b/test/net/sf/briar/BriarTestCase.java
@@ -0,0 +1,19 @@
+package net.sf.briar;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+
+import junit.framework.TestCase;
+
+public abstract class BriarTestCase extends TestCase {
+
+	public BriarTestCase() {
+		super();
+		// Ensure exceptions thrown on worker threads cause tests to fail
+		UncaughtExceptionHandler fail = new UncaughtExceptionHandler() {
+			public void uncaughtException(Thread thread, Throwable throwable) {
+				fail();
+			}
+		};
+		Thread.setDefaultUncaughtExceptionHandler(fail);
+	}
+}
diff --git a/test/net/sf/briar/LockFairnessTest.java b/test/net/sf/briar/LockFairnessTest.java
index e72c605e0594b851e0af1ff90348447f1659198b..7a798d40d9c8b2c2178e1cf2858630a94e964978 100644
--- a/test/net/sf/briar/LockFairnessTest.java
+++ b/test/net/sf/briar/LockFairnessTest.java
@@ -4,12 +4,10 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import junit.framework.TestCase;
-
 import org.junit.After;
 import org.junit.Test;
 
-public class LockFairnessTest extends TestCase {
+public class LockFairnessTest extends BriarTestCase {
 
 	private final ReentrantReadWriteLock lock =
 		new ReentrantReadWriteLock(true); // Fair
diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java
index 43590eec301c247abb0ff8b1db57869a52cc4b24..49f334c30f8006174c08b1de87373d417f641704 100644
--- a/test/net/sf/briar/ProtocolIntegrationTest.java
+++ b/test/net/sf/briar/ProtocolIntegrationTest.java
@@ -17,7 +17,6 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Random;
 
-import junit.framework.TestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.Author;
@@ -60,7 +59,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ProtocolIntegrationTest extends TestCase {
+public class ProtocolIntegrationTest extends BriarTestCase {
 
 	private final BatchId ack = new BatchId(TestUtils.getRandomId());
 	private final long timestamp = System.currentTimeMillis();
diff --git a/test/net/sf/briar/crypto/CounterModeTest.java b/test/net/sf/briar/crypto/CounterModeTest.java
index ff664429db30fbc03253ad8f65dc0ff34654cba1..d9f7131b672b8aa461975ad40aaf09a6bf47a8e9 100644
--- a/test/net/sf/briar/crypto/CounterModeTest.java
+++ b/test/net/sf/briar/crypto/CounterModeTest.java
@@ -10,13 +10,13 @@ import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.Bytes;
 
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.junit.Test;
 
-public class CounterModeTest extends TestCase {
+public class CounterModeTest extends BriarTestCase {
 
 	private static final String CIPHER_ALGO = "AES";
 	private static final String CIPHER_MODE = "AES/CTR/NoPadding";
diff --git a/test/net/sf/briar/crypto/ErasableKeyTest.java b/test/net/sf/briar/crypto/ErasableKeyTest.java
index 72f78b19534f9783397d8dd41bc1c38abdeeff22..37e4f82675a381bd1de7d59d08f01732e784a000 100644
--- a/test/net/sf/briar/crypto/ErasableKeyTest.java
+++ b/test/net/sf/briar/crypto/ErasableKeyTest.java
@@ -8,12 +8,12 @@ import javax.crypto.Cipher;
 import javax.crypto.Mac;
 import javax.crypto.spec.IvParameterSpec;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.crypto.ErasableKey;
 
 import org.junit.Test;
 
-public class ErasableKeyTest extends TestCase {
+public class ErasableKeyTest extends BriarTestCase {
 
 	private static final String CIPHER = "AES";
 	private static final String CIPHER_MODE = "AES/CTR/NoPadding";
diff --git a/test/net/sf/briar/crypto/KeyDerivationTest.java b/test/net/sf/briar/crypto/KeyDerivationTest.java
index 22bb5922963caac6c1502619dc536d08e8ba13be..b777cd7921491bafd8a483db0a65d9b8bec5b803 100644
--- a/test/net/sf/briar/crypto/KeyDerivationTest.java
+++ b/test/net/sf/briar/crypto/KeyDerivationTest.java
@@ -5,14 +5,14 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.ErasableKey;
 import net.sf.briar.api.protocol.ProtocolConstants;
 
 import org.junit.Test;
 
-public class KeyDerivationTest extends TestCase {
+public class KeyDerivationTest extends BriarTestCase {
 
 	private final CryptoComponent crypto;
 	private final byte[] secret;
diff --git a/test/net/sf/briar/db/BasicH2Test.java b/test/net/sf/briar/db/BasicH2Test.java
index f9ddbc93e5f034089ed7be8dc427e01a63bf4752..c21488ed4fa10ce9b87ffa13cd68669dc0da7afe 100644
--- a/test/net/sf/briar/db/BasicH2Test.java
+++ b/test/net/sf/briar/db/BasicH2Test.java
@@ -9,14 +9,14 @@ import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class BasicH2Test extends TestCase {
+public class BasicH2Test extends BriarTestCase {
 
 	private static final String CREATE_TABLE =
 		"CREATE TABLE foo"
diff --git a/test/net/sf/briar/db/DatabaseCleanerImplTest.java b/test/net/sf/briar/db/DatabaseCleanerImplTest.java
index 0ccf73824273b4293090514266188bc8b9d66a0f..9a79bc762cb8532bcf26a5c627dfda84691b00b9 100644
--- a/test/net/sf/briar/db/DatabaseCleanerImplTest.java
+++ b/test/net/sf/briar/db/DatabaseCleanerImplTest.java
@@ -3,13 +3,13 @@ package net.sf.briar.db;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.db.DbException;
 import net.sf.briar.db.DatabaseCleaner.Callback;
 
 import org.junit.Test;
 
-public class DatabaseCleanerImplTest extends TestCase {
+public class DatabaseCleanerImplTest extends BriarTestCase {
 
 	@Test
 	public void testStoppingCleanerWakesItUp() throws Exception {
diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java
index b196cfcd549cc39cd68d8f447fd0bc9e3e3eb64d..9b86bf2a3abf49398c6c35b542e16a1e146a39ff 100644
--- a/test/net/sf/briar/db/DatabaseComponentTest.java
+++ b/test/net/sf/briar/db/DatabaseComponentTest.java
@@ -8,7 +8,7 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.Rating;
@@ -47,7 +47,7 @@ import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.junit.Test;
 
-public abstract class DatabaseComponentTest extends TestCase {
+public abstract class DatabaseComponentTest extends BriarTestCase {
 
 	protected final Object txn = new Object();
 	protected final AuthorId authorId;
diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java
index 869963226fbe4b2d83c5c36db2dc3aab15ad2da0..6d8b812a9b3992575b992e646c3a0f89134f6121 100644
--- a/test/net/sf/briar/db/H2DatabaseTest.java
+++ b/test/net/sf/briar/db/H2DatabaseTest.java
@@ -16,7 +16,7 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestDatabaseModule;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
@@ -57,7 +57,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class H2DatabaseTest extends TestCase {
+public class H2DatabaseTest extends BriarTestCase {
 
 	private static final int ONE_MEGABYTE = 1024 * 1024;
 	private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
diff --git a/test/net/sf/briar/i18n/FontManagerTest.java b/test/net/sf/briar/i18n/FontManagerTest.java
index e3a123a87d809b5443b08fa2b3278237611160cf..a86c688c945d064fb75faf25902e12e7333a347c 100644
--- a/test/net/sf/briar/i18n/FontManagerTest.java
+++ b/test/net/sf/briar/i18n/FontManagerTest.java
@@ -3,13 +3,13 @@ import java.awt.Font;
 import java.io.File;
 import java.util.Locale;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.i18n.FontManager;
 
 import org.junit.Test;
 
-public class FontManagerTest extends TestCase {
+public class FontManagerTest extends BriarTestCase {
 
 	private final File fontDir = TestUtils.getFontDirectory();
 
diff --git a/test/net/sf/briar/i18n/I18nTest.java b/test/net/sf/briar/i18n/I18nTest.java
index 6545025a9a7e5fde0b65c343a076e5842db7edf5..d5f3f36a20257579eaf28758ce4813efc0b63883 100644
--- a/test/net/sf/briar/i18n/I18nTest.java
+++ b/test/net/sf/briar/i18n/I18nTest.java
@@ -5,7 +5,7 @@ import java.io.File;
 import java.io.IOException;
 import java.util.Locale;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.i18n.FontManager;
 import net.sf.briar.api.i18n.I18n;
@@ -16,7 +16,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class I18nTest extends TestCase {
+public class I18nTest extends BriarTestCase {
 
 	private final File base =
 		new File(TestUtils.getBuildDirectory(), "i18n.properties");
diff --git a/test/net/sf/briar/invitation/InvitationWorkerTest.java b/test/net/sf/briar/invitation/InvitationWorkerTest.java
index e6dc78b87dabc4f11386ac26be8b4e28cb1b96b6..6b960f9ef183e907fd8d900a3d7ff5a509f4ae79 100644
--- a/test/net/sf/briar/invitation/InvitationWorkerTest.java
+++ b/test/net/sf/briar/invitation/InvitationWorkerTest.java
@@ -8,7 +8,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
@@ -26,7 +26,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class InvitationWorkerTest extends TestCase {
+public class InvitationWorkerTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 
diff --git a/test/net/sf/briar/lifecycle/ShutdownManagerImplTest.java b/test/net/sf/briar/lifecycle/ShutdownManagerImplTest.java
index a7be414c9611dc1d21fb6a64bbd7d0f885be1e25..da38215693134803e6a1dd0e008f65a91756f938 100644
--- a/test/net/sf/briar/lifecycle/ShutdownManagerImplTest.java
+++ b/test/net/sf/briar/lifecycle/ShutdownManagerImplTest.java
@@ -3,12 +3,12 @@ package net.sf.briar.lifecycle;
 import java.util.HashSet;
 import java.util.Set;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.lifecycle.ShutdownManager;
 
 import org.junit.Test;
 
-public class ShutdownManagerImplTest extends TestCase {
+public class ShutdownManagerImplTest extends BriarTestCase {
 
 	@Test
 	public void testAddAndRemove() {
diff --git a/test/net/sf/briar/plugins/PluginManagerImplTest.java b/test/net/sf/briar/plugins/PluginManagerImplTest.java
index 47902f614e908bed30ea5086b511a9d184df34d9..3173f034498cba53fbd090c41c4f089c6118822e 100644
--- a/test/net/sf/briar/plugins/PluginManagerImplTest.java
+++ b/test/net/sf/briar/plugins/PluginManagerImplTest.java
@@ -1,10 +1,11 @@
 package net.sf.briar.plugins;
 
+import java.util.Collection;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.protocol.TransportId;
@@ -16,17 +17,20 @@ import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.junit.Test;
 
-public class PluginManagerImplTest extends TestCase {
+public class PluginManagerImplTest extends BriarTestCase {
 
+	@SuppressWarnings("unchecked")
 	@Test
 	public void testStartAndStop() throws Exception {
 		Mockery context = new Mockery();
 		final DatabaseComponent db = context.mock(DatabaseComponent.class);
+		final Poller poller = context.mock(Poller.class);
 		final ConnectionDispatcher dispatcher =
 			context.mock(ConnectionDispatcher.class);
 		final UiCallback uiCallback = context.mock(UiCallback.class);
 		final AtomicInteger index = new AtomicInteger(0);
 		context.checking(new Expectations() {{
+			oneOf(poller).startPolling(with(any(Collection.class)));
 			allowing(db).getLocalIndex(with(any(TransportId.class)));
 			will(returnValue(null));
 			allowing(db).addTransport(with(any(TransportId.class)));
@@ -37,10 +41,10 @@ public class PluginManagerImplTest extends TestCase {
 			will(returnValue(new TransportProperties()));
 			allowing(db).setLocalProperties(with(any(TransportId.class)),
 					with(any(TransportProperties.class)));
+			oneOf(poller).stopPolling();
 		}});
 		Executor executor = Executors.newCachedThreadPool();
-		Poller poller = new PollerImpl();
-		PluginManagerImpl p = new PluginManagerImpl(db, executor, poller,
+		PluginManagerImpl p = new PluginManagerImpl(executor, db, poller,
 				dispatcher, uiCallback);
 		// We expect either 2 or 3 plugins to be started, depending on whether
 		// the test machine has a Bluetooth device
diff --git a/test/net/sf/briar/plugins/file/LinuxRemovableDriveFinderTest.java b/test/net/sf/briar/plugins/file/LinuxRemovableDriveFinderTest.java
index 4a8a85b5d2d54279e24ee416b2f2ca398708bbc8..6634adc6577557ce1f18b6e64abcd01a27554102 100644
--- a/test/net/sf/briar/plugins/file/LinuxRemovableDriveFinderTest.java
+++ b/test/net/sf/briar/plugins/file/LinuxRemovableDriveFinderTest.java
@@ -1,10 +1,10 @@
 package net.sf.briar.plugins.file;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 
 import org.junit.Test;
 
-public class LinuxRemovableDriveFinderTest extends TestCase {
+public class LinuxRemovableDriveFinderTest extends BriarTestCase {
 
 	@Test
 	public void testParseMountPoint() {
diff --git a/test/net/sf/briar/plugins/file/MacRemovableDriveFinderTest.java b/test/net/sf/briar/plugins/file/MacRemovableDriveFinderTest.java
index 0b1848033a5171d11762a4f6e72fe577954a00ab..5b0fae4701e049704cdde5aedc95c68a19c930a2 100644
--- a/test/net/sf/briar/plugins/file/MacRemovableDriveFinderTest.java
+++ b/test/net/sf/briar/plugins/file/MacRemovableDriveFinderTest.java
@@ -1,10 +1,10 @@
 package net.sf.briar.plugins.file;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 
 import org.junit.Test;
 
-public class MacRemovableDriveFinderTest extends TestCase {
+public class MacRemovableDriveFinderTest extends BriarTestCase {
 
 	@Test
 	public void testParseMountPoint() {
diff --git a/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java b/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java
index 2d77dd4cc91f3739fd9df68a812bc303dde6b1e5..d8932519495b39557abc80a217326caba0848cab 100644
--- a/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java
+++ b/test/net/sf/briar/plugins/file/PollingRemovableDriveMonitorTest.java
@@ -9,15 +9,14 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.TestCase;
-
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback;
 
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.junit.Test;
 
-public class PollingRemovableDriveMonitorTest extends TestCase {
+public class PollingRemovableDriveMonitorTest extends BriarTestCase {
 
 	@Test
 	public void testOneCallbackPerFile() throws Exception {
diff --git a/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
index de912497271de7452ea361232446558d708762cd..3b07c80d3d76872a6c59384d9e78c7152c3c8bd5 100644
--- a/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
+++ b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
@@ -10,7 +10,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.plugins.BatchPluginCallback;
@@ -25,7 +25,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class RemovableDrivePluginTest extends TestCase {
+public class RemovableDrivePluginTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 	private final ContactId contactId = new ContactId(0);
diff --git a/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java b/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java
index c320968d0ed687067f30bd52f26d2afebe478192..fa1fb4e5eab598ffcd51f7d632cfb3b9f33f1e9f 100644
--- a/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java
+++ b/test/net/sf/briar/plugins/file/UnixRemovableDriveMonitorTest.java
@@ -6,7 +6,7 @@ import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback;
 import net.sf.briar.util.OsUtils;
@@ -15,7 +15,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class UnixRemovableDriveMonitorTest extends TestCase {
+public class UnixRemovableDriveMonitorTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 
diff --git a/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
index 7d82bf984c078ab47c907e709c547aa417826195..238a53152010b4b2b67abd48644ed86659f9f02f 100644
--- a/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
+++ b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
@@ -11,7 +11,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
@@ -20,7 +20,7 @@ import net.sf.briar.api.transport.StreamTransportConnection;
 
 import org.junit.Test;
 
-public class SimpleSocketPluginTest extends TestCase {
+public class SimpleSocketPluginTest extends BriarTestCase {
 
 	private final ContactId contactId = new ContactId(0);
 
diff --git a/test/net/sf/briar/protocol/AckReaderTest.java b/test/net/sf/briar/protocol/AckReaderTest.java
index 878718082f1bf49e1909a7ecff9da7623a53b218..255dc60a0697ad132761e3c169f572c5f2c270a0 100644
--- a/test/net/sf/briar/protocol/AckReaderTest.java
+++ b/test/net/sf/briar/protocol/AckReaderTest.java
@@ -4,7 +4,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.Collection;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.protocol.Ack;
@@ -25,7 +25,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class AckReaderTest extends TestCase {
+public class AckReaderTest extends BriarTestCase {
 
 	private final SerialComponent serial;
 	private final ReaderFactory readerFactory;
diff --git a/test/net/sf/briar/protocol/BatchReaderTest.java b/test/net/sf/briar/protocol/BatchReaderTest.java
index 4bd87ad252390bbc7dbd463d814ff957709fa8ab..e2eabf4ce311abdb36aaabc9cd717248f5cf1172 100644
--- a/test/net/sf/briar/protocol/BatchReaderTest.java
+++ b/test/net/sf/briar/protocol/BatchReaderTest.java
@@ -5,7 +5,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Collections;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.Types;
@@ -24,7 +24,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class BatchReaderTest extends TestCase {
+public class BatchReaderTest extends BriarTestCase {
 
 	private final ReaderFactory readerFactory;
 	private final WriterFactory writerFactory;
diff --git a/test/net/sf/briar/protocol/ConstantsTest.java b/test/net/sf/briar/protocol/ConstantsTest.java
index 2d02098f0754456f7b88d985aae74c712e103efd..29316c9e2be368803930ce8620208a51309be8d6 100644
--- a/test/net/sf/briar/protocol/ConstantsTest.java
+++ b/test/net/sf/briar/protocol/ConstantsTest.java
@@ -19,7 +19,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.Ack;
@@ -50,7 +50,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ConstantsTest extends TestCase {
+public class ConstantsTest extends BriarTestCase {
 
 	private final CryptoComponent crypto;
 	private final GroupFactory groupFactory;
diff --git a/test/net/sf/briar/protocol/ConsumersTest.java b/test/net/sf/briar/protocol/ConsumersTest.java
index e09595edfa3dab377470ae8822059efd37c39c33..095e792966582a44b9f875792b0893f3a3038f7b 100644
--- a/test/net/sf/briar/protocol/ConsumersTest.java
+++ b/test/net/sf/briar/protocol/ConsumersTest.java
@@ -4,7 +4,7 @@ import static org.junit.Assert.assertArrayEquals;
 
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.MessageDigest;
@@ -19,7 +19,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ConsumersTest extends TestCase {
+public class ConsumersTest extends BriarTestCase {
 
 	private CryptoComponent crypto = null;
 
diff --git a/test/net/sf/briar/protocol/OfferReaderTest.java b/test/net/sf/briar/protocol/OfferReaderTest.java
index 6c25e129d3beea40b3c7b9e9bc593158e0bdb2ba..92067e18fe79dc2008f72e1444490f9676833d9a 100644
--- a/test/net/sf/briar/protocol/OfferReaderTest.java
+++ b/test/net/sf/briar/protocol/OfferReaderTest.java
@@ -4,7 +4,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.Collection;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.protocol.Offer;
@@ -25,7 +25,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class OfferReaderTest extends TestCase {
+public class OfferReaderTest extends BriarTestCase {
 
 	private final SerialComponent serial;
 	private final ReaderFactory readerFactory;
diff --git a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java
index d74d910814539a4c1f89a1e55da5b907a785d417..3f2e6a00afa1652c96489a6cb47283a59dd39d53 100644
--- a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java
+++ b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java
@@ -7,7 +7,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.Batch;
@@ -37,7 +37,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ProtocolReadWriteTest extends TestCase {
+public class ProtocolReadWriteTest extends BriarTestCase {
 
 	private final ProtocolReaderFactory readerFactory;
 	private final ProtocolWriterFactory writerFactory;
diff --git a/test/net/sf/briar/protocol/ProtocolWriterImplTest.java b/test/net/sf/briar/protocol/ProtocolWriterImplTest.java
index fa1139e85945a63aec0580c536ce4cc8d10f4107..35bdb40c872a261041d777f688d7957a466f7bf2 100644
--- a/test/net/sf/briar/protocol/ProtocolWriterImplTest.java
+++ b/test/net/sf/briar/protocol/ProtocolWriterImplTest.java
@@ -4,7 +4,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.BitSet;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.protocol.PacketFactory;
 import net.sf.briar.api.protocol.ProtocolWriter;
 import net.sf.briar.api.protocol.Request;
@@ -19,7 +19,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ProtocolWriterImplTest extends TestCase {
+public class ProtocolWriterImplTest extends BriarTestCase {
 
 	private final PacketFactory packetFactory;
 	private final SerialComponent serial;
diff --git a/test/net/sf/briar/protocol/RequestReaderTest.java b/test/net/sf/briar/protocol/RequestReaderTest.java
index b972fba13231e8a70a2e39aeea42ec723d4ca66a..f241d13dac90e457786c5314d16b3a85092a8435 100644
--- a/test/net/sf/briar/protocol/RequestReaderTest.java
+++ b/test/net/sf/briar/protocol/RequestReaderTest.java
@@ -4,7 +4,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.BitSet;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.protocol.PacketFactory;
 import net.sf.briar.api.protocol.ProtocolConstants;
@@ -24,7 +24,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class RequestReaderTest extends TestCase {
+public class RequestReaderTest extends BriarTestCase {
 
 	private final ReaderFactory readerFactory;
 	private final WriterFactory writerFactory;
diff --git a/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java b/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java
index c0924c22ab2a2dd4f8d48cb25c734d626e7f567c..a1540b75fa4b9f0dc8a48372fd2d822e3048c61a 100644
--- a/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java
+++ b/test/net/sf/briar/protocol/UnverifiedBatchImplTest.java
@@ -8,7 +8,7 @@ import java.util.Collection;
 import java.util.Iterator;
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.MessageDigest;
@@ -30,7 +30,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class UnverifiedBatchImplTest extends TestCase {
+public class UnverifiedBatchImplTest extends BriarTestCase {
 
 	private final CryptoComponent crypto;
 	private final byte[] raw, raw1;
diff --git a/test/net/sf/briar/protocol/batch/BatchConnectionReadWriteTest.java b/test/net/sf/briar/protocol/batch/BatchConnectionReadWriteTest.java
index d2916e7bda75393e7cc458039c5c59e073f75ec3..c695a26634f69c3776a0a60da2d1a7e30bc22546 100644
--- a/test/net/sf/briar/protocol/batch/BatchConnectionReadWriteTest.java
+++ b/test/net/sf/briar/protocol/batch/BatchConnectionReadWriteTest.java
@@ -9,7 +9,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestDatabaseModule;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
@@ -28,6 +28,7 @@ import net.sf.briar.api.protocol.TransportUpdate;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
 import net.sf.briar.api.transport.ConnectionRecogniser;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.db.DatabaseModule;
@@ -45,7 +46,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class BatchConnectionReadWriteTest extends TestCase {
+public class BatchConnectionReadWriteTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 	private final File aliceDir = new File(testDir, "alice");
@@ -107,6 +108,8 @@ public class BatchConnectionReadWriteTest extends TestCase {
 		db.addLocalPrivateMessage(message, contactId);
 		// Create an outgoing batch connection
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		ConnectionRegistry connRegistry =
+			alice.getInstance(ConnectionRegistry.class);
 		ConnectionWriterFactory connFactory =
 			alice.getInstance(ConnectionWriterFactory.class);
 		ProtocolWriterFactory protoFactory =
@@ -114,8 +117,8 @@ public class BatchConnectionReadWriteTest extends TestCase {
 		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
 				Long.MAX_VALUE, false);
 		OutgoingBatchConnection batchOut = new OutgoingBatchConnection(db,
-				connFactory, protoFactory, contactId, transportIndex,
-				transport);
+				connRegistry, connFactory, protoFactory, contactId, transportId,
+				transportIndex, transport);
 		// Write whatever needs to be written
 		batchOut.write();
 		assertTrue(transport.getDisposed());
@@ -161,6 +164,8 @@ public class BatchConnectionReadWriteTest extends TestCase {
 		assertEquals(contactId, ctx.getContactId());
 		assertEquals(transportIndex, ctx.getTransportIndex());
 		// Create an incoming batch connection
+		ConnectionRegistry connRegistry =
+			bob.getInstance(ConnectionRegistry.class);
 		ConnectionReaderFactory connFactory =
 			bob.getInstance(ConnectionReaderFactory.class);
 		ProtocolReaderFactory protoFactory =
@@ -168,7 +173,8 @@ public class BatchConnectionReadWriteTest extends TestCase {
 		TestBatchTransportReader transport = new TestBatchTransportReader(in);
 		IncomingBatchConnection batchIn = new IncomingBatchConnection(
 				new ImmediateExecutor(), new ImmediateExecutor(), db,
-				connFactory, protoFactory, ctx, transport, tag);
+				connRegistry, connFactory, protoFactory, ctx, transportId,
+				transport, tag);
 		// No messages should have been added yet
 		assertFalse(listener.messagesAdded);
 		// Read whatever needs to be read
diff --git a/test/net/sf/briar/protocol/batch/OutgoingBatchConnectionTest.java b/test/net/sf/briar/protocol/batch/OutgoingBatchConnectionTest.java
index 7fbf325b6625adf0f98a1f4446ecab2831f341d3..a4b3bbfeced81459a37b0b0f4820b4b9d7f8098b 100644
--- a/test/net/sf/briar/protocol/batch/OutgoingBatchConnectionTest.java
+++ b/test/net/sf/briar/protocol/batch/OutgoingBatchConnectionTest.java
@@ -5,7 +5,7 @@ import java.util.Collections;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.db.DatabaseComponent;
@@ -15,9 +15,11 @@ import net.sf.briar.api.protocol.BatchId;
 import net.sf.briar.api.protocol.ProtocolConstants;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
 import net.sf.briar.api.protocol.RawBatch;
+import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.protocol.UniqueId;
 import net.sf.briar.api.transport.ConnectionContext;
+import net.sf.briar.api.transport.ConnectionRegistry;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.api.transport.TransportConstants;
 import net.sf.briar.crypto.CryptoModule;
@@ -35,13 +37,15 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Module;
 
-public class OutgoingBatchConnectionTest extends TestCase {
+public class OutgoingBatchConnectionTest extends BriarTestCase {
 
 	private final Mockery context;
 	private final DatabaseComponent db;
+	private final ConnectionRegistry connRegistry;
 	private final ConnectionWriterFactory connFactory;
 	private final ProtocolWriterFactory protoFactory;
 	private final ContactId contactId;
+	private final TransportId transportId;
 	private final TransportIndex transportIndex;
 	private final byte[] secret;
 
@@ -62,9 +66,11 @@ public class OutgoingBatchConnectionTest extends TestCase {
 				new SerialModule(), new TransportModule(),
 				new ProtocolBatchModule(), new ProtocolModule(),
 				new ProtocolStreamModule());
+		connRegistry = i.getInstance(ConnectionRegistry.class);
 		connFactory = i.getInstance(ConnectionWriterFactory.class);
 		protoFactory = i.getInstance(ProtocolWriterFactory.class);
 		contactId = new ContactId(1);
+		transportId = new TransportId(TestUtils.getRandomId());
 		transportIndex = new TransportIndex(13);
 		secret = new byte[32];
 	}
@@ -75,8 +81,8 @@ public class OutgoingBatchConnectionTest extends TestCase {
 		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
 				ProtocolConstants.MAX_PACKET_LENGTH, true);
 		OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
-				connFactory, protoFactory, contactId, transportIndex,
-				transport);
+				connRegistry, connFactory, protoFactory, contactId, transportId,
+				transportIndex, transport);
 		final ConnectionContext ctx = context.mock(ConnectionContext.class);
 		context.checking(new Expectations() {{
 			oneOf(db).getConnectionContext(contactId, transportIndex);
@@ -99,8 +105,8 @@ public class OutgoingBatchConnectionTest extends TestCase {
 		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
 				TransportConstants.MIN_CONNECTION_LENGTH, true);
 		OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
-				connFactory, protoFactory, contactId, transportIndex,
-				transport);
+				connRegistry, connFactory, protoFactory, contactId, transportId,
+				transportIndex, transport);
 		final ConnectionContext ctx = context.mock(ConnectionContext.class);
 		context.checking(new Expectations() {{
 			oneOf(db).getConnectionContext(contactId, transportIndex);
@@ -135,8 +141,8 @@ public class OutgoingBatchConnectionTest extends TestCase {
 		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
 				TransportConstants.MIN_CONNECTION_LENGTH, true);
 		OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
-				connFactory, protoFactory, contactId, transportIndex,
-				transport);
+				connRegistry, connFactory, protoFactory, contactId, transportId,
+				transportIndex, transport);
 		final ConnectionContext ctx = context.mock(ConnectionContext.class);
 		final Ack ack = context.mock(Ack.class);
 		final BatchId batchId = new BatchId(TestUtils.getRandomId());
diff --git a/test/net/sf/briar/serial/ReaderImplTest.java b/test/net/sf/briar/serial/ReaderImplTest.java
index 62bdd4e454134b8fc5ab20795b2175346ee4bbb3..1ba3d19048f17a07435ef6fc4876e0b4b5521f01 100644
--- a/test/net/sf/briar/serial/ReaderImplTest.java
+++ b/test/net/sf/briar/serial/ReaderImplTest.java
@@ -10,7 +10,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.Bytes;
 import net.sf.briar.api.FormatException;
 import net.sf.briar.api.serial.Consumer;
@@ -20,7 +20,7 @@ import net.sf.briar.util.StringUtils;
 
 import org.junit.Test;
 
-public class ReaderImplTest extends TestCase {
+public class ReaderImplTest extends BriarTestCase {
 
 	private ByteArrayInputStream in = null;
 	private ReaderImpl r = null;
diff --git a/test/net/sf/briar/serial/WriterImplTest.java b/test/net/sf/briar/serial/WriterImplTest.java
index 9cfb2881b0f8a3ec22470066d895bf73925da597..bfb697d6c47739be5d8f99fe37a9763e9d01d6e6 100644
--- a/test/net/sf/briar/serial/WriterImplTest.java
+++ b/test/net/sf/briar/serial/WriterImplTest.java
@@ -8,13 +8,13 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.util.StringUtils;
 
 import org.junit.Before;
 import org.junit.Test;
 
-public class WriterImplTest extends TestCase {
+public class WriterImplTest extends BriarTestCase {
 
 	private ByteArrayOutputStream out = null;
 	private WriterImpl w = null;
diff --git a/test/net/sf/briar/setup/SetupWorkerTest.java b/test/net/sf/briar/setup/SetupWorkerTest.java
index 5300bc87646e19e940690be6e94f1ef7958b0bf9..f5b8d77f1226aad19563b76206ba65bcb7a8bc91 100644
--- a/test/net/sf/briar/setup/SetupWorkerTest.java
+++ b/test/net/sf/briar/setup/SetupWorkerTest.java
@@ -5,7 +5,7 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.zip.ZipOutputStream;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.i18n.I18n;
 import net.sf.briar.api.setup.SetupCallback;
@@ -18,7 +18,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class SetupWorkerTest extends TestCase {
+public class SetupWorkerTest extends BriarTestCase {
 
 	private static final int HEADER_SIZE = 1234;
 
diff --git a/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java b/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
index 086adca1ced2766195fdb66555f63902a1c21e40..524fd37146c12f66a5100c5667fb1358ae26d288 100644
--- a/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionDecrypterImplTest.java
@@ -7,7 +7,7 @@ import java.io.ByteArrayInputStream;
 import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.ErasableKey;
@@ -19,7 +19,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ConnectionDecrypterImplTest extends TestCase {
+public class ConnectionDecrypterImplTest extends BriarTestCase {
 
 	private static final int MAC_LENGTH = 32;
 
diff --git a/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java b/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
index 01f87b78101b28ec443c4167d31de1c8469d61e5..469c333cbd26f7a2339a0af5b1aa6c99faf6d01f 100644
--- a/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionEncrypterImplTest.java
@@ -7,7 +7,7 @@ import java.io.ByteArrayOutputStream;
 import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.ErasableKey;
 import net.sf.briar.crypto.CryptoModule;
@@ -17,7 +17,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ConnectionEncrypterImplTest extends TestCase {
+public class ConnectionEncrypterImplTest extends BriarTestCase {
 
 	private static final int MAC_LENGTH = 32;
 
diff --git a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
index be5482a6bd9c832db6a13c635e1a199c487a3b99..db8cc11ba3e5141075ecd7eb6051f6955a085cd0 100644
--- a/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionRecogniserImplTest.java
@@ -11,7 +11,7 @@ import java.util.concurrent.Executor;
 
 import javax.crypto.Cipher;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.crypto.CryptoComponent;
@@ -35,7 +35,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ConnectionRecogniserImplTest extends TestCase {
+public class ConnectionRecogniserImplTest extends BriarTestCase {
 
 	private final CryptoComponent crypto;
 	private final ContactId contactId;
diff --git a/test/net/sf/briar/transport/ConnectionRegistryImplTest.java b/test/net/sf/briar/transport/ConnectionRegistryImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef9fc87b98bb247031cb44678c8b428e97f6a1b4
--- /dev/null
+++ b/test/net/sf/briar/transport/ConnectionRegistryImplTest.java
@@ -0,0 +1,73 @@
+package net.sf.briar.transport;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import net.sf.briar.BriarTestCase;
+import net.sf.briar.TestUtils;
+import net.sf.briar.api.ContactId;
+import net.sf.briar.api.protocol.TransportId;
+import net.sf.briar.api.transport.ConnectionRegistry;
+
+import org.junit.Test;
+
+public class ConnectionRegistryImplTest extends BriarTestCase {
+
+	private final ContactId contactId, contactId1;
+	private final TransportId transportId, transportId1;
+
+	public ConnectionRegistryImplTest() {
+		super();
+		contactId = new ContactId(1);
+		contactId1 = new ContactId(2);
+		transportId = new TransportId(TestUtils.getRandomId());
+		transportId1 = new TransportId(TestUtils.getRandomId());
+	}
+
+	@Test
+	public void testRegisterAndUnregister() {
+		ConnectionRegistry c = new ConnectionRegistryImpl();
+		// The registry should be empty
+		assertEquals(Collections.emptyList(),
+				c.getConnectedContacts(transportId));
+		assertEquals(Collections.emptyList(),
+				c.getConnectedContacts(transportId1));
+		// Check that a registered connection shows up
+		c.registerConnection(contactId, transportId);
+		assertEquals(Collections.singletonList(contactId),
+				c.getConnectedContacts(transportId));
+		assertEquals(Collections.emptyList(),
+				c.getConnectedContacts(transportId1));
+		// Register an identical connection - lookup should be unaffected
+		c.registerConnection(contactId, transportId);
+		assertEquals(Collections.singletonList(contactId),
+				c.getConnectedContacts(transportId));
+		assertEquals(Collections.emptyList(),
+				c.getConnectedContacts(transportId1));
+		// Unregister one of the connections - lookup should be unaffected
+		c.unregisterConnection(contactId, transportId);
+		assertEquals(Collections.singletonList(contactId),
+				c.getConnectedContacts(transportId));
+		assertEquals(Collections.emptyList(),
+				c.getConnectedContacts(transportId1));
+		// Unregister the other connection - lookup should be affected
+		c.unregisterConnection(contactId, transportId);
+		assertEquals(Collections.emptyList(),
+				c.getConnectedContacts(transportId));
+		assertEquals(Collections.emptyList(),
+				c.getConnectedContacts(transportId1));
+		// Try to unregister the connection again - exception should be thrown
+		try {
+			c.unregisterConnection(contactId, transportId);
+			fail();
+		} catch(IllegalArgumentException expected) {}
+		// Register both contacts with one transport, one contact with both
+		c.registerConnection(contactId, transportId);
+		c.registerConnection(contactId1, transportId);
+		c.registerConnection(contactId1, transportId1);
+		assertEquals(Arrays.asList(new ContactId[] {contactId, contactId1}),
+				c.getConnectedContacts(transportId));
+		assertEquals(Collections.singletonList(contactId1),
+				c.getConnectedContacts(transportId1));
+	}
+}
diff --git a/test/net/sf/briar/transport/ConnectionWindowImplTest.java b/test/net/sf/briar/transport/ConnectionWindowImplTest.java
index c6511263f67e996dca0d3641c097fe8043899a92..61e253ca912143e5dd9004ef15208d8d649373c1 100644
--- a/test/net/sf/briar/transport/ConnectionWindowImplTest.java
+++ b/test/net/sf/briar/transport/ConnectionWindowImplTest.java
@@ -4,7 +4,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.TransportIndex;
 import net.sf.briar.api.transport.ConnectionWindow;
@@ -16,7 +16,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ConnectionWindowImplTest extends TestCase {
+public class ConnectionWindowImplTest extends BriarTestCase {
 
 	private final CryptoComponent crypto;
 	private final byte[] secret;
diff --git a/test/net/sf/briar/transport/ConnectionWriterTest.java b/test/net/sf/briar/transport/ConnectionWriterTest.java
index 0dc41851e556948806f9523360a869873e1c9aff..2121c19f1641945d86a1ad071c4d56a7a9aa93dd 100644
--- a/test/net/sf/briar/transport/ConnectionWriterTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterTest.java
@@ -6,7 +6,7 @@ import static net.sf.briar.api.transport.TransportConstants.MIN_CONNECTION_LENGT
 import java.io.ByteArrayOutputStream;
 import java.util.Random;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestDatabaseModule;
 import net.sf.briar.api.transport.ConnectionWriter;
 import net.sf.briar.api.transport.ConnectionWriterFactory;
@@ -23,7 +23,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class ConnectionWriterTest extends TestCase {
+public class ConnectionWriterTest extends BriarTestCase {
 
 	private final ConnectionWriterFactory connectionWriterFactory;
 	private final byte[] secret;
diff --git a/test/net/sf/briar/transport/FrameReadWriteTest.java b/test/net/sf/briar/transport/FrameReadWriteTest.java
index 4c71859f51f7d62a8c6fc361f7c24e7810631c71..7c374c9544eb2a31b5ec2a5383a5f2bd1ee8f74a 100644
--- a/test/net/sf/briar/transport/FrameReadWriteTest.java
+++ b/test/net/sf/briar/transport/FrameReadWriteTest.java
@@ -12,7 +12,7 @@ import java.util.Random;
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.ErasableKey;
 import net.sf.briar.api.transport.ConnectionReader;
@@ -24,7 +24,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class FrameReadWriteTest extends TestCase {
+public class FrameReadWriteTest extends BriarTestCase {
 
 	private final CryptoComponent crypto;
 	private final Cipher tagCipher, frameCipher;
diff --git a/test/net/sf/briar/transport/TransportTest.java b/test/net/sf/briar/transport/TransportTest.java
index c833b677ff86a4dbfd89f66b6233cc8614427cd2..a4f81d10c00ba6315927420286276a2ba51c9ea2 100644
--- a/test/net/sf/briar/transport/TransportTest.java
+++ b/test/net/sf/briar/transport/TransportTest.java
@@ -5,7 +5,7 @@ import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
 
 import javax.crypto.Mac;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.crypto.ErasableKey;
 import net.sf.briar.crypto.CryptoModule;
@@ -13,7 +13,7 @@ import net.sf.briar.crypto.CryptoModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public abstract class TransportTest extends TestCase {
+public abstract class TransportTest extends BriarTestCase {
 
 	protected final Mac mac;
 	protected final ErasableKey macKey;
diff --git a/test/net/sf/briar/util/ByteUtilsTest.java b/test/net/sf/briar/util/ByteUtilsTest.java
index 3b850e8b197199b490810b75efbd7216be6348dc..0c0334697204395197cd6e021f95280ec417592f 100644
--- a/test/net/sf/briar/util/ByteUtilsTest.java
+++ b/test/net/sf/briar/util/ByteUtilsTest.java
@@ -1,10 +1,10 @@
 package net.sf.briar.util;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 
 import org.junit.Test;
 
-public class ByteUtilsTest extends TestCase {
+public class ByteUtilsTest extends BriarTestCase {
 
 	@Test
 	public void testReadUint16() {
diff --git a/test/net/sf/briar/util/FileUtilsTest.java b/test/net/sf/briar/util/FileUtilsTest.java
index 70e14c0f2d01b291c087b9f60e32d72da06baf8f..251d78a6e8aec8ce28c5779972237dac8832ab80 100644
--- a/test/net/sf/briar/util/FileUtilsTest.java
+++ b/test/net/sf/briar/util/FileUtilsTest.java
@@ -6,7 +6,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.Scanner;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.util.FileUtils.Callback;
 
@@ -16,7 +16,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class FileUtilsTest extends TestCase {
+public class FileUtilsTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 
diff --git a/test/net/sf/briar/util/StringUtilsTest.java b/test/net/sf/briar/util/StringUtilsTest.java
index a47125a2451824cea2b8508fb4796f920e3b40f4..d4465e062e688152ccae97c2cc9205085b7d19ce 100644
--- a/test/net/sf/briar/util/StringUtilsTest.java
+++ b/test/net/sf/briar/util/StringUtilsTest.java
@@ -1,11 +1,11 @@
 package net.sf.briar.util;
 
 import static org.junit.Assert.assertArrayEquals;
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 
 import org.junit.Test;
 
-public class StringUtilsTest extends TestCase {
+public class StringUtilsTest extends BriarTestCase {
 
 	@Test
 	public void testHead() {
diff --git a/test/net/sf/briar/util/ZipUtilsTest.java b/test/net/sf/briar/util/ZipUtilsTest.java
index 233222ad2408b28df50bd033bf31e15e81516760..c08d4a3700f407c5fe55a9e4ec4285f0752bd0b5 100644
--- a/test/net/sf/briar/util/ZipUtilsTest.java
+++ b/test/net/sf/briar/util/ZipUtilsTest.java
@@ -13,7 +13,7 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
-import junit.framework.TestCase;
+import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.util.ZipUtils.Callback;
 
@@ -23,7 +23,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-public class ZipUtilsTest extends TestCase {
+public class ZipUtilsTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();