diff --git a/api/net/sf/briar/api/db/DatabaseComponent.java b/api/net/sf/briar/api/db/DatabaseComponent.java
index db220b51220282505f11edf4206889dc2abb5e86..087b5a87b70ceb5adf3ce9cd136efd4e1177c4d5 100644
--- a/api/net/sf/briar/api/db/DatabaseComponent.java
+++ b/api/net/sf/briar/api/db/DatabaseComponent.java
@@ -50,7 +50,7 @@ public interface DatabaseComponent {
 	 * Adds a new contact to the database with the given transport properties
 	 * and shared secret, returns an ID for the contact.
 	 */
-	ContactId addContact(Map<String, Map<String, String>> transports,
+	ContactId addContact(Map<Integer, Map<String, String>> transports,
 			byte[] secret) throws DbException;
 
 	/** Adds a locally generated group message to the database. */
@@ -123,14 +123,14 @@ public interface DatabaseComponent {
 	/** Returns the set of groups to which the user subscribes. */
 	Collection<Group> getSubscriptions() throws DbException;
 
-	/** Returns the configuration for the transport with the given name. */
-	Map<String, String> getTransportConfig(String name) throws DbException;
+	/** Returns the configuration for the given transport. */
+	Map<String, String> getTransportConfig(int transportId) throws DbException;
 
 	/** Returns all local transport properties. */
-	Map<String, Map<String, String>> getTransports() throws DbException;
+	Map<Integer, Map<String, String>> getTransports() throws DbException;
 
 	/** Returns all transport properties for the given contact. */
-	Map<String, Map<String, String>> getTransports(ContactId c)
+	Map<Integer, Map<String, String>> getTransports(ContactId c)
 	throws DbException;
 
 	/** Returns the contacts to which the given group is visible. */
@@ -181,17 +181,17 @@ public interface DatabaseComponent {
 	void setSeen(ContactId c, Collection<MessageId> seen) throws DbException;
 
 	/**
-	 * Sets the configuration for the transport with the given name, replacing
-	 * any existing configuration for that transport.
+	 * Sets the configuration for the given transport, replacing any existing
+	 * configuration for that transport.
 	 */
-	void setTransportConfig(String name, Map<String, String> config)
+	void setTransportConfig(int transportId, Map<String, String> config)
 	throws DbException;
 
 	/**
-	 * Sets the transport properties for the transport with the given name,
-	 * replacing any existing properties for that transport.
+	 * Sets the transport properties for the given transport, replacing any
+	 * existing properties for that transport.
 	 */
-	void setTransportProperties(String name, Map<String, String> properties)
+	void setTransportProperties(int transportId, Map<String, String> properties)
 	throws DbException;
 
 	/**
diff --git a/api/net/sf/briar/api/protocol/TransportUpdate.java b/api/net/sf/briar/api/protocol/TransportUpdate.java
index e26883c2ca06a8bca2cdbd1ac9898f3b995c2058..b04940fe5d73dbdb06a229e92f2a5861bf6edc52 100644
--- a/api/net/sf/briar/api/protocol/TransportUpdate.java
+++ b/api/net/sf/briar/api/protocol/TransportUpdate.java
@@ -5,9 +5,6 @@ import java.util.Map;
 /** A packet updating the sender's transport properties. */
 public interface TransportUpdate {
 
-	/** The maximum length of a plugin's name in UTF-8 bytes. */
-	static final int MAX_NAME_LENGTH = 50;
-
 	/** The maximum length of a property's key or value in UTF-8 bytes. */
 	static final int MAX_KEY_OR_VALUE_LENGTH = 100;
 
@@ -18,7 +15,7 @@ public interface TransportUpdate {
 	static final int MAX_PLUGINS_PER_UPDATE = 50;
 
 	/** Returns the transport properties contained in the update. */
-	Map<String, Map<String, String>> getTransports();
+	Map<Integer, Map<String, String>> getTransports();
 
 	/**
 	 * Returns the update's timestamp. Updates that are older than the newest
diff --git a/api/net/sf/briar/api/protocol/writers/TransportWriter.java b/api/net/sf/briar/api/protocol/writers/TransportWriter.java
index 39257d6bbf16385618daca41ecbea68edb379e3f..9878de2ccfb2e96b6e21ce154557282e08fd8139 100644
--- a/api/net/sf/briar/api/protocol/writers/TransportWriter.java
+++ b/api/net/sf/briar/api/protocol/writers/TransportWriter.java
@@ -7,6 +7,6 @@ import java.util.Map;
 public interface TransportWriter {
 
 	/** Writes the contents of the update. */
-	void writeTransports(Map<String, Map<String, String>> transports,
+	void writeTransports(Map<Integer, Map<String, String>> transports,
 			long timestamp) throws IOException;
 }
diff --git a/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java b/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java
index bd810f8e61110414a38bc406a0aba4f1a06f7d24..26d07fcf22f7e562a9359acf95779744c16a6f0c 100644
--- a/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java
+++ b/api/net/sf/briar/api/transport/batch/BatchTransportPlugin.java
@@ -12,11 +12,8 @@ import net.sf.briar.api.transport.InvalidTransportException;
  */
 public interface BatchTransportPlugin {
 
-	/**
-	 * Returns the plugin's name, which is used to distinguish its transport
-	 * and configuration properties from those of other plugins.
-	 */
-	String getName();
+	/** Returns the plugin's transport identifier. */
+	int getTransportId();
 
 	/**
 	 * Starts the plugin. Any connections that are later initiated by contacts
diff --git a/api/net/sf/briar/api/transport/stream/StreamTransportPlugin.java b/api/net/sf/briar/api/transport/stream/StreamTransportPlugin.java
index 30c35047820f4cfc25d66ad2203907838cce967d..786635c7c04c8556cad4d1038c49ba369a48d705 100644
--- a/api/net/sf/briar/api/transport/stream/StreamTransportPlugin.java
+++ b/api/net/sf/briar/api/transport/stream/StreamTransportPlugin.java
@@ -12,11 +12,8 @@ import net.sf.briar.api.transport.InvalidTransportException;
  */
 public interface StreamTransportPlugin {
 
-	/**
-	 * Returns the plugin's name, which is used to distinguish its transport
-	 * and configuration properties from those of other plugins.
-	 */
-	String getName();
+	/** Returns the plugin's transport identifier. */
+	int getTransportId();
 
 	/**
 	 * Starts the plugin. Any connections that are later initiated by contacts
diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java
index 6f1141d27ef3873c161befb3793928e78c67cffc..3da87919f8705d3356311bf01526b56c8d3d0afc 100644
--- a/components/net/sf/briar/db/Database.java
+++ b/components/net/sf/briar/db/Database.java
@@ -83,7 +83,7 @@ interface Database<T> {
 	 * <p>
 	 * Locking: contacts write, transports write.
 	 */
-	ContactId addContact(T txn, Map<String, Map<String, String>> transports,
+	ContactId addContact(T txn, Map<Integer, Map<String, String>> transports,
 			byte[] secret) throws DbException;
 
 	/**
@@ -315,11 +315,11 @@ interface Database<T> {
 	Collection<Group> getSubscriptions(T txn, ContactId c) throws DbException;
 
 	/**
-	 * Returns the configuration for the transport with the given name.
+	 * Returns the configuration for the given transport.
 	 * <p>
 	 * Locking: transports read.
 	 */
-	Map<String, String> getTransportConfig(T txn, String name)
+	Map<String, String> getTransportConfig(T txn, int transportId)
 	throws DbException;
 
 	/**
@@ -327,14 +327,14 @@ interface Database<T> {
 	 * <p>
 	 * Locking: transports read.
 	 */
-	Map<String, Map<String, String>> getTransports(T txn) throws DbException;
+	Map<Integer, Map<String, String>> getTransports(T txn) throws DbException;
 
 	/**
 	 * Returns all transport properties for the given contact.
 	 * <p>
 	 * Locking: contacts read, transports read.
 	 */
-	Map<String, Map<String, String>> getTransports(T txn, ContactId c)
+	Map<Integer, Map<String, String>> getTransports(T txn, ContactId c)
 	throws DbException;
 
 	/**
@@ -471,21 +471,21 @@ interface Database<T> {
 	throws DbException;
 
 	/**
-	 * Sets the configuration for the transport with the given name, replacing
-	 * any existing configuration for that transport.
+	 * Sets the configuration for the given transport, replacing any existing
+	 * configuration for that transport.
 	 * <p>
 	 * Locking: transports write.
 	 */
-	void setTransportConfig(T txn, String name, Map<String, String> config)
+	void setTransportConfig(T txn, int transportId, Map<String, String> config)
 	throws DbException;
 
 	/**
-	 * Sets the transport properties for the transport with the given name,
-	 * replacing any existing properties for that transport.
+	 * Sets the transport properties for the given transport, replacing any
+	 * existing properties for that transport.
 	 * <p>
 	 * Locking: transports write.
 	 */
-	void setTransportProperties(T txn, String name,
+	void setTransportProperties(T txn, int transportId,
 			Map<String, String> properties) throws DbException;
 
 	/**
@@ -496,7 +496,7 @@ interface Database<T> {
 	 * Locking: contacts read, transports write.
 	 */
 	void setTransports(T txn, ContactId c,
-			Map<String, Map<String, String>> transports, long timestamp)
+			Map<Integer, Map<String, String>> transports, long timestamp)
 	throws DbException;
 
 	/**
diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java
index 25e90252778f07b204279190d25259daab64d98a..82f307fda33aa4258531b004236334a23b9f5b37 100644
--- a/components/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/components/net/sf/briar/db/DatabaseComponentImpl.java
@@ -117,7 +117,7 @@ DatabaseCleaner.Callback {
 		}
 	}
 
-	public ContactId addContact(Map<String, Map<String, String>> transports,
+	public ContactId addContact(Map<Integer, Map<String, String>> transports,
 			byte[] secret) throws DbException {
 		if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact");
 		ContactId c;
@@ -604,7 +604,7 @@ DatabaseCleaner.Callback {
 
 	public void generateTransportUpdate(ContactId c, TransportWriter t)
 	throws DbException, IOException {
-		Map<String, Map<String, String>> transports;
+		Map<Integer, Map<String, String>> transports;
 		long timestamp;
 		contactLock.readLock().lock();
 		try {
@@ -750,13 +750,14 @@ DatabaseCleaner.Callback {
 		}
 	}
 
-	public Map<String, String> getTransportConfig(String name)
+	public Map<String, String> getTransportConfig(int transportId)
 	throws DbException {
 		transportLock.readLock().lock();
 		try {
 			T txn = db.startTransaction();
 			try {
-				Map<String, String> config = db.getTransportConfig(txn, name);
+				Map<String, String> config =
+					db.getTransportConfig(txn, transportId);
 				db.commitTransaction(txn);
 				return config;
 			} catch(DbException e) {
@@ -768,12 +769,13 @@ DatabaseCleaner.Callback {
 		}
 	}
 
-	public Map<String, Map<String, String>> getTransports() throws DbException {
+	public Map<Integer, Map<String, String>> getTransports()
+	throws DbException {
 		transportLock.readLock().lock();
 		try {
 			T txn = db.startTransaction();
 			try {
-				Map<String, Map<String, String>> transports =
+				Map<Integer, Map<String, String>> transports =
 					db.getTransports(txn);
 				db.commitTransaction(txn);
 				return transports;
@@ -786,7 +788,7 @@ DatabaseCleaner.Callback {
 		}
 	}
 
-	public Map<String, Map<String, String>> getTransports(ContactId c)
+	public Map<Integer, Map<String, String>> getTransports(ContactId c)
 	throws DbException {
 		contactLock.readLock().lock();
 		try {
@@ -795,7 +797,7 @@ DatabaseCleaner.Callback {
 			try {
 				T txn = db.startTransaction();
 				try {
-					Map<String, Map<String, String>> transports =
+					Map<Integer, Map<String, String>> transports =
 						db.getTransports(txn, c);
 					db.commitTransaction(txn);
 					return transports;
@@ -1044,7 +1046,7 @@ DatabaseCleaner.Callback {
 			try {
 				T txn = db.startTransaction();
 				try {
-					Map<String, Map<String, String>> transports =
+					Map<Integer, Map<String, String>> transports =
 						t.getTransports();
 					db.setTransports(txn, c, transports, t.getTimestamp());
 					if(LOG.isLoggable(Level.FINE))
@@ -1218,16 +1220,17 @@ DatabaseCleaner.Callback {
 					+ indirect + " indirectly");
 	}
 
-	public void setTransportConfig(String name,
+	public void setTransportConfig(int transportId,
 			Map<String, String> config) throws DbException {
 		boolean changed = false;
 		transportLock.writeLock().lock();
 		try {
 			T txn = db.startTransaction();
 			try {
-				Map<String, String> old = db.getTransportConfig(txn, name);
+				Map<String, String> old =
+					db.getTransportConfig(txn, transportId);
 				if(!config.equals(old)) {
-					db.setTransportConfig(txn, name, config);
+					db.setTransportConfig(txn, transportId, config);
 					changed = true;
 				}
 				db.commitTransaction(txn);
@@ -1242,16 +1245,18 @@ DatabaseCleaner.Callback {
 		if(changed) callListeners(Event.TRANSPORTS_UPDATED);
 	}
 
-	public void setTransportProperties(String name,
+	public void setTransportProperties(int transportId,
 			Map<String, String> properties) throws DbException {
 		boolean changed = false;
 		transportLock.writeLock().lock();
 		try {
 			T txn = db.startTransaction();
 			try {
-				Map<String, String> old = db.getTransports(txn).get(name);
+				Map<Integer, Map<String, String>> transports =
+					db.getTransports(txn);
+				Map<String, String> old = transports.get(transportId);
 				if(!properties.equals(old)) {
-					db.setTransportProperties(txn, name, properties);
+					db.setTransportProperties(txn, transportId, properties);
 					changed = true;
 				}
 				db.commitTransaction(txn);
diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java
index 65f8b40e16e0d98727e44ad0af3fac4bdc958dbb..2b84f47d3518ed9ba249892e3987272f12fcb6fc 100644
--- a/components/net/sf/briar/db/JdbcDatabase.java
+++ b/components/net/sf/briar/db/JdbcDatabase.java
@@ -167,26 +167,26 @@ abstract class JdbcDatabase implements Database<Connection> {
 	private static final String CREATE_CONTACT_TRANSPORTS =
 		"CREATE TABLE contactTransports"
 		+ " (contactId INT NOT NULL,"
-		+ " name VARCHAR NOT NULL,"
+		+ " transportId INT NOT NULL,"
 		+ " key VARCHAR NOT NULL,"
 		+ " value VARCHAR NOT NULL,"
-		+ " PRIMARY KEY (contactId, name, key),"
+		+ " PRIMARY KEY (contactId, transportId, key),"
 		+ " FOREIGN KEY (contactId) REFERENCES contacts (contactId)"
 		+ " ON DELETE CASCADE)";
 
 	private static final String CREATE_TRANSPORTS =
 		"CREATE TABLE transports"
-		+ " (name VARCHAR NOT NULL,"
+		+ " (transportId INT NOT NULL,"
 		+ " key VARCHAR NOT NULL,"
 		+ " value VARCHAR NOT NULL,"
-		+ " PRIMARY KEY (name, key))";
+		+ " PRIMARY KEY (transportId, key))";
 
 	private static final String CREATE_TRANSPORT_CONFIG =
 		"CREATE TABLE transportConfig"
-		+ " (name VARCHAR NOT NULL,"
+		+ " (transportId INT NOT NULL,"
 		+ " key VARCHAR NOT NULL,"
 		+ " value VARCHAR NOT NULL,"
-		+ " PRIMARY KEY (name, key))";
+		+ " PRIMARY KEY (transportId, key))";
 
 	private static final String CREATE_CONNECTION_WINDOWS =
 		"CREATE TABLE connectionWindows"
@@ -455,7 +455,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 	}
 
 	public ContactId addContact(Connection txn,
-			Map<String, Map<String, String>> transports, byte[] secret)
+			Map<Integer, Map<String, String>> transports, byte[] secret)
 	throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
@@ -481,13 +481,13 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps.close();
 			// Store the contact's transport properties
 			sql = "INSERT INTO contactTransports"
-				+ " (contactId, name, key, value)"
+				+ " (contactId, transportId, key, value)"
 				+ " VALUES (?, ?, ?, ?)";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, c.getInt());
 			int batchSize = 0;
-			for(Entry<String, Map<String, String>> e : transports.entrySet()) {
-				ps.setString(2, e.getKey());
+			for(Entry<Integer, Map<String, String>> e : transports.entrySet()) {
+				ps.setInt(2, e.getKey());
 				for(Entry<String, String> e1 : e.getValue().entrySet()) {
 					ps.setString(3, e1.getKey());
 					ps.setString(4, e1.getValue());
@@ -1394,14 +1394,14 @@ abstract class JdbcDatabase implements Database<Connection> {
 	}
 
 	public Map<String, String> getTransportConfig(Connection txn,
-			String name) throws DbException {
+			int transportId) throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
 			String sql = "SELECT key, value FROM transportConfig"
-				+ " WHERE name = ?";
+				+ " WHERE transportId = ?";
 			ps = txn.prepareStatement(sql);
-			ps.setString(1, name);
+			ps.setInt(1, transportId);
 			rs = ps.executeQuery();
 			Map<String, String> config = new TreeMap<String, String>();
 			while(rs.next()) config.put(rs.getString(1), rs.getString(2));
@@ -1415,24 +1415,24 @@ abstract class JdbcDatabase implements Database<Connection> {
 		}
 	}
 
-	public Map<String, Map<String, String>> getTransports(Connection txn)
+	public Map<Integer, Map<String, String>> getTransports(Connection txn)
 	throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT name, key, value FROM transports"
-				+ " ORDER BY name";
+			String sql = "SELECT transportId, key, value FROM transports"
+				+ " ORDER BY transportId";
 			ps = txn.prepareStatement(sql);
 			rs = ps.executeQuery();
-			Map<String, Map<String, String>> transports =
-				new TreeMap<String, Map<String, String>>();
+			Map<Integer, Map<String, String>> transports =
+				new TreeMap<Integer, Map<String, String>>();
 			Map<String, String> properties = null;
-			String lastName = null;
+			Integer lastId = null;
 			while(rs.next()) {
-				String name = rs.getString(1);
-				if(!name.equals(lastName)) {
+				Integer transportId = rs.getInt(1);
+				if(!transportId.equals(lastId)) {
 					properties = new TreeMap<String, String>();
-					transports.put(name, properties);
+					transports.put(transportId, properties);
 				}
 				properties.put(rs.getString(2), rs.getString(3));
 			}
@@ -1446,26 +1446,26 @@ abstract class JdbcDatabase implements Database<Connection> {
 		}
 	}
 
-	public Map<String, Map<String, String>> getTransports(Connection txn,
+	public Map<Integer, Map<String, String>> getTransports(Connection txn,
 			ContactId c) throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT name, key, value FROM contactTransports"
+			String sql = "SELECT transportId, key, value FROM contactTransports"
 				+ " WHERE contactId = ?"
-				+ " ORDER BY name";
+				+ " ORDER BY transportId";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, c.getInt());
 			rs = ps.executeQuery();
-			Map<String, Map<String, String>> transports =
-				new TreeMap<String, Map<String, String>>();
+			Map<Integer, Map<String, String>> transports =
+				new TreeMap<Integer, Map<String, String>>();
 			Map<String, String> properties = null;
-			String lastName = null;
+			Integer lastId = null;
 			while(rs.next()) {
-				String name = rs.getString(1);
-				if(!name.equals(lastName)) {
+				Integer transportId = rs.getInt(1);
+				if(!transportId.equals(lastId)) {
 					properties = new TreeMap<String, String>();
-					transports.put(name, properties);
+					transports.put(transportId, properties);
 				}
 				properties.put(rs.getString(2), rs.getString(3));
 			}
@@ -2039,26 +2039,26 @@ abstract class JdbcDatabase implements Database<Connection> {
 		}
 	}
 
-	public void setTransportConfig(Connection txn, String name,
+	public void setTransportConfig(Connection txn, int transportId,
 			Map<String, String> config) throws DbException {
-		setTransportDetails(txn, name, config, "transportConfig");
+		setTransportDetails(txn, transportId, config, "transportConfig");
 	}
 
-	private void setTransportDetails(Connection txn, String name,
+	private void setTransportDetails(Connection txn, int transportId,
 			Map<String, String> details, String table) throws DbException {
 		PreparedStatement ps = null;
 		try {
-			// Delete any existing details for the named transport
-			String sql = "DELETE FROM " + table + " WHERE name = ?";
+			// Delete any existing details for the given transport
+			String sql = "DELETE FROM " + table + " WHERE transportId = ?";
 			ps = txn.prepareStatement(sql);
-			ps.setString(1, name);
+			ps.setInt(1, transportId);
 			ps.executeUpdate();
 			ps.close();
 			// Store the new details
-			sql = "INSERT INTO " + table + " (name, key, value)"
+			sql = "INSERT INTO " + table + " (transportId, key, value)"
 			+ " VALUES (?, ?, ?)";
 			ps = txn.prepareStatement(sql);
-			ps.setString(1, name);
+			ps.setInt(1, transportId);
 			for(Entry<String, String> e : details.entrySet()) {
 				ps.setString(2, e.getKey());
 				ps.setString(3, e.getValue());
@@ -2077,13 +2077,13 @@ abstract class JdbcDatabase implements Database<Connection> {
 		}
 	}
 
-	public void setTransportProperties(Connection txn, String name,
+	public void setTransportProperties(Connection txn, int transportId,
 			Map<String, String> properties) throws DbException {
-		setTransportDetails(txn, name, properties, "transports");
+		setTransportDetails(txn, transportId, properties, "transports");
 	}
 
 	public void setTransports(Connection txn, ContactId c,
-			Map<String, Map<String, String>> transports, long timestamp)
+			Map<Integer, Map<String, String>> transports, long timestamp)
 	throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
@@ -2107,13 +2107,14 @@ abstract class JdbcDatabase implements Database<Connection> {
 			ps.executeUpdate();
 			ps.close();
 			// Store the new transports
-			sql = "INSERT INTO contactTransports (contactId, name, key, value)"
+			sql = "INSERT INTO contactTransports"
+				+ " (contactId, transportId, key, value)"
 				+ " VALUES (?, ?, ?, ?)";
 			ps = txn.prepareStatement(sql);
 			ps.setInt(1, c.getInt());
 			int batchSize = 0;
-			for(Entry<String, Map<String, String>> e : transports.entrySet()) {
-				ps.setString(2, e.getKey());
+			for(Entry<Integer, Map<String, String>> e : transports.entrySet()) {
+				ps.setInt(2, e.getKey());
 				for(Entry<String, String> e1 : e.getValue().entrySet()) {
 					ps.setString(3, e1.getKey());
 					ps.setString(4, e1.getValue());
diff --git a/components/net/sf/briar/invitation/InvitationWorker.java b/components/net/sf/briar/invitation/InvitationWorker.java
index 33df74c059b4e740a8c5f91cca82d2208a24ce93..23e883dd9192274612ca07ed0266fab3bb23995e 100644
--- a/components/net/sf/briar/invitation/InvitationWorker.java
+++ b/components/net/sf/briar/invitation/InvitationWorker.java
@@ -70,7 +70,7 @@ class InvitationWorker implements Runnable {
 		File invitationDat = new File(dir, "invitation.dat");
 		callback.encryptingFile(invitationDat);
 		// FIXME: Create a real invitation
-		Map<String, Map<String, String>> transports;
+		Map<Integer, Map<String, String>> transports;
 		try {
 			transports = db.getTransports();
 		} catch(DbException e) {
diff --git a/components/net/sf/briar/protocol/TransportFactory.java b/components/net/sf/briar/protocol/TransportFactory.java
index d784e7aa3b6eedc640413bbaf9bb48523935adbe..ba39a82d659f28753c9cc214e3e1d1497ebc7327 100644
--- a/components/net/sf/briar/protocol/TransportFactory.java
+++ b/components/net/sf/briar/protocol/TransportFactory.java
@@ -6,6 +6,6 @@ import net.sf.briar.api.protocol.TransportUpdate;
 
 interface TransportFactory {
 
-	TransportUpdate createTransports(Map<String, Map<String, String>> transports,
-			long timestamp);
+	TransportUpdate createTransportUpdate(
+			Map<Integer, Map<String, String>> transports, long timestamp);
 }
diff --git a/components/net/sf/briar/protocol/TransportFactoryImpl.java b/components/net/sf/briar/protocol/TransportFactoryImpl.java
index 922ee3550b0899ddc5a74f16581d61625bfd3e51..268dbbb520c3e0dc5645f67ea741b9f55fcb5710 100644
--- a/components/net/sf/briar/protocol/TransportFactoryImpl.java
+++ b/components/net/sf/briar/protocol/TransportFactoryImpl.java
@@ -6,8 +6,8 @@ import net.sf.briar.api.protocol.TransportUpdate;
 
 class TransportFactoryImpl implements TransportFactory {
 
-	public TransportUpdate createTransports(Map<String, Map<String, String>> transports,
-			long timestamp) {
+	public TransportUpdate createTransportUpdate(
+			Map<Integer, Map<String, String>> transports, long timestamp) {
 		return new TransportUpdateImpl(transports, timestamp);
 	}
 }
diff --git a/components/net/sf/briar/protocol/TransportReader.java b/components/net/sf/briar/protocol/TransportReader.java
index 9cb20e79be0bb42361b27404154816ef3bfb85be..55604447b1a2256c04d590699eeec7480501e9b7 100644
--- a/components/net/sf/briar/protocol/TransportReader.java
+++ b/components/net/sf/briar/protocol/TransportReader.java
@@ -37,25 +37,25 @@ class TransportReader implements ObjectReader<TransportUpdate> {
 		r.removeObjectReader(Types.TRANSPORT_PROPERTIES);
 		if(l.size() > TransportUpdate.MAX_PLUGINS_PER_UPDATE)
 			throw new FormatException();
-		Map<String, Map<String, String>> transports =
-			new TreeMap<String, Map<String, String>>();
+		Map<Integer, Map<String, String>> transports =
+			new TreeMap<Integer, Map<String, String>>();
 		for(TransportProperties t : l) {
-			if(transports.put(t.name, t.properties) != null)
+			if(transports.put(t.transportId, t.properties) != null)
 				throw new FormatException(); // Duplicate plugin name
 		}
 		long timestamp = r.readInt64();
 		r.removeConsumer(counting);
 		// Build and return the transport update
-		return transportFactory.createTransports(transports, timestamp);
+		return transportFactory.createTransportUpdate(transports, timestamp);
 	}
 
 	private static class TransportProperties {
 
-		private final String name;
+		private final int transportId;
 		private final Map<String, String> properties;
 
-		TransportProperties(String name, Map<String, String> properties) {
-			this.name = name;
+		TransportProperties(int transportId, Map<String, String> properties) {
+			this.transportId = transportId;
 			this.properties = properties;
 		}
 	}
@@ -65,14 +65,14 @@ class TransportReader implements ObjectReader<TransportUpdate> {
 
 		public TransportProperties readObject(Reader r) throws IOException {
 			r.readUserDefinedId(Types.TRANSPORT_PROPERTIES);
-			String name = r.readString(TransportUpdate.MAX_NAME_LENGTH);
+			int transportId = r.readInt32();
 			r.setMaxStringLength(TransportUpdate.MAX_KEY_OR_VALUE_LENGTH);
 			Map<String, String> properties =
 				r.readMap(String.class, String.class);
 			r.resetMaxStringLength();
 			if(properties.size() > TransportUpdate.MAX_PROPERTIES_PER_PLUGIN)
 				throw new FormatException();
-			return new TransportProperties(name, properties);
+			return new TransportProperties(transportId, properties);
 		}
 	}
 }
diff --git a/components/net/sf/briar/protocol/TransportUpdateImpl.java b/components/net/sf/briar/protocol/TransportUpdateImpl.java
index 3536f8cd33ad19d43172553dbc05eb66b702e98f..f89c9ef9dd9aa50f8f56c8bcf1e230cf5c82240e 100644
--- a/components/net/sf/briar/protocol/TransportUpdateImpl.java
+++ b/components/net/sf/briar/protocol/TransportUpdateImpl.java
@@ -6,16 +6,16 @@ import net.sf.briar.api.protocol.TransportUpdate;
 
 class TransportUpdateImpl implements TransportUpdate {
 
-	private final Map<String, Map<String, String>> transports;
+	private final Map<Integer, Map<String, String>> transports;
 	private final long timestamp;
 
-	TransportUpdateImpl(Map<String, Map<String, String>> transports,
+	TransportUpdateImpl(Map<Integer, Map<String, String>> transports,
 			long timestamp) {
 		this.transports = transports;
 		this.timestamp = timestamp;
 	}
 
-	public Map<String, Map<String, String>> getTransports() {
+	public Map<Integer, Map<String, String>> getTransports() {
 		return transports;
 	}
 
diff --git a/components/net/sf/briar/protocol/writers/TransportWriterImpl.java b/components/net/sf/briar/protocol/writers/TransportWriterImpl.java
index 1ddcae6ce31b99a9960976fe7d31d19b4d0b6592..5b7e87e38a2b7ec3cbdef4a5bb23efe6343a9c60 100644
--- a/components/net/sf/briar/protocol/writers/TransportWriterImpl.java
+++ b/components/net/sf/briar/protocol/writers/TransportWriterImpl.java
@@ -20,13 +20,13 @@ class TransportWriterImpl implements TransportWriter {
 		w = writerFactory.createWriter(out);
 	}
 
-	public void writeTransports(Map<String, Map<String, String>> transports,
+	public void writeTransports(Map<Integer, Map<String, String>> transports,
 			long timestamp) throws IOException {
 		w.writeUserDefinedId(Types.TRANSPORT_UPDATE);
 		w.writeListStart();
-		for(Entry<String, Map<String, String>> e : transports.entrySet()) {
+		for(Entry<Integer, Map<String, String>> e : transports.entrySet()) {
 			w.writeUserDefinedId(Types.TRANSPORT_PROPERTIES);
-			w.writeString(e.getKey());
+			w.writeInt32(e.getKey());
 			w.writeMap(e.getValue());
 		}
 		w.writeListEnd();
diff --git a/test/net/sf/briar/ProtocolIntegrationTest.java b/test/net/sf/briar/ProtocolIntegrationTest.java
index a2e70d0d51203695792b434aa3b026a3a37c8ecf..a75b1e9bec929009c796b0c971ceb84d9972ff6c 100644
--- a/test/net/sf/briar/ProtocolIntegrationTest.java
+++ b/test/net/sf/briar/ProtocolIntegrationTest.java
@@ -73,7 +73,7 @@ public class ProtocolIntegrationTest extends TestCase {
 	private final Message message, message1, message2, message3;
 	private final String authorName = "Alice";
 	private final String messageBody = "Hello world";
-	private final Map<String, Map<String, String>> transports;
+	private final Map<Integer, Map<String, String>> transports;
 
 	public ProtocolIntegrationTest() throws Exception {
 		super();
@@ -114,7 +114,7 @@ public class ProtocolIntegrationTest extends TestCase {
 		message3 = messageEncoder.encodeMessage(null, group1,
 				groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(),
 				messageBody.getBytes("UTF-8"));
-		transports = Collections.singletonMap("foo",
+		transports = Collections.singletonMap(transportId,
 				Collections.singletonMap("bar", "baz"));
 	}
 
diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java
index 4f9d1dbbbfd7cfb3c453b8086771cc886eefc705..197a980a9357673322db6734cbc23da5b7a33a03 100644
--- a/test/net/sf/briar/db/DatabaseComponentTest.java
+++ b/test/net/sf/briar/db/DatabaseComponentTest.java
@@ -53,7 +53,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 	private final byte[] raw;
 	private final Message message, privateMessage;
 	private final Group group;
-	private final Map<String, Map<String, String>> transports;
+	private final Map<Integer, Map<String, String>> transports;
 	private final byte[] secret;
 
 	public DatabaseComponentTest() {
@@ -72,7 +72,7 @@ public abstract class DatabaseComponentTest extends TestCase {
 		privateMessage =
 			new TestMessage(messageId, null, null, null, timestamp, raw);
 		group = new TestGroup(groupId, "The really exciting group", null);
-		transports = Collections.singletonMap("foo",
+		transports = Collections.singletonMap(123,
 				Collections.singletonMap("bar", "baz"));
 		secret = new byte[123];
 	}
@@ -1284,15 +1284,15 @@ public abstract class DatabaseComponentTest extends TestCase {
 			oneOf(database).startTransaction();
 			will(returnValue(txn));
 			oneOf(database).getTransports(txn);
-			will(returnValue(Collections.singletonMap("foo", properties)));
-			oneOf(database).setTransportProperties(txn, "foo", properties1);
+			will(returnValue(Collections.singletonMap(123, properties)));
+			oneOf(database).setTransportProperties(txn, 123, properties1);
 			oneOf(database).commitTransaction(txn);
 			oneOf(listener).eventOccurred(Event.TRANSPORTS_UPDATED);
 		}});
 		DatabaseComponent db = createDatabaseComponent(database, cleaner);
 
 		db.addListener(listener);
-		db.setTransportProperties("foo", properties1);
+		db.setTransportProperties(123, properties1);
 
 		context.assertIsSatisfied();
 	}
@@ -1311,13 +1311,13 @@ public abstract class DatabaseComponentTest extends TestCase {
 			oneOf(database).startTransaction();
 			will(returnValue(txn));
 			oneOf(database).getTransports(txn);
-			will(returnValue(Collections.singletonMap("foo", properties)));
+			will(returnValue(Collections.singletonMap(123, properties)));
 			oneOf(database).commitTransaction(txn);
 		}});
 		DatabaseComponent db = createDatabaseComponent(database, cleaner);
 
 		db.addListener(listener);
-		db.setTransportProperties("foo", properties);
+		db.setTransportProperties(123, properties);
 
 		context.assertIsSatisfied();
 	}
@@ -1336,16 +1336,16 @@ public abstract class DatabaseComponentTest extends TestCase {
 		context.checking(new Expectations() {{
 			oneOf(database).startTransaction();
 			will(returnValue(txn));
-			oneOf(database).getTransportConfig(txn, "foo");
+			oneOf(database).getTransportConfig(txn, 123);
 			will(returnValue(config));
-			oneOf(database).setTransportConfig(txn, "foo", config1);
+			oneOf(database).setTransportConfig(txn, 123, config1);
 			oneOf(database).commitTransaction(txn);
 			oneOf(listener).eventOccurred(Event.TRANSPORTS_UPDATED);
 		}});
 		DatabaseComponent db = createDatabaseComponent(database, cleaner);
 
 		db.addListener(listener);
-		db.setTransportConfig("foo", config1);
+		db.setTransportConfig(123, config1);
 
 		context.assertIsSatisfied();
 	}
@@ -1363,14 +1363,14 @@ public abstract class DatabaseComponentTest extends TestCase {
 		context.checking(new Expectations() {{
 			oneOf(database).startTransaction();
 			will(returnValue(txn));
-			oneOf(database).getTransportConfig(txn, "foo");
+			oneOf(database).getTransportConfig(txn, 123);
 			will(returnValue(config));
 			oneOf(database).commitTransaction(txn);
 		}});
 		DatabaseComponent db = createDatabaseComponent(database, cleaner);
 
 		db.addListener(listener);
-		db.setTransportConfig("foo", config);
+		db.setTransportConfig(123, config);
 
 		context.assertIsSatisfied();
 	}
diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java
index 5b545514e9c244da8a69cb40f2d0e65f6373a37f..339ee475fa12a32867467ba1163787542e0ab9e1 100644
--- a/test/net/sf/briar/db/H2DatabaseTest.java
+++ b/test/net/sf/briar/db/H2DatabaseTest.java
@@ -65,7 +65,7 @@ public class H2DatabaseTest extends TestCase {
 	private final byte[] raw;
 	private final Message message, privateMessage;
 	private final Group group;
-	private final Map<String, Map<String, String>> transports;
+	private final Map<Integer, Map<String, String>> transports;
 	private final Map<Group, Long> subscriptions;
 	private final byte[] secret;
 
@@ -91,7 +91,7 @@ public class H2DatabaseTest extends TestCase {
 		privateMessage =
 			new TestMessage(privateMessageId, null, null, null, timestamp, raw);
 		group = groupFactory.createGroup(groupId, "Group name", null);
-		transports = Collections.singletonMap("foo",
+		transports = Collections.singletonMap(123,
 				Collections.singletonMap("bar", "baz"));
 		subscriptions = Collections.singletonMap(group, 0L);
 		secret = new byte[123];
@@ -991,27 +991,28 @@ public class H2DatabaseTest extends TestCase {
 		assertEquals(transports, db.getTransports(txn, contactId));
 
 		// Replace the transport properties
-		Map<String, Map<String, String>> transports1 =
-			new TreeMap<String, Map<String, String>>();
-		transports1.put("foo", Collections.singletonMap("bar", "baz"));
-		transports1.put("bar", Collections.singletonMap("baz", "quux"));
+		Map<Integer, Map<String, String>> transports1 =
+			new TreeMap<Integer, Map<String, String>>();
+		transports1.put(123, Collections.singletonMap("bar", "baz"));
+		transports1.put(456, Collections.singletonMap("baz", "quux"));
 		db.setTransports(txn, contactId, transports1, 1);
 		assertEquals(transports1, db.getTransports(txn, contactId));
 
 		// Remove the transport properties
 		db.setTransports(txn, contactId,
-				Collections.<String, Map<String, String>>emptyMap(), 2);
+				Collections.<Integer, Map<String, String>>emptyMap(), 2);
 		assertEquals(Collections.emptyMap(), db.getTransports(txn, contactId));
 
 		// Set the local transport properties
-		for(String name : transports.keySet()) {
-			db.setTransportProperties(txn, name, transports.get(name));
+		for(Integer transportId : transports.keySet()) {
+			Map<String, String> properties = transports.get(transportId);
+			db.setTransportProperties(txn, transportId, properties);
 		}
 		assertEquals(transports, db.getTransports(txn));
 
 		// Remove the local transport properties
-		for(String name : transports.keySet()) {
-			db.setTransportProperties(txn, name,
+		for(Integer transportId : transports.keySet()) {
+			db.setTransportProperties(txn, transportId,
 					Collections.<String, String>emptyMap());
 		}
 		assertEquals(Collections.emptyMap(), db.getTransports(txn));
@@ -1029,17 +1030,17 @@ public class H2DatabaseTest extends TestCase {
 		Connection txn = db.startTransaction();
 
 		// Set the transport config
-		db.setTransportConfig(txn, "foo", config);
-		assertEquals(config, db.getTransportConfig(txn, "foo"));
+		db.setTransportConfig(txn, 123, config);
+		assertEquals(config, db.getTransportConfig(txn, 123));
 
 		// Update the transport config
-		db.setTransportConfig(txn, "foo", config1);
-		assertEquals(config1, db.getTransportConfig(txn, "foo"));
+		db.setTransportConfig(txn, 123, config1);
+		assertEquals(config1, db.getTransportConfig(txn, 123));
 
 		// Remove the transport config
-		db.setTransportConfig(txn, "foo",
+		db.setTransportConfig(txn, 123,
 				Collections.<String, String>emptyMap());
-		assertEquals(Collections.emptyMap(), db.getTransportConfig(txn, "foo"));
+		assertEquals(Collections.emptyMap(), db.getTransportConfig(txn, 123));
 
 		db.commitTransaction(txn);
 		db.close();
@@ -1055,18 +1056,18 @@ public class H2DatabaseTest extends TestCase {
 		assertEquals(transports, db.getTransports(txn, contactId));
 
 		// Replace the transport properties using a timestamp of 2
-		Map<String, Map<String, String>> transports1 =
-			new TreeMap<String, Map<String, String>>();
-		transports1.put("foo", Collections.singletonMap("bar", "baz"));
-		transports1.put("bar", Collections.singletonMap("baz", "quux"));
+		Map<Integer, Map<String, String>> transports1 =
+			new TreeMap<Integer, Map<String, String>>();
+		transports1.put(123, Collections.singletonMap("bar", "baz"));
+		transports1.put(456, Collections.singletonMap("baz", "quux"));
 		db.setTransports(txn, contactId, transports1, 2);
 		assertEquals(transports1, db.getTransports(txn, contactId));
 
 		// Try to replace the transport properties using a timestamp of 1
-		Map<String, Map<String, String>> transports2 =
-			new TreeMap<String, Map<String, String>>();
-		transports2.put("bar", Collections.singletonMap("baz", "quux"));
-		transports2.put("baz", Collections.singletonMap("quux", "fnord"));
+		Map<Integer, Map<String, String>> transports2 =
+			new TreeMap<Integer, Map<String, String>>();
+		transports2.put(456, Collections.singletonMap("baz", "quux"));
+		transports2.put(789, Collections.singletonMap("quux", "fnord"));
 		db.setTransports(txn, contactId, transports2, 1);
 
 		// The old properties should still be there
diff --git a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java
index 3ae4e997937cc2a54c3717ae8d8d4eb49784af93..2bb232d510d1068e2f7deaf37af2953453909484 100644
--- a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java
+++ b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java
@@ -47,7 +47,7 @@ public class ProtocolReadWriteTest extends TestCase {
 	private final String messageBody = "Hello world";
 	private final BitSet bitSet;
 	private final Map<Group, Long> subscriptions;
-	private final Map<String, Map<String, String>> transports;
+	private final Map<Integer, Map<String, String>> transports;
 	private final long timestamp = System.currentTimeMillis();
 
 	public ProtocolReadWriteTest() throws Exception {
@@ -67,7 +67,7 @@ public class ProtocolReadWriteTest extends TestCase {
 		bitSet.set(3);
 		bitSet.set(7);
 		subscriptions = Collections.singletonMap(group, 123L);
-		transports = Collections.singletonMap("foo",
+		transports = Collections.singletonMap(123,
 				Collections.singletonMap("bar", "baz"));
 	}
 
diff --git a/test/net/sf/briar/protocol/writers/ConstantsTest.java b/test/net/sf/briar/protocol/writers/ConstantsTest.java
index d6a50b20db27b82fd23d212de044c53ae8e20a66..e1ce9d8510c40fc47520f4b822126e85112e396e 100644
--- a/test/net/sf/briar/protocol/writers/ConstantsTest.java
+++ b/test/net/sf/briar/protocol/writers/ConstantsTest.java
@@ -4,6 +4,7 @@ import java.io.ByteArrayOutputStream;
 import java.security.PrivateKey;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.TreeMap;
 
 import junit.framework.TestCase;
 import net.sf.briar.TestUtils;
@@ -189,13 +190,10 @@ public class ConstantsTest extends TestCase {
 	public void testTransportsFitIntoUpdate() throws Exception {
 		// Create the maximum number of plugins, each with the maximum number
 		// of maximum-length properties
-		Map<String, Map<String, String>> transports =
-			new HashMap<String, Map<String, String>>(
-					TransportUpdate.MAX_PLUGINS_PER_UPDATE);
+		Map<Integer, Map<String, String>> transports =
+			new TreeMap<Integer, Map<String, String>>();
 		for(int i = 0; i < TransportUpdate.MAX_PLUGINS_PER_UPDATE; i++) {
-			String name = createRandomString(TransportUpdate.MAX_NAME_LENGTH);
-			Map<String, String> properties = new HashMap<String, String>(
-					TransportUpdate.MAX_PROPERTIES_PER_PLUGIN);
+			Map<String, String> properties = new TreeMap<String, String>();
 			for(int j = 0; j < TransportUpdate.MAX_PROPERTIES_PER_PLUGIN; j++) {
 				String key = createRandomString(
 						TransportUpdate.MAX_KEY_OR_VALUE_LENGTH);
@@ -203,7 +201,7 @@ public class ConstantsTest extends TestCase {
 						TransportUpdate.MAX_KEY_OR_VALUE_LENGTH);
 				properties.put(key, value);
 			}
-			transports.put(name, properties);
+			transports.put(i, properties);
 		}
 		// Add the transports to an update
 		ByteArrayOutputStream out = new ByteArrayOutputStream(
@@ -212,8 +210,7 @@ public class ConstantsTest extends TestCase {
 		t.writeTransports(transports, Long.MAX_VALUE);
 		// Check the size of the serialised update
 		assertTrue(out.size() > TransportUpdate.MAX_PLUGINS_PER_UPDATE *
-				(TransportUpdate.MAX_NAME_LENGTH +
-						TransportUpdate.MAX_PROPERTIES_PER_PLUGIN *
+				(4 + TransportUpdate.MAX_PROPERTIES_PER_PLUGIN *
 						TransportUpdate.MAX_KEY_OR_VALUE_LENGTH * 2) + 8);
 		assertTrue(out.size() <= ProtocolConstants.MAX_PACKET_LENGTH);
 	}
diff --git a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java
index 0deafde5786d6f50508247e0eb906ec0002e25e9..8a65f3227a6c80b95bc4de1520e9260d5237ae7f 100644
--- a/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java
+++ b/test/net/sf/briar/transport/batch/BatchConnectionReadWriteTest.java
@@ -43,7 +43,7 @@ public class BatchConnectionReadWriteTest extends TestCase {
 	private final File testDir = TestUtils.getTestDirectory();
 	private final File aliceDir = new File(testDir, "alice");
 	private final File bobDir = new File(testDir, "bob");
-	private final Map<String, Map<String, String>> transports =
+	private final Map<Integer, Map<String, String>> transports =
 		Collections.emptyMap();
 	private final byte[] aliceSecret, bobSecret;
 	private final int transportId = 123;