diff --git a/api/net/sf/briar/api/plugins/BatchPlugin.java b/api/net/sf/briar/api/plugins/BatchPlugin.java
deleted file mode 100644
index 26d41bd48741d5c334d6820b20b8f2cb5d9c7ec7..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/plugins/BatchPlugin.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package net.sf.briar.api.plugins;
-
-import net.sf.briar.api.ContactId;
-import net.sf.briar.api.transport.BatchTransportReader;
-import net.sf.briar.api.transport.BatchTransportWriter;
-
-/**
- * An interface for transport plugins that do not support bidirectional,
- * reliable, ordered, timely delivery of data.
- */
-public interface BatchPlugin extends Plugin {
-
-	/**
-	 * Attempts to create and return a BatchTransportReader for the given
-	 * contact using the current transport and configuration properties.
-	 * Returns null if a reader could not be created.
-	 */
-	BatchTransportReader createReader(ContactId c);
-
-	/**
-	 * Attempts to create and return a BatchTransportWriter for the given
-	 * contact using the current transport and configuration properties.
-	 * Returns null if a writer could not be created.
-	 */
-	BatchTransportWriter createWriter(ContactId c);
-
-	/**
-	 * Starts the invitation process from the inviter's side. Returns null if
-	 * no connection can be established within the given timeout.
-	 */
-	BatchTransportWriter sendInvitation(int code, long timeout);
-
-	/**
-	 * Starts the invitation process from the invitee's side. Returns null if
-	 * no connection can be established within the given timeout.
-	 */
-	BatchTransportReader acceptInvitation(int code, long timeout);
-
-	/**
-	 * Continues the invitation process from the invitee's side. Returns null
-	 * if no connection can be established within the given timeout.
-	 */
-	BatchTransportWriter sendInvitationResponse(int code, long timeout);
-
-	/**
-	 * Continues the invitation process from the inviter's side. Returns null
-	 * if no connection can be established within the given timeout.
-	 */
-	BatchTransportReader acceptInvitationResponse(int code, long timeout);
-}
diff --git a/api/net/sf/briar/api/plugins/BatchPluginCallback.java b/api/net/sf/briar/api/plugins/BatchPluginCallback.java
deleted file mode 100644
index 8aae562002aaa8f2699aa1bcd74b7f1730cb80d1..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/plugins/BatchPluginCallback.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package net.sf.briar.api.plugins;
-
-import net.sf.briar.api.ContactId;
-import net.sf.briar.api.transport.BatchTransportReader;
-import net.sf.briar.api.transport.BatchTransportWriter;
-
-/**
- * An interface for receiving readers and writers created by a batch-mode
- * transport plugin.
- */
-public interface BatchPluginCallback extends PluginCallback {
-
-	void readerCreated(BatchTransportReader r);
-
-	void writerCreated(ContactId c, BatchTransportWriter w);
-}
diff --git a/api/net/sf/briar/api/plugins/BatchPluginFactory.java b/api/net/sf/briar/api/plugins/BatchPluginFactory.java
deleted file mode 100644
index d0d1be9fbd46dbb3b55d494f8e1f98c28669595e..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/plugins/BatchPluginFactory.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.sf.briar.api.plugins;
-
-import java.util.concurrent.Executor;
-
-public interface BatchPluginFactory {
-
-	BatchPlugin createPlugin(Executor pluginExecutor,
-			BatchPluginCallback callback);
-}
diff --git a/api/net/sf/briar/api/plugins/DuplexPlugin.java b/api/net/sf/briar/api/plugins/DuplexPlugin.java
new file mode 100644
index 0000000000000000000000000000000000000000..45656e4023092d4c50acee936fa5fef53da03c65
--- /dev/null
+++ b/api/net/sf/briar/api/plugins/DuplexPlugin.java
@@ -0,0 +1,26 @@
+package net.sf.briar.api.plugins;
+
+import net.sf.briar.api.ContactId;
+
+/**  An interface for transport plugins that support duplex communication. */
+public interface DuplexPlugin extends Plugin {
+
+	/**
+	 * Attempts to create and return a connection to the given contact using
+	 * the current transport and configuration properties. Returns null if a
+	 * connection could not be created.
+	 */
+	DuplexTransportConnection createConnection(ContactId c);
+
+	/**
+	 * Starts the invitation process from the inviter's side. Returns null if
+	 * no connection can be established within the given timeout.
+	 */
+	DuplexTransportConnection sendInvitation(int code, long timeout);
+
+	/**
+	 * Starts the invitation process from the invitee's side. Returns null if
+	 * no connection can be established within the given timeout.
+	 */
+	DuplexTransportConnection acceptInvitation(int code, long timeout);
+}
diff --git a/api/net/sf/briar/api/plugins/DuplexPluginCallback.java b/api/net/sf/briar/api/plugins/DuplexPluginCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c240a2d2e1ce3c44ea7ae6dfe6f632545631abd
--- /dev/null
+++ b/api/net/sf/briar/api/plugins/DuplexPluginCallback.java
@@ -0,0 +1,13 @@
+package net.sf.briar.api.plugins;
+
+import net.sf.briar.api.ContactId;
+
+/**
+ * An interface for receiving connections created by a duplex transport plugin.
+ */
+public interface DuplexPluginCallback extends PluginCallback {
+
+	void incomingConnectionCreated(DuplexTransportConnection d);
+
+	void outgoingConnectionCreated(ContactId c, DuplexTransportConnection d);
+}
diff --git a/api/net/sf/briar/api/plugins/DuplexPluginFactory.java b/api/net/sf/briar/api/plugins/DuplexPluginFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..25159e41b8a98fb681c3a06b8545524a982c86ab
--- /dev/null
+++ b/api/net/sf/briar/api/plugins/DuplexPluginFactory.java
@@ -0,0 +1,9 @@
+package net.sf.briar.api.plugins;
+
+import java.util.concurrent.Executor;
+
+public interface DuplexPluginFactory {
+
+	DuplexPlugin createPlugin(Executor pluginExecutor,
+			DuplexPluginCallback callback);
+}
diff --git a/api/net/sf/briar/api/transport/StreamTransportConnection.java b/api/net/sf/briar/api/plugins/DuplexTransportConnection.java
similarity index 84%
rename from api/net/sf/briar/api/transport/StreamTransportConnection.java
rename to api/net/sf/briar/api/plugins/DuplexTransportConnection.java
index 528341541775a45974ee1d666bd05d6a9298eb0c..8f03d8b9bbd8e5352e964073f4faa205574450f9 100644
--- a/api/net/sf/briar/api/transport/StreamTransportConnection.java
+++ b/api/net/sf/briar/api/plugins/DuplexTransportConnection.java
@@ -1,15 +1,15 @@
-package net.sf.briar.api.transport;
+package net.sf.briar.api.plugins;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
 /**
- * An interface for reading and writing data over a stream-mode transport. The
+ * An interface for reading and writing data over a duplex transport. The
  * connection is not responsible for encrypting/decrypting or authenticating
  * the data.
  */
-public interface StreamTransportConnection {
+public interface DuplexTransportConnection {
 
 	/** Returns an input stream for reading from the connection. */
 	InputStream getInputStream() throws IOException;
diff --git a/api/net/sf/briar/api/plugins/SimplexPlugin.java b/api/net/sf/briar/api/plugins/SimplexPlugin.java
new file mode 100644
index 0000000000000000000000000000000000000000..c59553d069199b671abe47ff4cff247b4e97bb49
--- /dev/null
+++ b/api/net/sf/briar/api/plugins/SimplexPlugin.java
@@ -0,0 +1,45 @@
+package net.sf.briar.api.plugins;
+
+import net.sf.briar.api.ContactId;
+
+/** An interface for transport plugins that support simplex communication. */
+public interface SimplexPlugin extends Plugin {
+
+	/**
+	 * Attempts to create and return a reader for the given contact using the
+	 * current transport and configuration properties. Returns null if a reader
+	 * could not be created.
+	 */
+	SimplexTransportReader createReader(ContactId c);
+
+	/**
+	 * Attempts to create and return a writer for the given contact using the
+	 * current transport and configuration properties. Returns null if a writer
+	 * could not be created.
+	 */
+	SimplexTransportWriter createWriter(ContactId c);
+
+	/**
+	 * Starts the invitation process from the inviter's side. Returns null if
+	 * no connection can be established within the given timeout.
+	 */
+	SimplexTransportWriter sendInvitation(int code, long timeout);
+
+	/**
+	 * Starts the invitation process from the invitee's side. Returns null if
+	 * no connection can be established within the given timeout.
+	 */
+	SimplexTransportReader acceptInvitation(int code, long timeout);
+
+	/**
+	 * Continues the invitation process from the invitee's side. Returns null
+	 * if no connection can be established within the given timeout.
+	 */
+	SimplexTransportWriter sendInvitationResponse(int code, long timeout);
+
+	/**
+	 * Continues the invitation process from the inviter's side. Returns null
+	 * if no connection can be established within the given timeout.
+	 */
+	SimplexTransportReader acceptInvitationResponse(int code, long timeout);
+}
diff --git a/api/net/sf/briar/api/plugins/SimplexPluginCallback.java b/api/net/sf/briar/api/plugins/SimplexPluginCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..6c52a9bb6def6c1b6a7c1e0f731ed1d14dcaaf56
--- /dev/null
+++ b/api/net/sf/briar/api/plugins/SimplexPluginCallback.java
@@ -0,0 +1,13 @@
+package net.sf.briar.api.plugins;
+
+import net.sf.briar.api.ContactId;
+
+/**
+ * An interface for receiving readers and writers created by a simplex plugin.
+ */
+public interface SimplexPluginCallback extends PluginCallback {
+
+	void readerCreated(SimplexTransportReader r);
+
+	void writerCreated(ContactId c, SimplexTransportWriter w);
+}
diff --git a/api/net/sf/briar/api/plugins/SimplexPluginFactory.java b/api/net/sf/briar/api/plugins/SimplexPluginFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..d007f1b336e160df3c6458a9a29abd45dad8d19f
--- /dev/null
+++ b/api/net/sf/briar/api/plugins/SimplexPluginFactory.java
@@ -0,0 +1,9 @@
+package net.sf.briar.api.plugins;
+
+import java.util.concurrent.Executor;
+
+public interface SimplexPluginFactory {
+
+	SimplexPlugin createPlugin(Executor pluginExecutor,
+			SimplexPluginCallback callback);
+}
diff --git a/api/net/sf/briar/api/transport/BatchTransportReader.java b/api/net/sf/briar/api/plugins/SimplexTransportReader.java
similarity index 78%
rename from api/net/sf/briar/api/transport/BatchTransportReader.java
rename to api/net/sf/briar/api/plugins/SimplexTransportReader.java
index c2a42a2ea47c79abab36d80aaab2adb9fb3f1acf..70e696eb7747e9c79e2d62f8d672ab4d4f861e63 100644
--- a/api/net/sf/briar/api/transport/BatchTransportReader.java
+++ b/api/net/sf/briar/api/plugins/SimplexTransportReader.java
@@ -1,12 +1,12 @@
-package net.sf.briar.api.transport;
+package net.sf.briar.api.plugins;
 
 import java.io.InputStream;
 
 /**
- * An interface for reading data from a batch-mode transport. The reader is not
+ * An interface for reading data from a simplex transport. The reader is not
  * responsible for decrypting or authenticating the data before returning it.
  */
-public interface BatchTransportReader {
+public interface SimplexTransportReader {
 
 	/** Returns an input stream for reading from the transport. */
 	InputStream getInputStream();
diff --git a/api/net/sf/briar/api/transport/BatchTransportWriter.java b/api/net/sf/briar/api/plugins/SimplexTransportWriter.java
similarity index 80%
rename from api/net/sf/briar/api/transport/BatchTransportWriter.java
rename to api/net/sf/briar/api/plugins/SimplexTransportWriter.java
index 0476543d47506271b0ba682c46f0fb2ada051b27..58071a7837b74ba214420ecb387cdd869bcee6d8 100644
--- a/api/net/sf/briar/api/transport/BatchTransportWriter.java
+++ b/api/net/sf/briar/api/plugins/SimplexTransportWriter.java
@@ -1,12 +1,12 @@
-package net.sf.briar.api.transport;
+package net.sf.briar.api.plugins;
 
 import java.io.OutputStream;
 
 /**
- * An interface for writing data to a batch-mode transport. The writer is not
+ * An interface for writing data to a simplex transport. The writer is not
  * responsible for authenticating or encrypting the data before writing it.
  */
-public interface BatchTransportWriter {
+public interface SimplexTransportWriter {
 
 	/** Returns the capacity of the transport in bytes. */
 	long getCapacity();
diff --git a/api/net/sf/briar/api/plugins/StreamPlugin.java b/api/net/sf/briar/api/plugins/StreamPlugin.java
deleted file mode 100644
index bceae8ec947a475f4fa3c534dd303747ac259a63..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/plugins/StreamPlugin.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package net.sf.briar.api.plugins;
-
-import net.sf.briar.api.ContactId;
-import net.sf.briar.api.transport.StreamTransportConnection;
-
-/**
- * An interface for transport plugins that support bidirectional, reliable,
- * ordered, timely delivery of data.
- */
-public interface StreamPlugin extends Plugin {
-
-	/**
-	 * Attempts to create and return a StreamTransportConnection to the given
-	 * contact using the current transport and configuration properties.
-	 * Returns null if a connection could not be created.
-	 */
-	StreamTransportConnection createConnection(ContactId c);
-
-	/**
-	 * Starts the invitation process from the inviter's side. Returns null if
-	 * no connection can be established within the given timeout.
-	 */
-	StreamTransportConnection sendInvitation(int code, long timeout);
-
-	/**
-	 * Starts the invitation process from the invitee's side. Returns null if
-	 * no connection can be established within the given timeout.
-	 */
-	StreamTransportConnection acceptInvitation(int code, long timeout);
-}
diff --git a/api/net/sf/briar/api/plugins/StreamPluginCallback.java b/api/net/sf/briar/api/plugins/StreamPluginCallback.java
deleted file mode 100644
index adabd8e17bf214da0d921b12892548f08fce1747..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/plugins/StreamPluginCallback.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.sf.briar.api.plugins;
-
-import net.sf.briar.api.ContactId;
-import net.sf.briar.api.transport.StreamTransportConnection;
-
-/**
- * An interface for receiving connections created by a stream-mode transport
- * plugin.
- */
-public interface StreamPluginCallback extends PluginCallback {
-
-	void incomingConnectionCreated(StreamTransportConnection s);
-
-	void outgoingConnectionCreated(ContactId c, StreamTransportConnection s);
-}
diff --git a/api/net/sf/briar/api/plugins/StreamPluginFactory.java b/api/net/sf/briar/api/plugins/StreamPluginFactory.java
deleted file mode 100644
index 7102305704023f8ff3fd7adf9217bc23b37bb66b..0000000000000000000000000000000000000000
--- a/api/net/sf/briar/api/plugins/StreamPluginFactory.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.sf.briar.api.plugins;
-
-import java.util.concurrent.Executor;
-
-public interface StreamPluginFactory {
-
-	StreamPlugin createPlugin(Executor pluginExecutor,
-			StreamPluginCallback callback);
-}
diff --git a/api/net/sf/briar/api/protocol/stream/StreamConnectionFactory.java b/api/net/sf/briar/api/protocol/duplex/DuplexConnectionFactory.java
similarity index 59%
rename from api/net/sf/briar/api/protocol/stream/StreamConnectionFactory.java
rename to api/net/sf/briar/api/protocol/duplex/DuplexConnectionFactory.java
index 5b371c9147e3b1572b768dfc4b3f58a5187f9cbc..0b79f4211edb6982508500025b81dc680241d71f 100644
--- a/api/net/sf/briar/api/protocol/stream/StreamConnectionFactory.java
+++ b/api/net/sf/briar/api/protocol/duplex/DuplexConnectionFactory.java
@@ -1,16 +1,16 @@
-package net.sf.briar.api.protocol.stream;
+package net.sf.briar.api.protocol.duplex;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 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 {
+public interface DuplexConnectionFactory {
 
 	void createIncomingConnection(ConnectionContext ctx, TransportId t,
-			StreamTransportConnection s, byte[] tag);
+			DuplexTransportConnection d, byte[] tag);
 
 	void createOutgoingConnection(ContactId c, TransportId t, TransportIndex i,
-			StreamTransportConnection s);
+			DuplexTransportConnection d);
 }
diff --git a/api/net/sf/briar/api/protocol/batch/BatchConnectionFactory.java b/api/net/sf/briar/api/protocol/simplex/SimplexConnectionFactory.java
similarity index 55%
rename from api/net/sf/briar/api/protocol/batch/BatchConnectionFactory.java
rename to api/net/sf/briar/api/protocol/simplex/SimplexConnectionFactory.java
index 7f581ff8c17094fdc6487fe7fd8b8e660e69968b..1fa1f30c27bafab098f116967a71482ae60a1b5a 100644
--- a/api/net/sf/briar/api/protocol/batch/BatchConnectionFactory.java
+++ b/api/net/sf/briar/api/protocol/simplex/SimplexConnectionFactory.java
@@ -1,17 +1,17 @@
-package net.sf.briar.api.protocol.batch;
+package net.sf.briar.api.protocol.simplex;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.plugins.SimplexTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 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;
 import net.sf.briar.api.transport.ConnectionContext;
 
-public interface BatchConnectionFactory {
+public interface SimplexConnectionFactory {
 
 	void createIncomingConnection(ConnectionContext ctx, TransportId t,
-			BatchTransportReader r, byte[] tag);
+			SimplexTransportReader r, byte[] tag);
 
 	void createOutgoingConnection(ContactId c, TransportId t, TransportIndex i,
-			BatchTransportWriter w);
+			SimplexTransportWriter w);
 }
diff --git a/api/net/sf/briar/api/transport/ConnectionDispatcher.java b/api/net/sf/briar/api/transport/ConnectionDispatcher.java
index 81c26abfadac6eded98baf25ede6831907c22e75..d75a3ad684540e723866f1250733332930d8a675 100644
--- a/api/net/sf/briar/api/transport/ConnectionDispatcher.java
+++ b/api/net/sf/briar/api/transport/ConnectionDispatcher.java
@@ -1,18 +1,21 @@
 package net.sf.briar.api.transport;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.plugins.SimplexTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
 
 public interface ConnectionDispatcher {
 
-	void dispatchReader(TransportId t, BatchTransportReader r);
+	void dispatchReader(TransportId t, SimplexTransportReader r);
 
 	void dispatchWriter(ContactId c, TransportId t, TransportIndex i,
-			BatchTransportWriter w);
+			SimplexTransportWriter w);
 
-	void dispatchIncomingConnection(TransportId t, StreamTransportConnection s);
+	void dispatchIncomingConnection(TransportId t, DuplexTransportConnection d);
 
 	void dispatchOutgoingConnection(ContactId c, TransportId t,
-			TransportIndex i, StreamTransportConnection s);
+			TransportIndex i, DuplexTransportConnection d);
 }
diff --git a/components/net/sf/briar/plugins/PluginManagerImpl.java b/components/net/sf/briar/plugins/PluginManagerImpl.java
index bd4e198fe9a2e3bfe702c233447dc8f9267f067e..9276fcc096088eae440ff767d665a2967f218b22 100644
--- a/components/net/sf/briar/plugins/PluginManagerImpl.java
+++ b/components/net/sf/briar/plugins/PluginManagerImpl.java
@@ -16,23 +16,23 @@ import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
-import net.sf.briar.api.plugins.BatchPlugin;
-import net.sf.briar.api.plugins.BatchPluginCallback;
-import net.sf.briar.api.plugins.BatchPluginFactory;
+import net.sf.briar.api.plugins.SimplexPlugin;
+import net.sf.briar.api.plugins.SimplexPluginCallback;
+import net.sf.briar.api.plugins.SimplexPluginFactory;
+import net.sf.briar.api.plugins.SimplexTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 import net.sf.briar.api.plugins.Plugin;
 import net.sf.briar.api.plugins.PluginCallback;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.plugins.PluginManager;
-import net.sf.briar.api.plugins.StreamPlugin;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.plugins.StreamPluginFactory;
+import net.sf.briar.api.plugins.DuplexPlugin;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexPluginFactory;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.ProtocolConstants;
 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;
 import net.sf.briar.api.transport.ConnectionDispatcher;
-import net.sf.briar.api.transport.StreamTransportConnection;
 import net.sf.briar.api.ui.UiCallback;
 
 import com.google.inject.Inject;
@@ -42,11 +42,11 @@ class PluginManagerImpl implements PluginManager {
 	private static final Logger LOG =
 		Logger.getLogger(PluginManagerImpl.class.getName());
 
-	private static final String[] BATCH_FACTORIES = new String[] {
+	private static final String[] SIMPLEX_PLUGIN_FACTORIES = new String[] {
 		"net.sf.briar.plugins.file.RemovableDrivePluginFactory"
 	};
 
-	private static final String[] STREAM_FACTORIES = new String[] {
+	private static final String[] DUPLEX_PLUGIN_FACTORIES = new String[] {
 		"net.sf.briar.plugins.bluetooth.BluetoothPluginFactory",
 		"net.sf.briar.plugins.socket.SimpleSocketPluginFactory"
 	};
@@ -56,8 +56,8 @@ class PluginManagerImpl implements PluginManager {
 	private final Poller poller;
 	private final ConnectionDispatcher dispatcher;
 	private final UiCallback uiCallback;
-	private final List<BatchPlugin> batchPlugins; // Locking: this
-	private final List<StreamPlugin> streamPlugins; // Locking: this
+	private final List<SimplexPlugin> simplexPlugins; // Locking: this
+	private final List<DuplexPlugin> duplexPlugins; // Locking: this
 
 	@Inject
 	PluginManagerImpl(@PluginExecutor ExecutorService pluginExecutor,
@@ -68,24 +68,24 @@ class PluginManagerImpl implements PluginManager {
 		this.poller = poller;
 		this.dispatcher = dispatcher;
 		this.uiCallback = uiCallback;
-		batchPlugins = new ArrayList<BatchPlugin>();
-		streamPlugins = new ArrayList<StreamPlugin>();
+		simplexPlugins = new ArrayList<SimplexPlugin>();
+		duplexPlugins = new ArrayList<DuplexPlugin>();
 	}
 
 	public synchronized int getPluginCount() {
-		return batchPlugins.size() + streamPlugins.size();
+		return simplexPlugins.size() + duplexPlugins.size();
 	}
 
 	public synchronized int start() {
 		Set<TransportId> ids = new HashSet<TransportId>();
-		// Instantiate and start the batch plugins
-		for(String s : BATCH_FACTORIES) {
+		// Instantiate and start the simplex plugins
+		for(String s : SIMPLEX_PLUGIN_FACTORIES) {
 			try {
 				Class<?> c = Class.forName(s);
-				BatchPluginFactory factory =
-					(BatchPluginFactory) c.newInstance();
-				BatchCallback callback = new BatchCallback();
-				BatchPlugin plugin = factory.createPlugin(pluginExecutor,
+				SimplexPluginFactory factory =
+					(SimplexPluginFactory) c.newInstance();
+				SimplexCallback callback = new SimplexCallback();
+				SimplexPlugin plugin = factory.createPlugin(pluginExecutor,
 						callback);
 				if(plugin == null) {
 					if(LOG.isLoggable(Level.INFO)) {
@@ -109,7 +109,7 @@ class PluginManagerImpl implements PluginManager {
 				}
 				callback.init(id, index);
 				plugin.start();
-				batchPlugins.add(plugin);
+				simplexPlugins.add(plugin);
 			} catch(ClassCastException e) {
 				if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 				continue;
@@ -118,14 +118,14 @@ class PluginManagerImpl implements PluginManager {
 				continue;
 			}
 		}
-		// Instantiate and start the stream plugins
-		for(String s : STREAM_FACTORIES) {
+		// Instantiate and start the duplex plugins
+		for(String s : DUPLEX_PLUGIN_FACTORIES) {
 			try {
 				Class<?> c = Class.forName(s);
-				StreamPluginFactory factory =
-					(StreamPluginFactory) c.newInstance();
-				StreamCallback callback = new StreamCallback();
-				StreamPlugin plugin = factory.createPlugin(pluginExecutor,
+				DuplexPluginFactory factory =
+					(DuplexPluginFactory) c.newInstance();
+				DuplexCallback callback = new DuplexCallback();
+				DuplexPlugin plugin = factory.createPlugin(pluginExecutor,
 						callback);
 				if(plugin == null) {
 					if(LOG.isLoggable(Level.INFO)) {
@@ -149,7 +149,7 @@ class PluginManagerImpl implements PluginManager {
 				}
 				callback.init(id, index);
 				plugin.start();
-				streamPlugins.add(plugin);
+				duplexPlugins.add(plugin);
 			} catch(ClassCastException e) {
 				if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 				continue;
@@ -160,17 +160,17 @@ class PluginManagerImpl implements PluginManager {
 		}
 		// Start the poller
 		List<Plugin> plugins = new ArrayList<Plugin>();
-		plugins.addAll(batchPlugins);
-		plugins.addAll(streamPlugins);
+		plugins.addAll(simplexPlugins);
+		plugins.addAll(duplexPlugins);
 		poller.start(Collections.unmodifiableList(plugins));
 		// Return the number of plugins successfully started
-		return batchPlugins.size() + streamPlugins.size();
+		return simplexPlugins.size() + duplexPlugins.size();
 	}
 
 	public synchronized int stop() {
 		int stopped = 0;
-		// Stop the batch plugins
-		for(BatchPlugin plugin : batchPlugins) {
+		// Stop the simplex plugins
+		for(SimplexPlugin plugin : simplexPlugins) {
 			try {
 				plugin.stop();
 				stopped++;
@@ -178,9 +178,9 @@ class PluginManagerImpl implements PluginManager {
 				if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 			}
 		}
-		batchPlugins.clear();
-		// Stop the stream plugins
-		for(StreamPlugin plugin : streamPlugins) {
+		simplexPlugins.clear();
+		// Stop the duplex plugins
+		for(DuplexPlugin plugin : duplexPlugins) {
 			try {
 				plugin.stop();
 				stopped++;
@@ -188,7 +188,7 @@ class PluginManagerImpl implements PluginManager {
 				if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
 			}
 		}
-		streamPlugins.clear();
+		duplexPlugins.clear();
 		// Stop the poller
 		poller.stop();
 		// Shut down the executor service
@@ -289,32 +289,32 @@ class PluginManagerImpl implements PluginManager {
 		}
 	}
 
-	private class BatchCallback extends PluginCallbackImpl
-	implements BatchPluginCallback {
+	private class SimplexCallback extends PluginCallbackImpl
+	implements SimplexPluginCallback {
 
-		public void readerCreated(BatchTransportReader r) {
+		public void readerCreated(SimplexTransportReader r) {
 			assert id != null;
 			dispatcher.dispatchReader(id, r);
 		}
 
-		public void writerCreated(ContactId c, BatchTransportWriter w) {
+		public void writerCreated(ContactId c, SimplexTransportWriter w) {
 			assert index != null;
 			dispatcher.dispatchWriter(c, id, index, w);
 		}
 	}
 
-	private class StreamCallback extends PluginCallbackImpl
-	implements StreamPluginCallback {
+	private class DuplexCallback extends PluginCallbackImpl
+	implements DuplexPluginCallback {
 
-		public void incomingConnectionCreated(StreamTransportConnection s) {
+		public void incomingConnectionCreated(DuplexTransportConnection d) {
 			assert id != null;
-			dispatcher.dispatchIncomingConnection(id, s);
+			dispatcher.dispatchIncomingConnection(id, d);
 		}
 
 		public void outgoingConnectionCreated(ContactId c,
-				StreamTransportConnection s) {
+				DuplexTransportConnection d) {
 			assert index != null;
-			dispatcher.dispatchOutgoingConnection(c, id, index, s);
+			dispatcher.dispatchOutgoingConnection(c, id, index, d);
 		}
 	}
 }
\ No newline at end of file
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
index bddcfa8e91a3f8b4f395c6b858f3bd68f567baee..af068999d523a14bfede39fc509d2b03e4c7107a 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothPlugin.java
@@ -26,14 +26,14 @@ import javax.microedition.io.StreamConnectionNotifier;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.plugins.PluginExecutor;
-import net.sf.briar.api.plugins.StreamPlugin;
-import net.sf.briar.api.plugins.StreamPluginCallback;
+import net.sf.briar.api.plugins.DuplexPlugin;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.TransportId;
-import net.sf.briar.api.transport.StreamTransportConnection;
 import net.sf.briar.util.OsUtils;
 import net.sf.briar.util.StringUtils;
 
-class BluetoothPlugin implements StreamPlugin {
+class BluetoothPlugin implements DuplexPlugin {
 
 	public static final byte[] TRANSPORT_ID =
 		StringUtils.fromHexString("d99c9313c04417dcf22fc60d12a187ea"
@@ -44,7 +44,7 @@ class BluetoothPlugin implements StreamPlugin {
 		Logger.getLogger(BluetoothPlugin.class.getName());
 
 	private final Executor pluginExecutor;
-	private final StreamPluginCallback callback;
+	private final DuplexPluginCallback callback;
 	private final long pollingInterval;
 	private final Object discoveryLock = new Object();
 	private final Object localPropertiesLock = new Object();
@@ -56,7 +56,7 @@ class BluetoothPlugin implements StreamPlugin {
 	private StreamConnectionNotifier socket = null; // Locking: this
 
 	BluetoothPlugin(@PluginExecutor Executor pluginExecutor,
-			StreamPluginCallback callback, long pollingInterval) {
+			DuplexPluginCallback callback, long pollingInterval) {
 		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
 		this.pollingInterval = pollingInterval;
@@ -228,8 +228,8 @@ class BluetoothPlugin implements StreamPlugin {
 			// 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);
+			DuplexTransportConnection d = connect(c, url);
+			if(d != null) callback.outgoingConnectionCreated(c, d);
 		}
 	}
 
@@ -274,7 +274,7 @@ class BluetoothPlugin implements StreamPlugin {
 		}
 	}
 
-	private StreamTransportConnection connect(ContactId c, String url) {
+	private DuplexTransportConnection connect(ContactId c, String url) {
 		synchronized(this) {
 			if(!running) return null;
 		}
@@ -287,7 +287,7 @@ class BluetoothPlugin implements StreamPlugin {
 		}
 	}
 
-	public StreamTransportConnection createConnection(ContactId c) {
+	public DuplexTransportConnection createConnection(ContactId c) {
 		synchronized(this) {
 			if(!running) return null;
 		}
@@ -303,15 +303,15 @@ class BluetoothPlugin implements StreamPlugin {
 		return true;
 	}
 
-	public StreamTransportConnection sendInvitation(int code, long timeout) {
+	public DuplexTransportConnection sendInvitation(int code, long timeout) {
 		return createInvitationConnection(code, timeout);
 	}
 
-	public StreamTransportConnection acceptInvitation(int code, long timeout) {
+	public DuplexTransportConnection acceptInvitation(int code, long timeout) {
 		return createInvitationConnection(code, timeout);
 	}
 
-	private StreamTransportConnection createInvitationConnection(int code,
+	private DuplexTransportConnection createInvitationConnection(int code,
 			long timeout) {
 		synchronized(this) {
 			if(!running) return null;
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java b/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
index a7a55fa1c3fefc0db6cfb19c93ad2190e640672e..511f874e2ab051aa99dec08519f911e1547295ed 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothPluginFactory.java
@@ -3,16 +3,16 @@ package net.sf.briar.plugins.bluetooth;
 import java.util.concurrent.Executor;
 
 import net.sf.briar.api.plugins.PluginExecutor;
-import net.sf.briar.api.plugins.StreamPlugin;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.plugins.StreamPluginFactory;
+import net.sf.briar.api.plugins.DuplexPlugin;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexPluginFactory;
 
-public class BluetoothPluginFactory implements StreamPluginFactory {
+public class BluetoothPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 3L * 60L * 1000L; // 3 mins
 
-	public StreamPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			StreamPluginCallback callback) {
+	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
+			DuplexPluginCallback callback) {
 		return new BluetoothPlugin(pluginExecutor, callback, POLLING_INTERVAL);
 	}
 }
diff --git a/components/net/sf/briar/plugins/bluetooth/BluetoothTransportConnection.java b/components/net/sf/briar/plugins/bluetooth/BluetoothTransportConnection.java
index c136875dcca2d724e19de51b89be861ee8e50d27..baab4332fe6557f11465be2939a27c5caf487622 100644
--- a/components/net/sf/briar/plugins/bluetooth/BluetoothTransportConnection.java
+++ b/components/net/sf/briar/plugins/bluetooth/BluetoothTransportConnection.java
@@ -8,9 +8,9 @@ import java.util.logging.Logger;
 
 import javax.microedition.io.StreamConnection;
 
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 
-class BluetoothTransportConnection implements StreamTransportConnection {
+class BluetoothTransportConnection implements DuplexTransportConnection {
 
 	private static final Logger LOG =
 		Logger.getLogger(BluetoothTransportConnection.class.getName());
diff --git a/components/net/sf/briar/plugins/file/FilePlugin.java b/components/net/sf/briar/plugins/file/FilePlugin.java
index 66b8f572e7158a51c1e55e8cdf1ae74de3f89ed0..eb4c86e42e3a15737ba377725c869a562c85c82b 100644
--- a/components/net/sf/briar/plugins/file/FilePlugin.java
+++ b/components/net/sf/briar/plugins/file/FilePlugin.java
@@ -11,22 +11,22 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import net.sf.briar.api.ContactId;
-import net.sf.briar.api.plugins.BatchPlugin;
-import net.sf.briar.api.plugins.BatchPluginCallback;
+import net.sf.briar.api.plugins.SimplexPlugin;
+import net.sf.briar.api.plugins.SimplexPluginCallback;
+import net.sf.briar.api.plugins.SimplexTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 import net.sf.briar.api.plugins.PluginExecutor;
-import net.sf.briar.api.transport.BatchTransportReader;
-import net.sf.briar.api.transport.BatchTransportWriter;
 import net.sf.briar.api.transport.TransportConstants;
 
 import org.apache.commons.io.FileSystemUtils;
 
-abstract class FilePlugin implements BatchPlugin {
+abstract class FilePlugin implements SimplexPlugin {
 
 	private static final Logger LOG =
 		Logger.getLogger(FilePlugin.class.getName());
 
 	protected final Executor pluginExecutor;
-	protected final BatchPluginCallback callback;
+	protected final SimplexPluginCallback callback;
 
 	protected volatile boolean running = false;
 
@@ -40,16 +40,16 @@ abstract class FilePlugin implements BatchPlugin {
 	protected abstract void readerFinished(File f);
 
 	protected FilePlugin(@PluginExecutor Executor pluginExecutor,
-			BatchPluginCallback callback) {
+			SimplexPluginCallback callback) {
 		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
 	}
 
-	public BatchTransportReader createReader(ContactId c) {
+	public SimplexTransportReader createReader(ContactId c) {
 		return null;
 	}
 
-	public BatchTransportWriter createWriter(ContactId c) {
+	public SimplexTransportWriter createWriter(ContactId c) {
 		if(!running) return null;
 		return createWriter(createConnectionFilename());
 	}
@@ -66,7 +66,7 @@ abstract class FilePlugin implements BatchPlugin {
 		return filename.toLowerCase().matches("[a-z]{8}\\.dat");
 	}
 
-	private BatchTransportWriter createWriter(String filename) {
+	private SimplexTransportWriter createWriter(String filename) {
 		if(!running) return null;
 		File dir = chooseOutputDirectory();
 		if(dir == null || !dir.exists() || !dir.isDirectory()) return null;
@@ -92,30 +92,30 @@ abstract class FilePlugin implements BatchPlugin {
 		pluginExecutor.execute(new ReaderCreator(f));
 	}
 
-	public BatchTransportWriter sendInvitation(int code, long timeout) {
+	public SimplexTransportWriter sendInvitation(int code, long timeout) {
 		if(!running) return null;
 		return createWriter(createInvitationFilename(code, false));
 	}
 
-	public BatchTransportReader acceptInvitation(int code, long timeout) {
+	public SimplexTransportReader acceptInvitation(int code, long timeout) {
 		if(!running) return null;
 		String filename = createInvitationFilename(code, false);
 		return createInvitationReader(filename, timeout);
 	}
 
-	public BatchTransportWriter sendInvitationResponse(int code, long timeout) {
+	public SimplexTransportWriter sendInvitationResponse(int code, long timeout) {
 		if(!running) return null;
 		return createWriter(createInvitationFilename(code, true));
 	}
 
-	public BatchTransportReader acceptInvitationResponse(int code,
+	public SimplexTransportReader acceptInvitationResponse(int code,
 			long timeout) {
 		if(!running) return null;
 		String filename = createInvitationFilename(code, true);
 		return createInvitationReader(filename, timeout);
 	}
 
-	private BatchTransportReader createInvitationReader(String filename,
+	private SimplexTransportReader createInvitationReader(String filename,
 			long timeout) {
 		Collection<File> files;
 		// FIXME: Avoid making alien calls with a lock held
diff --git a/components/net/sf/briar/plugins/file/FileTransportReader.java b/components/net/sf/briar/plugins/file/FileTransportReader.java
index 0f96e7134b0b0d2993bbd600faf16ed54d2d1794..a7df1d398463b612807c02d63ca720943aee69a6 100644
--- a/components/net/sf/briar/plugins/file/FileTransportReader.java
+++ b/components/net/sf/briar/plugins/file/FileTransportReader.java
@@ -6,9 +6,9 @@ import java.io.InputStream;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import net.sf.briar.api.transport.BatchTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportReader;
 
-class FileTransportReader implements BatchTransportReader {
+class FileTransportReader implements SimplexTransportReader {
 
 	private static final Logger LOG =
 		Logger.getLogger(FileTransportReader.class.getName());
diff --git a/components/net/sf/briar/plugins/file/FileTransportWriter.java b/components/net/sf/briar/plugins/file/FileTransportWriter.java
index a7eaacebd203ad095bff933210880826d6abec4c..e311196907dc33368a28cca592f25e232a2e6c4d 100644
--- a/components/net/sf/briar/plugins/file/FileTransportWriter.java
+++ b/components/net/sf/briar/plugins/file/FileTransportWriter.java
@@ -6,9 +6,9 @@ import java.io.OutputStream;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import net.sf.briar.api.transport.BatchTransportWriter;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 
-class FileTransportWriter implements BatchTransportWriter {
+class FileTransportWriter implements SimplexTransportWriter {
 
 	private static final Logger LOG =
 		Logger.getLogger(FileTransportWriter.class.getName());
diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
index 930bea4059e1c71241942e51fe334f1ce367af44..200588f21aaf9cafed69fe493c38c0c82b93dd28 100644
--- a/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
+++ b/components/net/sf/briar/plugins/file/RemovableDrivePlugin.java
@@ -11,7 +11,7 @@ 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.SimplexPluginCallback;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.util.StringUtils;
@@ -31,7 +31,7 @@ implements RemovableDriveMonitor.Callback {
 	private final RemovableDriveMonitor monitor;
 
 	RemovableDrivePlugin(@PluginExecutor Executor pluginExecutor,
-			BatchPluginCallback callback, RemovableDriveFinder finder,
+			SimplexPluginCallback callback, RemovableDriveFinder finder,
 			RemovableDriveMonitor monitor) {
 		super(pluginExecutor, callback);
 		this.finder = finder;
diff --git a/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java b/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
index 81f719c8dcf5454d4aaf0e73b772b9ae2233ba84..545380c187cd418a66c221f68cf4ea23e854251f 100644
--- a/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
+++ b/components/net/sf/briar/plugins/file/RemovableDrivePluginFactory.java
@@ -2,18 +2,18 @@ package net.sf.briar.plugins.file;
 
 import java.util.concurrent.Executor;
 
-import net.sf.briar.api.plugins.BatchPlugin;
-import net.sf.briar.api.plugins.BatchPluginCallback;
-import net.sf.briar.api.plugins.BatchPluginFactory;
+import net.sf.briar.api.plugins.SimplexPlugin;
+import net.sf.briar.api.plugins.SimplexPluginCallback;
+import net.sf.briar.api.plugins.SimplexPluginFactory;
 import net.sf.briar.api.plugins.PluginExecutor;
 import net.sf.briar.util.OsUtils;
 
-public class RemovableDrivePluginFactory implements BatchPluginFactory {
+public class RemovableDrivePluginFactory implements SimplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 10L * 1000L; // 10 seconds
 
-	public BatchPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			BatchPluginCallback callback) {
+	public SimplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
+			SimplexPluginCallback callback) {
 		RemovableDriveFinder finder;
 		RemovableDriveMonitor monitor;
 		if(OsUtils.isLinux()) {
diff --git a/components/net/sf/briar/plugins/socket/LanSocketPlugin.java b/components/net/sf/briar/plugins/socket/LanSocketPlugin.java
index 9e5c3742c1df69b7589435292f75df9d4c183e05..a6bae33bc6d141c93867bc17ee375b1afc515ce0 100644
--- a/components/net/sf/briar/plugins/socket/LanSocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/LanSocketPlugin.java
@@ -15,8 +15,8 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import net.sf.briar.api.plugins.PluginExecutor;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.util.ByteUtils;
 
 /** A socket plugin that supports exchanging invitations over a LAN. */
@@ -26,7 +26,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 		Logger.getLogger(LanSocketPlugin.class.getName());
 
 	LanSocketPlugin(@PluginExecutor Executor pluginExecutor,
-			StreamPluginCallback callback, long pollingInterval) {
+			DuplexPluginCallback callback, long pollingInterval) {
 		super(pluginExecutor, callback, pollingInterval);
 	}
 
@@ -36,7 +36,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 	}
 
 	@Override
-	public StreamTransportConnection sendInvitation(int code, long timeout) {
+	public DuplexTransportConnection sendInvitation(int code, long timeout) {
 		synchronized(this) {
 			if(!running) return null;
 		}
@@ -139,7 +139,7 @@ class LanSocketPlugin extends SimpleSocketPlugin {
 	}
 
 	@Override
-	public StreamTransportConnection acceptInvitation(int code, long timeout) {
+	public DuplexTransportConnection acceptInvitation(int code, long timeout) {
 		synchronized(this) {
 			if(!running) return null;
 		}
diff --git a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
index 1a6bb99eb16f1ea6bb28d6eec084346a5eefa719..f6efe6fbcbaca78981c5ba9629a4112b7b6f815d 100644
--- a/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/SimpleSocketPlugin.java
@@ -16,9 +16,9 @@ import java.util.logging.Logger;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.plugins.PluginExecutor;
-import net.sf.briar.api.plugins.StreamPluginCallback;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.TransportId;
-import net.sf.briar.api.transport.StreamTransportConnection;
 import net.sf.briar.util.StringUtils;
 
 class SimpleSocketPlugin extends SocketPlugin {
@@ -32,7 +32,7 @@ class SimpleSocketPlugin extends SocketPlugin {
 		Logger.getLogger(SimpleSocketPlugin.class.getName());
 
 	SimpleSocketPlugin(@PluginExecutor Executor pluginExecutor,
-			StreamPluginCallback callback, long pollingInterval) {
+			DuplexPluginCallback callback, long pollingInterval) {
 		super(pluginExecutor, callback, pollingInterval);
 	}
 
@@ -138,11 +138,11 @@ class SimpleSocketPlugin extends SocketPlugin {
 		return false;
 	}
 
-	public StreamTransportConnection sendInvitation(int code, long timeout) {
+	public DuplexTransportConnection sendInvitation(int code, long timeout) {
 		throw new UnsupportedOperationException();
 	}
 
-	public StreamTransportConnection acceptInvitation(int code, long timeout) {
+	public DuplexTransportConnection acceptInvitation(int code, long timeout) {
 		throw new UnsupportedOperationException();
 	}
 }
diff --git a/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java b/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java
index a34e21ead8d1c00e6800c70b653155007d4e9e94..e5b2f07bde0cf8b3e0fb6f9fd7f5a8c323bb1862 100644
--- a/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java
+++ b/components/net/sf/briar/plugins/socket/SimpleSocketPluginFactory.java
@@ -3,16 +3,16 @@ package net.sf.briar.plugins.socket;
 import java.util.concurrent.Executor;
 
 import net.sf.briar.api.plugins.PluginExecutor;
-import net.sf.briar.api.plugins.StreamPlugin;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.plugins.StreamPluginFactory;
+import net.sf.briar.api.plugins.DuplexPlugin;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexPluginFactory;
 
-public class SimpleSocketPluginFactory implements StreamPluginFactory {
+public class SimpleSocketPluginFactory implements DuplexPluginFactory {
 
 	private static final long POLLING_INTERVAL = 5L * 60L * 1000L; // 5 mins
 
-	public StreamPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
-			StreamPluginCallback callback) {
+	public DuplexPlugin createPlugin(@PluginExecutor Executor pluginExecutor,
+			DuplexPluginCallback callback) {
 		return new SimpleSocketPlugin(pluginExecutor, callback,
 				POLLING_INTERVAL);
 	}
diff --git a/components/net/sf/briar/plugins/socket/SocketPlugin.java b/components/net/sf/briar/plugins/socket/SocketPlugin.java
index 2c046478eabcf751891862074e2344fcaf2be1b2..8292a446fc63a2213e98e7f1404533dce3c97a38 100644
--- a/components/net/sf/briar/plugins/socket/SocketPlugin.java
+++ b/components/net/sf/briar/plugins/socket/SocketPlugin.java
@@ -13,17 +13,17 @@ import java.util.logging.Logger;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.plugins.PluginExecutor;
-import net.sf.briar.api.plugins.StreamPlugin;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexPlugin;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 
-abstract class SocketPlugin implements StreamPlugin {
+abstract class SocketPlugin implements DuplexPlugin {
 
 	private static final Logger LOG =
 		Logger.getLogger(SocketPlugin.class.getName());
 
 	protected final Executor pluginExecutor;
-	protected final StreamPluginCallback callback;
+	protected final DuplexPluginCallback callback;
 
 	private final long pollingInterval;
 
@@ -38,7 +38,7 @@ abstract class SocketPlugin implements StreamPlugin {
 	protected abstract SocketAddress getRemoteSocketAddress(ContactId c);
 
 	protected SocketPlugin(@PluginExecutor Executor pluginExecutor,
-			StreamPluginCallback callback, long pollingInterval) {
+			DuplexPluginCallback callback, long pollingInterval) {
 		this.pluginExecutor = pluginExecutor;
 		this.callback = callback;
 		this.pollingInterval = pollingInterval;
@@ -148,11 +148,11 @@ abstract class SocketPlugin implements StreamPlugin {
 	}
 
 	private void connectAndCallBack(ContactId c) {
-		StreamTransportConnection conn = createConnection(c);
-		if(conn != null) callback.outgoingConnectionCreated(c, conn);
+		DuplexTransportConnection d = createConnection(c);
+		if(d != null) callback.outgoingConnectionCreated(c, d);
 	}
 
-	public StreamTransportConnection createConnection(ContactId c) {
+	public DuplexTransportConnection createConnection(ContactId c) {
 		synchronized(this) {
 			if(!running) return null;
 		}
diff --git a/components/net/sf/briar/plugins/socket/SocketTransportConnection.java b/components/net/sf/briar/plugins/socket/SocketTransportConnection.java
index 2890ec63f8706910a314656fc0b3b2121021c662..dc342945357c2a02f19d5481f3a611e8e9db7abd 100644
--- a/components/net/sf/briar/plugins/socket/SocketTransportConnection.java
+++ b/components/net/sf/briar/plugins/socket/SocketTransportConnection.java
@@ -7,9 +7,9 @@ import java.net.Socket;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 
-class SocketTransportConnection implements StreamTransportConnection {
+class SocketTransportConnection implements DuplexTransportConnection {
 
 	private static final Logger LOG =
 		Logger.getLogger(SocketTransportConnection.class.getName());
diff --git a/components/net/sf/briar/protocol/batch/ProtocolBatchModule.java b/components/net/sf/briar/protocol/batch/ProtocolBatchModule.java
deleted file mode 100644
index e5ce39b198d36895d66b26c5f1b3e9784a19cf13..0000000000000000000000000000000000000000
--- a/components/net/sf/briar/protocol/batch/ProtocolBatchModule.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.sf.briar.protocol.batch;
-
-import net.sf.briar.api.protocol.batch.BatchConnectionFactory;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Singleton;
-
-public class ProtocolBatchModule extends AbstractModule {
-
-	@Override
-	protected void configure() {
-		bind(BatchConnectionFactory.class).to(
-				BatchConnectionFactoryImpl.class).in(Singleton.class);
-	}
-}
diff --git a/components/net/sf/briar/protocol/stream/StreamConnection.java b/components/net/sf/briar/protocol/duplex/DuplexConnection.java
similarity index 97%
rename from components/net/sf/briar/protocol/stream/StreamConnection.java
rename to components/net/sf/briar/protocol/duplex/DuplexConnection.java
index 8bb47d2276c32925bc9c2c1d79f32bdc3f8d9332..7ebba90f3bfdfcb31e475853b06a67684b306a10 100644
--- a/components/net/sf/briar/protocol/stream/StreamConnection.java
+++ b/components/net/sf/briar/protocol/duplex/DuplexConnection.java
@@ -1,4 +1,4 @@
-package net.sf.briar.protocol.stream;
+package net.sf.briar.protocol.duplex;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -29,6 +29,7 @@ import net.sf.briar.api.db.event.DatabaseListener;
 import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
 import net.sf.briar.api.db.event.MessagesAddedEvent;
 import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.Batch;
 import net.sf.briar.api.protocol.MessageId;
@@ -49,12 +50,11 @@ 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;
 
-abstract class StreamConnection implements DatabaseListener {
+abstract class DuplexConnection implements DatabaseListener {
 
 	private static final Logger LOG =
-		Logger.getLogger(StreamConnection.class.getName());
+		Logger.getLogger(DuplexConnection.class.getName());
 
 	private static final Runnable CLOSE = new Runnable() {
 		public void run() {}
@@ -68,7 +68,7 @@ abstract class StreamConnection implements DatabaseListener {
 	protected final ProtocolWriterFactory protoWriterFactory;
 	protected final ContactId contactId;
 	protected final TransportId transportId;
-	protected final StreamTransportConnection transport;
+	protected final DuplexTransportConnection transport;
 
 	private final Executor dbExecutor, verificationExecutor;
 	private final AtomicBoolean canSendOffer, disposed;
@@ -78,14 +78,14 @@ abstract class StreamConnection implements DatabaseListener {
 
 	private volatile ProtocolWriter writer = null;
 
-	StreamConnection(@DatabaseExecutor Executor dbExecutor,
+	DuplexConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
 			DatabaseComponent db, ConnectionRegistry connRegistry,
 			ConnectionReaderFactory connReaderFactory,
 			ConnectionWriterFactory connWriterFactory,
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory, ContactId contactId,
-			TransportId transportId, StreamTransportConnection transport) {
+			TransportId transportId, DuplexTransportConnection transport) {
 		this.dbExecutor = dbExecutor;
 		this.verificationExecutor = verificationExecutor;
 		this.db = db;
diff --git a/components/net/sf/briar/protocol/duplex/DuplexProtocolModule.java b/components/net/sf/briar/protocol/duplex/DuplexProtocolModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..e04df3b249e029a0018e6e7022e268b52f290402
--- /dev/null
+++ b/components/net/sf/briar/protocol/duplex/DuplexProtocolModule.java
@@ -0,0 +1,15 @@
+package net.sf.briar.protocol.duplex;
+
+import net.sf.briar.api.protocol.duplex.DuplexConnectionFactory;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Singleton;
+
+public class DuplexProtocolModule extends AbstractModule {
+
+	@Override
+	protected void configure() {
+		bind(DuplexConnectionFactory.class).to(
+				StreamConnectionFactoryImpl.class).in(Singleton.class);
+	}
+}
diff --git a/components/net/sf/briar/protocol/stream/IncomingStreamConnection.java b/components/net/sf/briar/protocol/duplex/IncomingDuplexConnection.java
similarity index 86%
rename from components/net/sf/briar/protocol/stream/IncomingStreamConnection.java
rename to components/net/sf/briar/protocol/duplex/IncomingDuplexConnection.java
index 6a32c24850d38b3f61795fcd4903696720448097..34059ca58aaa9d965323bbf999b67e58e4d6b910 100644
--- a/components/net/sf/briar/protocol/stream/IncomingStreamConnection.java
+++ b/components/net/sf/briar/protocol/duplex/IncomingDuplexConnection.java
@@ -1,10 +1,11 @@
-package net.sf.briar.protocol.stream;
+package net.sf.briar.protocol.duplex;
 
 import java.io.IOException;
 import java.util.concurrent.Executor;
 
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
 import net.sf.briar.api.protocol.TransportId;
@@ -15,14 +16,13 @@ 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;
 
-class IncomingStreamConnection extends StreamConnection {
+class IncomingDuplexConnection extends DuplexConnection {
 
 	private final ConnectionContext ctx;
 	private final byte[] tag;
 
-	IncomingStreamConnection(@DatabaseExecutor Executor dbExecutor,
+	IncomingDuplexConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
 			DatabaseComponent db, ConnectionRegistry connRegistry,
 			ConnectionReaderFactory connReaderFactory,
@@ -30,7 +30,7 @@ class IncomingStreamConnection extends StreamConnection {
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory,
 			ConnectionContext ctx, TransportId transportId,
-			StreamTransportConnection transport, byte[] tag) {
+			DuplexTransportConnection transport, byte[] tag) {
 		super(dbExecutor, verificationExecutor, db, connRegistry,
 				connReaderFactory, connWriterFactory, protoReaderFactory,
 				protoWriterFactory, ctx.getContactId(), transportId, transport);
diff --git a/components/net/sf/briar/protocol/stream/OutgoingStreamConnection.java b/components/net/sf/briar/protocol/duplex/OutgoingDuplexConnection.java
similarity index 89%
rename from components/net/sf/briar/protocol/stream/OutgoingStreamConnection.java
rename to components/net/sf/briar/protocol/duplex/OutgoingDuplexConnection.java
index 84fa026653dde15febb958b42eadc4c10761a7d1..b4a4c0d03fd9f15699145e68c132bdf7325fcbfa 100644
--- a/components/net/sf/briar/protocol/stream/OutgoingStreamConnection.java
+++ b/components/net/sf/briar/protocol/duplex/OutgoingDuplexConnection.java
@@ -1,4 +1,4 @@
-package net.sf.briar.protocol.stream;
+package net.sf.briar.protocol.duplex;
 
 import java.io.IOException;
 import java.util.concurrent.Executor;
@@ -7,6 +7,7 @@ import net.sf.briar.api.ContactId;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.db.DbException;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.ProtocolReaderFactory;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
 import net.sf.briar.api.protocol.TransportId;
@@ -18,15 +19,14 @@ 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;
 
-class OutgoingStreamConnection extends StreamConnection {
+class OutgoingDuplexConnection extends DuplexConnection {
 
 	private final TransportIndex transportIndex;
 
 	private ConnectionContext ctx = null; // Locking: this
 
-	OutgoingStreamConnection(@DatabaseExecutor Executor dbExecutor,
+	OutgoingDuplexConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
 			DatabaseComponent db, ConnectionRegistry connRegistry,
 			ConnectionReaderFactory connReaderFactory,
@@ -34,7 +34,7 @@ class OutgoingStreamConnection extends StreamConnection {
 			ProtocolReaderFactory protoReaderFactory,
 			ProtocolWriterFactory protoWriterFactory, ContactId contactId,
 			TransportId transportId, TransportIndex transportIndex,
-			StreamTransportConnection transport) {
+			DuplexTransportConnection transport) {
 		super(dbExecutor, verificationExecutor, db, connRegistry,
 				connReaderFactory, connWriterFactory, protoReaderFactory,
 				protoWriterFactory, contactId, transportId, transport);
diff --git a/components/net/sf/briar/protocol/stream/StreamConnectionFactoryImpl.java b/components/net/sf/briar/protocol/duplex/StreamConnectionFactoryImpl.java
similarity index 84%
rename from components/net/sf/briar/protocol/stream/StreamConnectionFactoryImpl.java
rename to components/net/sf/briar/protocol/duplex/StreamConnectionFactoryImpl.java
index 05e337c6af96c5383adfbda9872ffc3a3b9781ec..8f4b3c40d435d4de8edd4bc59eab76f795a684c6 100644
--- a/components/net/sf/briar/protocol/stream/StreamConnectionFactoryImpl.java
+++ b/components/net/sf/briar/protocol/duplex/StreamConnectionFactoryImpl.java
@@ -1,25 +1,25 @@
-package net.sf.briar.protocol.stream;
+package net.sf.briar.protocol.duplex;
 
 import java.util.concurrent.Executor;
 
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 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.protocol.duplex.DuplexConnectionFactory;
 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;
 
 import com.google.inject.Inject;
 
-class StreamConnectionFactoryImpl implements StreamConnectionFactory {
+class StreamConnectionFactoryImpl implements DuplexConnectionFactory {
 
 	private final Executor dbExecutor, verificationExecutor;
 	private final DatabaseComponent db;
@@ -48,11 +48,11 @@ class StreamConnectionFactoryImpl implements StreamConnectionFactory {
 	}
 
 	public void createIncomingConnection(ConnectionContext ctx, TransportId t,
-			StreamTransportConnection s, byte[] tag) {
-		final StreamConnection conn = new IncomingStreamConnection(dbExecutor,
+			DuplexTransportConnection d, byte[] tag) {
+		final DuplexConnection conn = new IncomingDuplexConnection(dbExecutor,
 				verificationExecutor, db, connRegistry, connReaderFactory,
 				connWriterFactory, protoReaderFactory, protoWriterFactory,
-				ctx, t, s, tag);
+				ctx, t, d, tag);
 		Runnable write = new Runnable() {
 			public void run() {
 				conn.write();
@@ -68,11 +68,11 @@ class StreamConnectionFactoryImpl implements StreamConnectionFactory {
 	}
 
 	public void createOutgoingConnection(ContactId c, TransportId t,
-			TransportIndex i, StreamTransportConnection s) {
-		final StreamConnection conn = new OutgoingStreamConnection(dbExecutor,
+			TransportIndex i, DuplexTransportConnection d) {
+		final DuplexConnection conn = new OutgoingDuplexConnection(dbExecutor,
 				verificationExecutor, db, connRegistry, connReaderFactory,
 				connWriterFactory, protoReaderFactory, protoWriterFactory,
-				c, t, i, s);
+				c, t, i, d);
 		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/simplex/IncomingSimplexConnection.java
similarity index 93%
rename from components/net/sf/briar/protocol/batch/IncomingBatchConnection.java
rename to components/net/sf/briar/protocol/simplex/IncomingSimplexConnection.java
index 1f5327f996a4a26aad3b44fd85263fc50ecdf11c..6b81a318a9cd922df6cd4ea6aaaeac71f155d151 100644
--- a/components/net/sf/briar/protocol/batch/IncomingBatchConnection.java
+++ b/components/net/sf/briar/protocol/simplex/IncomingSimplexConnection.java
@@ -1,4 +1,4 @@
-package net.sf.briar.protocol.batch;
+package net.sf.briar.protocol.simplex;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -12,6 +12,7 @@ import net.sf.briar.api.FormatException;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
 import net.sf.briar.api.db.DbException;
+import net.sf.briar.api.plugins.SimplexTransportReader;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.Batch;
 import net.sf.briar.api.protocol.ProtocolReader;
@@ -21,16 +22,15 @@ 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.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 {
+class IncomingSimplexConnection {
 
 	private static final Logger LOG =
-		Logger.getLogger(IncomingBatchConnection.class.getName());
+		Logger.getLogger(IncomingSimplexConnection.class.getName());
 
 	private final Executor dbExecutor, verificationExecutor;
 	private final DatabaseComponent db;
@@ -39,16 +39,16 @@ class IncomingBatchConnection {
 	private final ProtocolReaderFactory protoFactory;
 	private final ConnectionContext ctx;
 	private final TransportId transportId;
-	private final BatchTransportReader transport;
+	private final SimplexTransportReader transport;
 	private final byte[] tag;
 	private final ContactId contactId;
 
-	IncomingBatchConnection(@DatabaseExecutor Executor dbExecutor,
+	IncomingSimplexConnection(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
 			DatabaseComponent db, ConnectionRegistry connRegistry,
 			ConnectionReaderFactory connFactory,
 			ProtocolReaderFactory protoFactory, ConnectionContext ctx,
-			TransportId transportId, BatchTransportReader transport,
+			TransportId transportId, SimplexTransportReader transport,
 			byte[] tag) {
 		this.dbExecutor = dbExecutor;
 		this.verificationExecutor = verificationExecutor;
diff --git a/components/net/sf/briar/protocol/batch/OutgoingBatchConnection.java b/components/net/sf/briar/protocol/simplex/OutgoingSimplexConnection.java
similarity index 92%
rename from components/net/sf/briar/protocol/batch/OutgoingBatchConnection.java
rename to components/net/sf/briar/protocol/simplex/OutgoingSimplexConnection.java
index 14ef7268e0bd3a00ed9d6592efaac076494eb470..da080bb371681df804dfb45c291723a8ef19ef10 100644
--- a/components/net/sf/briar/protocol/batch/OutgoingBatchConnection.java
+++ b/components/net/sf/briar/protocol/simplex/OutgoingSimplexConnection.java
@@ -1,4 +1,4 @@
-package net.sf.briar.protocol.batch;
+package net.sf.briar.protocol.simplex;
 
 import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
 
@@ -11,6 +11,7 @@ import java.util.logging.Logger;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DbException;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.ProtocolWriter;
 import net.sf.briar.api.protocol.ProtocolWriterFactory;
@@ -19,16 +20,15 @@ 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;
 
-class OutgoingBatchConnection {
+class OutgoingSimplexConnection {
 
 	private static final Logger LOG =
-		Logger.getLogger(OutgoingBatchConnection.class.getName());
+		Logger.getLogger(OutgoingSimplexConnection.class.getName());
 
 	private final DatabaseComponent db;
 	private final ConnectionRegistry connRegistry;
@@ -37,14 +37,14 @@ class OutgoingBatchConnection {
 	private final ContactId contactId;
 	private final TransportId transportId;
 	private final TransportIndex transportIndex;
-	private final BatchTransportWriter transport;
+	private final SimplexTransportWriter transport;
 
-	OutgoingBatchConnection(DatabaseComponent db,
+	OutgoingSimplexConnection(DatabaseComponent db,
 			ConnectionRegistry connRegistry,
 			ConnectionWriterFactory connFactory,
 			ProtocolWriterFactory protoFactory, ContactId contactId,
 			TransportId transportId, TransportIndex transportIndex,
-			BatchTransportWriter transport) {
+			SimplexTransportWriter transport) {
 		this.db = db;
 		this.connRegistry = connRegistry;
 		this.connFactory = connFactory;
diff --git a/components/net/sf/briar/protocol/batch/BatchConnectionFactoryImpl.java b/components/net/sf/briar/protocol/simplex/SimplexConnectionFactoryImpl.java
similarity index 79%
rename from components/net/sf/briar/protocol/batch/BatchConnectionFactoryImpl.java
rename to components/net/sf/briar/protocol/simplex/SimplexConnectionFactoryImpl.java
index 5d52a90fb372667a65c652fd299879c4b48eea59..3e5d1e16ce399c4958fa6d871e1d4df07bac7f3b 100644
--- a/components/net/sf/briar/protocol/batch/BatchConnectionFactoryImpl.java
+++ b/components/net/sf/briar/protocol/simplex/SimplexConnectionFactoryImpl.java
@@ -1,18 +1,18 @@
-package net.sf.briar.protocol.batch;
+package net.sf.briar.protocol.simplex;
 
 import java.util.concurrent.Executor;
 
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.db.DatabaseComponent;
 import net.sf.briar.api.db.DatabaseExecutor;
+import net.sf.briar.api.plugins.SimplexTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 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;
-import net.sf.briar.api.transport.BatchTransportReader;
-import net.sf.briar.api.transport.BatchTransportWriter;
+import net.sf.briar.api.protocol.simplex.SimplexConnectionFactory;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionReaderFactory;
 import net.sf.briar.api.transport.ConnectionRegistry;
@@ -20,7 +20,7 @@ import net.sf.briar.api.transport.ConnectionWriterFactory;
 
 import com.google.inject.Inject;
 
-class BatchConnectionFactoryImpl implements BatchConnectionFactory {
+class SimplexConnectionFactoryImpl implements SimplexConnectionFactory {
 
 	private final Executor dbExecutor, verificationExecutor;
 	private final DatabaseComponent db;
@@ -31,7 +31,7 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
 	private final ProtocolWriterFactory protoWriterFactory;
 
 	@Inject
-	BatchConnectionFactoryImpl(@DatabaseExecutor Executor dbExecutor,
+	SimplexConnectionFactoryImpl(@DatabaseExecutor Executor dbExecutor,
 			@VerificationExecutor Executor verificationExecutor,
 			DatabaseComponent db, ConnectionRegistry connRegistry,
 			ConnectionReaderFactory connReaderFactory,
@@ -49,8 +49,8 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
 	}
 
 	public void createIncomingConnection(ConnectionContext ctx, TransportId t,
-			BatchTransportReader r, byte[] tag) {
-		final IncomingBatchConnection conn = new IncomingBatchConnection(
+			SimplexTransportReader r, byte[] tag) {
+		final IncomingSimplexConnection conn = new IncomingSimplexConnection(
 				dbExecutor, verificationExecutor, db, connRegistry,
 				connReaderFactory, protoReaderFactory, ctx, t, r, tag);
 		Runnable read = new Runnable() {
@@ -62,8 +62,8 @@ class BatchConnectionFactoryImpl implements BatchConnectionFactory {
 	}
 
 	public void createOutgoingConnection(ContactId c, TransportId t,
-			TransportIndex i, BatchTransportWriter w) {
-		final OutgoingBatchConnection conn = new OutgoingBatchConnection(db,
+			TransportIndex i, SimplexTransportWriter w) {
+		final OutgoingSimplexConnection conn = new OutgoingSimplexConnection(db,
 				connRegistry, connWriterFactory, protoWriterFactory,
 				c, t, i, w);
 		Runnable write = new Runnable() {
diff --git a/components/net/sf/briar/protocol/simplex/SimplexProtocolModule.java b/components/net/sf/briar/protocol/simplex/SimplexProtocolModule.java
new file mode 100644
index 0000000000000000000000000000000000000000..45ec2a9d1467cfcb77bbe8d1d5980a341746a7fd
--- /dev/null
+++ b/components/net/sf/briar/protocol/simplex/SimplexProtocolModule.java
@@ -0,0 +1,15 @@
+package net.sf.briar.protocol.simplex;
+
+import net.sf.briar.api.protocol.simplex.SimplexConnectionFactory;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Singleton;
+
+public class SimplexProtocolModule extends AbstractModule {
+
+	@Override
+	protected void configure() {
+		bind(SimplexConnectionFactory.class).to(
+				SimplexConnectionFactoryImpl.class).in(Singleton.class);
+	}
+}
diff --git a/components/net/sf/briar/protocol/stream/ProtocolStreamModule.java b/components/net/sf/briar/protocol/stream/ProtocolStreamModule.java
deleted file mode 100644
index d870d248b998a0ea3136c671309867757477454f..0000000000000000000000000000000000000000
--- a/components/net/sf/briar/protocol/stream/ProtocolStreamModule.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.sf.briar.protocol.stream;
-
-import net.sf.briar.api.protocol.stream.StreamConnectionFactory;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Singleton;
-
-public class ProtocolStreamModule extends AbstractModule {
-
-	@Override
-	protected void configure() {
-		bind(StreamConnectionFactory.class).to(
-				StreamConnectionFactoryImpl.class).in(Singleton.class);
-	}
-}
diff --git a/components/net/sf/briar/transport/ConnectionDispatcherImpl.java b/components/net/sf/briar/transport/ConnectionDispatcherImpl.java
index 1cb97fdef60fe4cabc3ec9009d796b70abf89cf5..ea19fb1bb3e2e8d24490ea3f911bb753854afe90 100644
--- a/components/net/sf/briar/transport/ConnectionDispatcherImpl.java
+++ b/components/net/sf/briar/transport/ConnectionDispatcherImpl.java
@@ -9,17 +9,17 @@ import java.util.logging.Logger;
 
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.db.DbException;
+import net.sf.briar.api.plugins.SimplexTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 import net.sf.briar.api.protocol.TransportId;
 import net.sf.briar.api.protocol.TransportIndex;
-import net.sf.briar.api.protocol.batch.BatchConnectionFactory;
-import net.sf.briar.api.protocol.stream.StreamConnectionFactory;
-import net.sf.briar.api.transport.BatchTransportReader;
-import net.sf.briar.api.transport.BatchTransportWriter;
+import net.sf.briar.api.protocol.duplex.DuplexConnectionFactory;
+import net.sf.briar.api.protocol.simplex.SimplexConnectionFactory;
 import net.sf.briar.api.transport.ConnectionContext;
 import net.sf.briar.api.transport.ConnectionDispatcher;
 import net.sf.briar.api.transport.ConnectionRecogniser;
 import net.sf.briar.api.transport.IncomingConnectionExecutor;
-import net.sf.briar.api.transport.StreamTransportConnection;
 import net.sf.briar.api.transport.TransportConstants;
 
 import com.google.inject.Inject;
@@ -31,37 +31,37 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
 
 	private final Executor connExecutor;
 	private final ConnectionRecogniser recogniser;
-	private final BatchConnectionFactory batchConnFactory;
-	private final StreamConnectionFactory streamConnFactory;
+	private final SimplexConnectionFactory batchConnFactory;
+	private final DuplexConnectionFactory streamConnFactory;
 
 	@Inject
 	ConnectionDispatcherImpl(@IncomingConnectionExecutor Executor connExecutor,
 			ConnectionRecogniser recogniser,
-			BatchConnectionFactory batchConnFactory,
-			StreamConnectionFactory streamConnFactory) {
+			SimplexConnectionFactory batchConnFactory,
+			DuplexConnectionFactory streamConnFactory) {
 		this.connExecutor = connExecutor;
 		this.recogniser = recogniser;
 		this.batchConnFactory = batchConnFactory;
 		this.streamConnFactory = streamConnFactory;
 	}
 
-	public void dispatchReader(TransportId t, BatchTransportReader r) {
-		connExecutor.execute(new DispatchBatchConnection(t, r));
+	public void dispatchReader(TransportId t, SimplexTransportReader r) {
+		connExecutor.execute(new DispatchSimplexConnection(t, r));
 	}
 
 	public void dispatchWriter(ContactId c, TransportId t, TransportIndex i,
-			BatchTransportWriter w) {
+			SimplexTransportWriter w) {
 		batchConnFactory.createOutgoingConnection(c, t, i, w);
 	}
 
 	public void dispatchIncomingConnection(TransportId t,
-			StreamTransportConnection s) {
-		connExecutor.execute(new DispatchStreamConnection(t, s));
+			DuplexTransportConnection d) {
+		connExecutor.execute(new DispatchDuplexConnection(t, d));
 	}
 
 	public void dispatchOutgoingConnection(ContactId c, TransportId t,
-			TransportIndex i, StreamTransportConnection s) {
-		streamConnFactory.createOutgoingConnection(c, t, i, s);
+			TransportIndex i, DuplexTransportConnection d) {
+		streamConnFactory.createOutgoingConnection(c, t, i, d);
 	}
 
 	private byte[] readTag(InputStream in) throws IOException {
@@ -75,13 +75,13 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
 		return b;
 	}
 
-	private class DispatchBatchConnection implements Runnable {
+	private class DispatchSimplexConnection implements Runnable {
 
 		private final TransportId transportId;
-		private final BatchTransportReader transport;
+		private final SimplexTransportReader transport;
 
-		private DispatchBatchConnection(TransportId transportId,
-				BatchTransportReader transport) {
+		private DispatchSimplexConnection(TransportId transportId,
+				SimplexTransportReader transport) {
 			this.transportId = transportId;
 			this.transport = transport;
 		}
@@ -104,13 +104,13 @@ class ConnectionDispatcherImpl implements ConnectionDispatcher {
 		}
 	}
 
-	private class DispatchStreamConnection implements Runnable {
+	private class DispatchDuplexConnection implements Runnable {
 
 		private final TransportId transportId;
-		private final StreamTransportConnection transport;
+		private final DuplexTransportConnection transport;
 
-		private DispatchStreamConnection(TransportId transportId,
-				StreamTransportConnection transport) {
+		private DispatchDuplexConnection(TransportId transportId,
+				DuplexTransportConnection transport) {
 			this.transportId = transportId;
 			this.transport = transport;
 		}
diff --git a/test/build.xml b/test/build.xml
index 3ee4485477db4dd32c4c613bf2c22b5fa001cbae..904f92fb1308403bffc6618c51d6848e484ae081 100644
--- a/test/build.xml
+++ b/test/build.xml
@@ -44,8 +44,8 @@
 			<test name='net.sf.briar.protocol.ProtocolWriterImplTest'/>
 			<test name='net.sf.briar.protocol.RequestReaderTest'/>
 			<test name='net.sf.briar.protocol.UnverifiedBatchImplTest'/>
-			<test name='net.sf.briar.protocol.batch.BatchConnectionReadWriteTest'/>
-			<test name='net.sf.briar.protocol.batch.OutgoingBatchConnectionTest'/>
+			<test name='net.sf.briar.protocol.simplex.OutgoingSimplexConnectionTest'/>
+			<test name='net.sf.briar.protocol.simplex.SimplexConnectionReadWriteTest'/>
 			<test name='net.sf.briar.serial.ReaderImplTest'/>
 			<test name='net.sf.briar.serial.WriterImplTest'/>
 			<test name='net.sf.briar.setup.SetupWorkerTest'/>
diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java
index 49f334c30f8006174c08b1de87373d417f641704..45455525034b2f775449722b114160704d3ce4e9 100644
--- a/test/net/sf/briar/ProtocolIntegrationTest.java
+++ b/test/net/sf/briar/ProtocolIntegrationTest.java
@@ -49,8 +49,8 @@ import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.db.DatabaseModule;
 import net.sf.briar.lifecycle.LifecycleModule;
 import net.sf.briar.protocol.ProtocolModule;
-import net.sf.briar.protocol.batch.ProtocolBatchModule;
-import net.sf.briar.protocol.stream.ProtocolStreamModule;
+import net.sf.briar.protocol.duplex.DuplexProtocolModule;
+import net.sf.briar.protocol.simplex.SimplexProtocolModule;
 import net.sf.briar.serial.SerialModule;
 import net.sf.briar.transport.TransportModule;
 
@@ -85,8 +85,8 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 		Injector i = Guice.createInjector(new CryptoModule(),
 				new DatabaseModule(), new LifecycleModule(),
 				new ProtocolModule(), new SerialModule(),
-				new TestDatabaseModule(), new ProtocolBatchModule(),
-				new TransportModule(), new ProtocolStreamModule());
+				new TestDatabaseModule(), new SimplexProtocolModule(),
+				new TransportModule(), new DuplexProtocolModule());
 		connectionReaderFactory = i.getInstance(ConnectionReaderFactory.class);
 		connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class);
 		protocolReaderFactory = i.getInstance(ProtocolReaderFactory.class);
diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java
index 6d8b812a9b3992575b992e646c3a0f89134f6121..e8f55a275f1eb1d41ed61f82fd3f9a08bdd77794 100644
--- a/test/net/sf/briar/db/H2DatabaseTest.java
+++ b/test/net/sf/briar/db/H2DatabaseTest.java
@@ -44,8 +44,8 @@ import net.sf.briar.api.transport.ConnectionWindowFactory;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.lifecycle.LifecycleModule;
 import net.sf.briar.protocol.ProtocolModule;
-import net.sf.briar.protocol.batch.ProtocolBatchModule;
-import net.sf.briar.protocol.stream.ProtocolStreamModule;
+import net.sf.briar.protocol.duplex.DuplexProtocolModule;
+import net.sf.briar.protocol.simplex.SimplexProtocolModule;
 import net.sf.briar.serial.SerialModule;
 import net.sf.briar.transport.TransportModule;
 
@@ -96,8 +96,8 @@ public class H2DatabaseTest extends BriarTestCase {
 		Injector i = Guice.createInjector(new CryptoModule(),
 				new DatabaseModule(), new LifecycleModule(),
 				new ProtocolModule(), new SerialModule(),
-				new ProtocolBatchModule(), new TransportModule(),
-				new ProtocolStreamModule(), new TestDatabaseModule(testDir));
+				new SimplexProtocolModule(), new TransportModule(),
+				new DuplexProtocolModule(), new TestDatabaseModule(testDir));
 		connectionContextFactory =
 			i.getInstance(ConnectionContextFactory.class);
 		connectionWindowFactory = i.getInstance(ConnectionWindowFactory.class);
diff --git a/test/net/sf/briar/plugins/StreamClientTest.java b/test/net/sf/briar/plugins/DuplexClientTest.java
similarity index 74%
rename from test/net/sf/briar/plugins/StreamClientTest.java
rename to test/net/sf/briar/plugins/DuplexClientTest.java
index 2607099fcbbfc0e55e7eaf837891ede04a976265..9e11a93e043b3473523d73bef8ca10928e1c85c0 100644
--- a/test/net/sf/briar/plugins/StreamClientTest.java
+++ b/test/net/sf/briar/plugins/DuplexClientTest.java
@@ -6,10 +6,10 @@ import java.util.Map;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 
-public abstract class StreamClientTest extends StreamTest {
+public abstract class DuplexClientTest extends DuplexTest {
 
 	protected ClientCallback callback = null;
 
@@ -20,37 +20,37 @@ public abstract class StreamClientTest extends StreamTest {
 		plugin.start();
 		// Try to connect to the server
 		System.out.println("Creating connection");
-		StreamTransportConnection s = plugin.createConnection(contactId);
-		if(s == null) {
+		DuplexTransportConnection d = plugin.createConnection(contactId);
+		if(d == null) {
 			System.out.println("Connection failed");
 		} else {
 			System.out.println("Connection created");
-			receiveChallengeSendResponse(s);
+			receiveChallengeSendResponse(d);
 		}
 		// Try to send an invitation
 		System.out.println("Sending invitation");
-		s = plugin.sendInvitation(123, INVITATION_TIMEOUT);
-		if(s == null) {
+		d = plugin.sendInvitation(123, INVITATION_TIMEOUT);
+		if(d == null) {
 			System.out.println("Connection failed");
 		} else {
 			System.out.println("Connection created");
-			receiveChallengeSendResponse(s);
+			receiveChallengeSendResponse(d);
 		}
 		// Try to accept an invitation
 		System.out.println("Accepting invitation");
-		s = plugin.acceptInvitation(456, INVITATION_TIMEOUT);
-		if(s == null) {
+		d = plugin.acceptInvitation(456, INVITATION_TIMEOUT);
+		if(d == null) {
 			System.out.println("Connection failed");
 		} else {
 			System.out.println("Connection created");
-			sendChallengeReceiveResponse(s);
+			sendChallengeReceiveResponse(d);
 		}
 		// Stop the plugin
 		System.out.println("Stopping plugin");
 		plugin.stop();
 	}
 
-	protected static class ClientCallback implements StreamPluginCallback {
+	protected static class ClientCallback implements DuplexPluginCallback {
 
 		private TransportConfig config = null;
 		private TransportProperties local = null;
@@ -93,9 +93,9 @@ public abstract class StreamClientTest extends StreamTest {
 
 		public void showMessage(String... message) {}
 
-		public void incomingConnectionCreated(StreamTransportConnection c) {}
+		public void incomingConnectionCreated(DuplexTransportConnection d) {}
 
 		public void outgoingConnectionCreated(ContactId contactId,
-				StreamTransportConnection c) {}
+				DuplexTransportConnection d) {}
 	}
 }
diff --git a/test/net/sf/briar/plugins/StreamServerTest.java b/test/net/sf/briar/plugins/DuplexServerTest.java
similarity index 75%
rename from test/net/sf/briar/plugins/StreamServerTest.java
rename to test/net/sf/briar/plugins/DuplexServerTest.java
index ecf65e76affea8c002a0b9975b68adc329940f98..0681010363ae9cf4de8c750746ac7ced8bf7d952 100644
--- a/test/net/sf/briar/plugins/StreamServerTest.java
+++ b/test/net/sf/briar/plugins/DuplexServerTest.java
@@ -6,10 +6,10 @@ import java.util.concurrent.CountDownLatch;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 
-public abstract class StreamServerTest extends StreamTest {
+public abstract class DuplexServerTest extends DuplexTest {
 
 	protected ServerCallback callback = null;
 
@@ -24,29 +24,29 @@ public abstract class StreamServerTest extends StreamTest {
 		callback.latch.await();
 		// Try to accept an invitation
 		System.out.println("Accepting invitation");
-		StreamTransportConnection s = plugin.acceptInvitation(123,
+		DuplexTransportConnection d = plugin.acceptInvitation(123,
 				INVITATION_TIMEOUT);
-		if(s == null) {
+		if(d == null) {
 			System.out.println("Connection failed");
 		} else {
 			System.out.println("Connection created");
-			sendChallengeReceiveResponse(s);
+			sendChallengeReceiveResponse(d);
 		}
 		// Try to send an invitation
 		System.out.println("Sending invitation");
-		s = plugin.sendInvitation(456, INVITATION_TIMEOUT);
-		if(s == null) {
+		d = plugin.sendInvitation(456, INVITATION_TIMEOUT);
+		if(d == null) {
 			System.out.println("Connection failed");
 		} else {
 			System.out.println("Connection created");
-			receiveChallengeSendResponse(s);
+			receiveChallengeSendResponse(d);
 		}
 		// Stop the plugin
 		System.out.println("Stopping plugin");
 		plugin.stop();
 	}
 
-	protected class ServerCallback implements StreamPluginCallback {
+	protected class ServerCallback implements DuplexPluginCallback {
 
 		private final CountDownLatch latch = new CountDownLatch(1);
 
@@ -91,13 +91,13 @@ public abstract class StreamServerTest extends StreamTest {
 
 		public void showMessage(String... message) {}
 
-		public void incomingConnectionCreated(StreamTransportConnection s) {
+		public void incomingConnectionCreated(DuplexTransportConnection d) {
 			System.out.println("Connection received");
-			sendChallengeReceiveResponse(s);
+			sendChallengeReceiveResponse(d);
 			latch.countDown();
 		}
 
-		public void outgoingConnectionCreated(ContactId contactId,
-				StreamTransportConnection c) {}
+		public void outgoingConnectionCreated(ContactId c,
+				DuplexTransportConnection d) {}
 	}
 }
diff --git a/test/net/sf/briar/plugins/StreamTest.java b/test/net/sf/briar/plugins/DuplexTest.java
similarity index 67%
rename from test/net/sf/briar/plugins/StreamTest.java
rename to test/net/sf/briar/plugins/DuplexTest.java
index ecb3f6bacfbf7a865e79699b7be386e4aafbb3be..586acb928a51d5121cf2c42a452e5b80672be57e 100644
--- a/test/net/sf/briar/plugins/StreamTest.java
+++ b/test/net/sf/briar/plugins/DuplexTest.java
@@ -5,10 +5,10 @@ import java.io.PrintStream;
 import java.util.Scanner;
 
 import net.sf.briar.api.ContactId;
-import net.sf.briar.api.plugins.StreamPlugin;
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexPlugin;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 
-abstract class StreamTest {
+abstract class DuplexTest {
 
 	protected static final String CHALLENGE = "Carrots!";
 	protected static final String RESPONSE = "Potatoes!";
@@ -16,15 +16,15 @@ abstract class StreamTest {
 
 	protected final ContactId contactId = new ContactId(0);
 
-	protected StreamPlugin plugin = null;
+	protected DuplexPlugin plugin = null;
 
-	protected void sendChallengeReceiveResponse(StreamTransportConnection s) {
+	protected void sendChallengeReceiveResponse(DuplexTransportConnection d) {
 		assert plugin != null;
 		try {
-			PrintStream out = new PrintStream(s.getOutputStream());
+			PrintStream out = new PrintStream(d.getOutputStream());
 			out.println(CHALLENGE);
 			System.out.println("Sent challenge: " + CHALLENGE);
-			Scanner in = new Scanner(s.getInputStream());
+			Scanner in = new Scanner(d.getInputStream());
 			if(in.hasNextLine()) {
 				String response = in.nextLine();
 				System.out.println("Received response: " + response);
@@ -36,22 +36,22 @@ abstract class StreamTest {
 			} else {
 				System.out.println("No response");
 			}
-			s.dispose(false, true);
+			d.dispose(false, true);
 		} catch(IOException e) {
 			e.printStackTrace();
-			s.dispose(true, true);
+			d.dispose(true, true);
 		}
 	}
 
-	protected void receiveChallengeSendResponse(StreamTransportConnection s) {
+	protected void receiveChallengeSendResponse(DuplexTransportConnection d) {
 		assert plugin != null;
 		try {
-			Scanner in = new Scanner(s.getInputStream());
+			Scanner in = new Scanner(d.getInputStream());
 			if(in.hasNextLine()) {
 				String challenge = in.nextLine();
 				System.out.println("Received challenge: " + challenge);
 				if(CHALLENGE.equals(challenge)) {
-					PrintStream out = new PrintStream(s.getOutputStream());
+					PrintStream out = new PrintStream(d.getOutputStream());
 					out.println(RESPONSE);
 					System.out.println("Sent response: " + RESPONSE);
 				} else {
@@ -60,10 +60,10 @@ abstract class StreamTest {
 			} else {
 				System.out.println("No challenge");
 			}
-			s.dispose(false, true);
+			d.dispose(false, true);
 		} catch(IOException e) {
 			e.printStackTrace();
-			s.dispose(true, true);
+			d.dispose(true, true);
 		}
 	}
 }
diff --git a/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java b/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java
index 4e464e7c3c7d681d7f43318a8c3599f86c6383bb..51a85f7f0e3f5b684b82f06366f9d572057c8e78 100644
--- a/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java
+++ b/test/net/sf/briar/plugins/bluetooth/BluetoothClientTest.java
@@ -9,11 +9,11 @@ import java.util.concurrent.Executors;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
-import net.sf.briar.plugins.StreamClientTest;
+import net.sf.briar.plugins.DuplexClientTest;
 
 // This is not a JUnit test - it has to be run manually while the server test
 // is running on another machine
-public class BluetoothClientTest extends StreamClientTest {
+public class BluetoothClientTest extends DuplexClientTest {
 
 	private BluetoothClientTest(Executor executor, String serverAddress) {
 		// Store the server's Bluetooth address and UUID
diff --git a/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java b/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java
index 956edff546869641770124b778586e70fe98982c..9a492f37fea21ac3f7caa958f1f7fa9d62db99aa 100644
--- a/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java
+++ b/test/net/sf/briar/plugins/bluetooth/BluetoothServerTest.java
@@ -7,11 +7,11 @@ import java.util.concurrent.Executors;
 
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
-import net.sf.briar.plugins.StreamServerTest;
+import net.sf.briar.plugins.DuplexServerTest;
 
 // This is not a JUnit test - it has to be run manually while the client test
 // is running on another machine
-public class BluetoothServerTest extends StreamServerTest {
+public class BluetoothServerTest extends DuplexServerTest {
 
 	private BluetoothServerTest(Executor executor) {
 		// Store the UUID
diff --git a/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
index 3b07c80d3d76872a6c59384d9e78c7152c3c8bd5..d12edcf82980d806dc3648053d692ef7a0b9fd39 100644
--- a/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
+++ b/test/net/sf/briar/plugins/file/RemovableDrivePluginTest.java
@@ -13,8 +13,8 @@ import java.util.concurrent.Executor;
 import net.sf.briar.BriarTestCase;
 import net.sf.briar.TestUtils;
 import net.sf.briar.api.ContactId;
-import net.sf.briar.api.plugins.BatchPluginCallback;
-import net.sf.briar.api.transport.BatchTransportWriter;
+import net.sf.briar.api.plugins.SimplexPluginCallback;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 import net.sf.briar.api.transport.TransportConstants;
 import net.sf.briar.plugins.ImmediateExecutor;
 import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback;
@@ -39,8 +39,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 	public void testGetId() {
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -61,8 +61,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -93,8 +93,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -130,8 +130,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -169,8 +169,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -208,8 +208,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -250,8 +250,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -271,7 +271,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 				callback, finder, monitor);
 		plugin.start();
 
-		BatchTransportWriter writer = plugin.createWriter(contactId);
+		SimplexTransportWriter writer = plugin.createWriter(contactId);
 		assertNotNull(writer);
 		// The output file should exist and should be empty
 		File[] files = drive1.listFiles();
@@ -295,8 +295,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 	public void testEmptyDriveIsIgnored() throws Exception {
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -319,8 +319,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 	public void testFilenames() {
 		Mockery context = new Mockery();
 		final Executor executor = context.mock(Executor.class);
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
@@ -342,8 +342,8 @@ public class RemovableDrivePluginTest extends BriarTestCase {
 	@Test
 	public void testReaderIsCreated() throws Exception {
 		Mockery context = new Mockery();
-		final BatchPluginCallback callback =
-			context.mock(BatchPluginCallback.class);
+		final SimplexPluginCallback callback =
+			context.mock(SimplexPluginCallback.class);
 		final RemovableDriveFinder finder =
 			context.mock(RemovableDriveFinder.class);
 		final RemovableDriveMonitor monitor =
diff --git a/test/net/sf/briar/plugins/socket/LanSocketClientTest.java b/test/net/sf/briar/plugins/socket/LanSocketClientTest.java
index 6031b4b721f805a6e61d8a9b355ebb6f34040bb3..72be342cb2d6329404d13ba49c7b2c02c882dd27 100644
--- a/test/net/sf/briar/plugins/socket/LanSocketClientTest.java
+++ b/test/net/sf/briar/plugins/socket/LanSocketClientTest.java
@@ -9,11 +9,11 @@ import java.util.concurrent.Executor;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
-import net.sf.briar.plugins.StreamClientTest;
+import net.sf.briar.plugins.DuplexClientTest;
 
 // This is not a JUnit test - it has to be run manually while the server test
 // is running on another machine
-public class LanSocketClientTest extends StreamClientTest {
+public class LanSocketClientTest extends DuplexClientTest {
 
 	private LanSocketClientTest(Executor executor, String serverAddress,
 			String serverPort) {
diff --git a/test/net/sf/briar/plugins/socket/LanSocketServerTest.java b/test/net/sf/briar/plugins/socket/LanSocketServerTest.java
index cf88b3b23faeced6d33b927174ae21dbe9a87d76..414d03116dd70ae394d9b3df26167f0a4377f4d1 100644
--- a/test/net/sf/briar/plugins/socket/LanSocketServerTest.java
+++ b/test/net/sf/briar/plugins/socket/LanSocketServerTest.java
@@ -7,11 +7,11 @@ import java.util.concurrent.Executors;
 
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
-import net.sf.briar.plugins.StreamServerTest;
+import net.sf.briar.plugins.DuplexServerTest;
 
 // This is not a JUnit test - it has to be run manually while the client test
 // is running on another machine
-public class LanSocketServerTest extends StreamServerTest {
+public class LanSocketServerTest extends DuplexServerTest {
 
 	private LanSocketServerTest(Executor executor) {
 		callback = new ServerCallback(new TransportConfig(),
diff --git a/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
index c1b9ded937d5a1b413a8b82a44f38d2cc2500b5d..e9aec16c7156a680d8501c08c31f493496dacce1 100644
--- a/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
+++ b/test/net/sf/briar/plugins/socket/SimpleSocketPluginTest.java
@@ -16,8 +16,8 @@ import net.sf.briar.BriarTestCase;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportConfig;
 import net.sf.briar.api.TransportProperties;
-import net.sf.briar.api.plugins.StreamPluginCallback;
-import net.sf.briar.api.transport.StreamTransportConnection;
+import net.sf.briar.api.plugins.DuplexPluginCallback;
+import net.sf.briar.api.plugins.DuplexTransportConnection;
 
 import org.junit.Test;
 
@@ -27,7 +27,7 @@ public class SimpleSocketPluginTest extends BriarTestCase {
 
 	@Test
 	public void testIncomingConnection() throws Exception {
-		StreamCallback callback = new StreamCallback();
+		Callback callback = new Callback();
 		callback.local.put("internal", "127.0.0.1");
 		callback.local.put("port", "0");
 		Executor e = Executors.newCachedThreadPool();
@@ -63,7 +63,7 @@ public class SimpleSocketPluginTest extends BriarTestCase {
 
 	@Test
 	public void testOutgoingConnection() throws Exception {
-		StreamCallback callback = new StreamCallback();
+		Callback callback = new Callback();
 		Executor e = Executors.newCachedThreadPool();
 		SimpleSocketPlugin plugin = new SimpleSocketPlugin(e, callback, 0L);
 		plugin.start();
@@ -90,18 +90,18 @@ public class SimpleSocketPluginTest extends BriarTestCase {
 		p.put("port", String.valueOf(port));
 		callback.remote.put(contactId, p);
 		// Connect to the port
-		StreamTransportConnection conn = plugin.createConnection(contactId);
-		assertNotNull(conn);
+		DuplexTransportConnection d = plugin.createConnection(contactId);
+		assertNotNull(d);
 		// Check that the connection was accepted
 		assertTrue(latch.await(1, TimeUnit.SECONDS));
 		assertFalse(error.get());
 		// Clean up
-		conn.dispose(false, true);
+		d.dispose(false, true);
 		ss.close();
 		plugin.stop();
 	}
 
-	private static class StreamCallback implements StreamPluginCallback {
+	private static class Callback implements DuplexPluginCallback {
 
 		private final Map<ContactId, TransportProperties> remote =
 			new HashMap<ContactId, TransportProperties>();
@@ -143,12 +143,11 @@ public class SimpleSocketPluginTest extends BriarTestCase {
 
 		public void showMessage(String... message) {}
 
-		public void incomingConnectionCreated(StreamTransportConnection c) {
+		public void incomingConnectionCreated(DuplexTransportConnection d) {
 			incomingConnections++;
 		}
 
-		public void outgoingConnectionCreated(ContactId contactId,
-				StreamTransportConnection c) {
-		}
+		public void outgoingConnectionCreated(ContactId c,
+				DuplexTransportConnection d) {}
 	}
 }
diff --git a/test/net/sf/briar/protocol/batch/OutgoingBatchConnectionTest.java b/test/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java
similarity index 86%
rename from test/net/sf/briar/protocol/batch/OutgoingBatchConnectionTest.java
rename to test/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java
index a4b3bbfeced81459a37b0b0f4820b4b9d7f8098b..d469c60ab438d7b717914a5fdb27230a5d7bb3fc 100644
--- a/test/net/sf/briar/protocol/batch/OutgoingBatchConnectionTest.java
+++ b/test/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java
@@ -1,4 +1,4 @@
-package net.sf.briar.protocol.batch;
+package net.sf.briar.protocol.simplex;
 
 import java.io.ByteArrayOutputStream;
 import java.util.Collections;
@@ -24,7 +24,8 @@ import net.sf.briar.api.transport.ConnectionWriterFactory;
 import net.sf.briar.api.transport.TransportConstants;
 import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.protocol.ProtocolModule;
-import net.sf.briar.protocol.stream.ProtocolStreamModule;
+import net.sf.briar.protocol.duplex.DuplexProtocolModule;
+import net.sf.briar.protocol.simplex.SimplexProtocolModule;
 import net.sf.briar.serial.SerialModule;
 import net.sf.briar.transport.TransportModule;
 
@@ -37,7 +38,7 @@ import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Module;
 
-public class OutgoingBatchConnectionTest extends BriarTestCase {
+public class OutgoingSimplexConnectionTest extends BriarTestCase {
 
 	private final Mockery context;
 	private final DatabaseComponent db;
@@ -49,7 +50,7 @@ public class OutgoingBatchConnectionTest extends BriarTestCase {
 	private final TransportIndex transportIndex;
 	private final byte[] secret;
 
-	public OutgoingBatchConnectionTest() {
+	public OutgoingSimplexConnectionTest() {
 		super();
 		context = new Mockery();
 		db = context.mock(DatabaseComponent.class);
@@ -64,8 +65,8 @@ public class OutgoingBatchConnectionTest extends BriarTestCase {
 		};
 		Injector i = Guice.createInjector(testModule, new CryptoModule(),
 				new SerialModule(), new TransportModule(),
-				new ProtocolBatchModule(), new ProtocolModule(),
-				new ProtocolStreamModule());
+				new SimplexProtocolModule(), new ProtocolModule(),
+				new DuplexProtocolModule());
 		connRegistry = i.getInstance(ConnectionRegistry.class);
 		connFactory = i.getInstance(ConnectionWriterFactory.class);
 		protoFactory = i.getInstance(ProtocolWriterFactory.class);
@@ -78,9 +79,9 @@ public class OutgoingBatchConnectionTest extends BriarTestCase {
 	@Test
 	public void testConnectionTooShort() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
-				ProtocolConstants.MAX_PACKET_LENGTH, true);
-		OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
+		TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
+				out, ProtocolConstants.MAX_PACKET_LENGTH, true);
+		OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
 				connRegistry, connFactory, protoFactory, contactId, transportId,
 				transportIndex, transport);
 		final ConnectionContext ctx = context.mock(ConnectionContext.class);
@@ -102,9 +103,9 @@ public class OutgoingBatchConnectionTest extends BriarTestCase {
 	@Test
 	public void testNothingToSend() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
-				TransportConstants.MIN_CONNECTION_LENGTH, true);
-		OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
+		TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
+				out, TransportConstants.MIN_CONNECTION_LENGTH, true);
+		OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
 				connRegistry, connFactory, protoFactory, contactId, transportId,
 				transportIndex, transport);
 		final ConnectionContext ctx = context.mock(ConnectionContext.class);
@@ -138,9 +139,9 @@ public class OutgoingBatchConnectionTest extends BriarTestCase {
 	@Test
 	public void testSomethingToSend() throws Exception {
 		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
-				TransportConstants.MIN_CONNECTION_LENGTH, true);
-		OutgoingBatchConnection connection = new OutgoingBatchConnection(db,
+		TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
+				out, TransportConstants.MIN_CONNECTION_LENGTH, true);
+		OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
 				connRegistry, connFactory, protoFactory, contactId, transportId,
 				transportIndex, transport);
 		final ConnectionContext ctx = context.mock(ConnectionContext.class);
diff --git a/test/net/sf/briar/protocol/batch/BatchConnectionReadWriteTest.java b/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
similarity index 90%
rename from test/net/sf/briar/protocol/batch/BatchConnectionReadWriteTest.java
rename to test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
index c695a26634f69c3776a0a60da2d1a7e30bc22546..dd7c14ca128a36b79034a8b98523d26406db257b 100644
--- a/test/net/sf/briar/protocol/batch/BatchConnectionReadWriteTest.java
+++ b/test/net/sf/briar/protocol/simplex/SimplexConnectionReadWriteTest.java
@@ -1,4 +1,4 @@
-package net.sf.briar.protocol.batch;
+package net.sf.briar.protocol.simplex;
 
 import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
 
@@ -35,7 +35,8 @@ import net.sf.briar.db.DatabaseModule;
 import net.sf.briar.lifecycle.LifecycleModule;
 import net.sf.briar.plugins.ImmediateExecutor;
 import net.sf.briar.protocol.ProtocolModule;
-import net.sf.briar.protocol.stream.ProtocolStreamModule;
+import net.sf.briar.protocol.duplex.DuplexProtocolModule;
+import net.sf.briar.protocol.simplex.SimplexProtocolModule;
 import net.sf.briar.serial.SerialModule;
 import net.sf.briar.transport.TransportModule;
 
@@ -46,7 +47,7 @@ import org.junit.Test;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
-public class BatchConnectionReadWriteTest extends BriarTestCase {
+public class SimplexConnectionReadWriteTest extends BriarTestCase {
 
 	private final File testDir = TestUtils.getTestDirectory();
 	private final File aliceDir = new File(testDir, "alice");
@@ -57,7 +58,7 @@ public class BatchConnectionReadWriteTest extends BriarTestCase {
 
 	private Injector alice, bob;
 
-	public BatchConnectionReadWriteTest() throws Exception {
+	public SimplexConnectionReadWriteTest() throws Exception {
 		super();
 		transportId = new TransportId(TestUtils.getRandomId());
 		transportIndex = new TransportIndex(1);
@@ -79,8 +80,8 @@ public class BatchConnectionReadWriteTest extends BriarTestCase {
 	private Injector createInjector(File dir) {
 		return Guice.createInjector(new CryptoModule(), new DatabaseModule(),
 				new LifecycleModule(), new ProtocolModule(), new SerialModule(),
-				new TestDatabaseModule(dir), new ProtocolBatchModule(),
-				new TransportModule(), new ProtocolStreamModule());
+				new TestDatabaseModule(dir), new SimplexProtocolModule(),
+				new TransportModule(), new DuplexProtocolModule());
 	}
 
 	@Test
@@ -114,9 +115,9 @@ public class BatchConnectionReadWriteTest extends BriarTestCase {
 			alice.getInstance(ConnectionWriterFactory.class);
 		ProtocolWriterFactory protoFactory =
 			alice.getInstance(ProtocolWriterFactory.class);
-		TestBatchTransportWriter transport = new TestBatchTransportWriter(out,
+		TestSimplexTransportWriter transport = new TestSimplexTransportWriter(out,
 				Long.MAX_VALUE, false);
-		OutgoingBatchConnection batchOut = new OutgoingBatchConnection(db,
+		OutgoingSimplexConnection batchOut = new OutgoingSimplexConnection(db,
 				connRegistry, connFactory, protoFactory, contactId, transportId,
 				transportIndex, transport);
 		// Write whatever needs to be written
@@ -170,8 +171,8 @@ public class BatchConnectionReadWriteTest extends BriarTestCase {
 			bob.getInstance(ConnectionReaderFactory.class);
 		ProtocolReaderFactory protoFactory =
 			bob.getInstance(ProtocolReaderFactory.class);
-		TestBatchTransportReader transport = new TestBatchTransportReader(in);
-		IncomingBatchConnection batchIn = new IncomingBatchConnection(
+		TestSimplexTransportReader transport = new TestSimplexTransportReader(in);
+		IncomingSimplexConnection batchIn = new IncomingSimplexConnection(
 				new ImmediateExecutor(), new ImmediateExecutor(), db,
 				connRegistry, connFactory, protoFactory, ctx, transportId,
 				transport, tag);
diff --git a/test/net/sf/briar/protocol/batch/TestBatchTransportReader.java b/test/net/sf/briar/protocol/simplex/TestSimplexTransportReader.java
similarity index 71%
rename from test/net/sf/briar/protocol/batch/TestBatchTransportReader.java
rename to test/net/sf/briar/protocol/simplex/TestSimplexTransportReader.java
index c68a7e61b84779a4c6e3443ed8f741e7469cea91..c8ccd632c8d1c4666a36e4f8981f612fbdb3b615 100644
--- a/test/net/sf/briar/protocol/batch/TestBatchTransportReader.java
+++ b/test/net/sf/briar/protocol/simplex/TestSimplexTransportReader.java
@@ -1,16 +1,16 @@
-package net.sf.briar.protocol.batch;
+package net.sf.briar.protocol.simplex;
 
 import java.io.InputStream;
 
-import net.sf.briar.api.transport.BatchTransportReader;
+import net.sf.briar.api.plugins.SimplexTransportReader;
 
-class TestBatchTransportReader implements BatchTransportReader {
+class TestSimplexTransportReader implements SimplexTransportReader {
 
 	private final InputStream in;
 
 	private boolean disposed = false, exception = false, recognised = false;
 
-	TestBatchTransportReader(InputStream in) {
+	TestSimplexTransportReader(InputStream in) {
 		this.in = in;
 	}
 
diff --git a/test/net/sf/briar/protocol/batch/TestBatchTransportWriter.java b/test/net/sf/briar/protocol/simplex/TestSimplexTransportWriter.java
similarity index 74%
rename from test/net/sf/briar/protocol/batch/TestBatchTransportWriter.java
rename to test/net/sf/briar/protocol/simplex/TestSimplexTransportWriter.java
index c3afcd2906c7d861278635c96a87e0151cccae36..82a8c9e2336df2ad325269fc734a521c5e6ce66f 100644
--- a/test/net/sf/briar/protocol/batch/TestBatchTransportWriter.java
+++ b/test/net/sf/briar/protocol/simplex/TestSimplexTransportWriter.java
@@ -1,11 +1,11 @@
-package net.sf.briar.protocol.batch;
+package net.sf.briar.protocol.simplex;
 
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStream;
 
-import net.sf.briar.api.transport.BatchTransportWriter;
+import net.sf.briar.api.plugins.SimplexTransportWriter;
 
-class TestBatchTransportWriter implements BatchTransportWriter {
+class TestSimplexTransportWriter implements SimplexTransportWriter {
 
 	private final ByteArrayOutputStream out;
 	private final long capacity;
@@ -13,7 +13,7 @@ class TestBatchTransportWriter implements BatchTransportWriter {
 
 	private boolean disposed = false, exception = false;
 
-	TestBatchTransportWriter(ByteArrayOutputStream out, long capacity,
+	TestSimplexTransportWriter(ByteArrayOutputStream out, long capacity,
 			boolean flush) {
 		this.out = out;
 		this.capacity = capacity;
diff --git a/test/net/sf/briar/transport/ConnectionWriterTest.java b/test/net/sf/briar/transport/ConnectionWriterTest.java
index 2121c19f1641945d86a1ad071c4d56a7a9aa93dd..6c84bb12d36263a745c9dcf2f7d4a2b53ae5c21d 100644
--- a/test/net/sf/briar/transport/ConnectionWriterTest.java
+++ b/test/net/sf/briar/transport/ConnectionWriterTest.java
@@ -14,8 +14,8 @@ import net.sf.briar.crypto.CryptoModule;
 import net.sf.briar.db.DatabaseModule;
 import net.sf.briar.lifecycle.LifecycleModule;
 import net.sf.briar.protocol.ProtocolModule;
-import net.sf.briar.protocol.batch.ProtocolBatchModule;
-import net.sf.briar.protocol.stream.ProtocolStreamModule;
+import net.sf.briar.protocol.duplex.DuplexProtocolModule;
+import net.sf.briar.protocol.simplex.SimplexProtocolModule;
 import net.sf.briar.serial.SerialModule;
 
 import org.junit.Test;
@@ -33,8 +33,8 @@ public class ConnectionWriterTest extends BriarTestCase {
 		Injector i = Guice.createInjector(new CryptoModule(),
 				new DatabaseModule(), new LifecycleModule(),
 				new ProtocolModule(), new SerialModule(),
-				new TestDatabaseModule(), new ProtocolBatchModule(),
-				new TransportModule(), new ProtocolStreamModule());
+				new TestDatabaseModule(), new SimplexProtocolModule(),
+				new TransportModule(), new DuplexProtocolModule());
 		connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class);
 		secret = new byte[32];
 		new Random().nextBytes(secret);