diff --git a/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java b/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java
index 56f199deee4b5edf96af8d3ee835961950b5c837..6b76041c7e3dd93a3c2979e1ae317dd2931ecf92 100644
--- a/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java
+++ b/briar-core/src/net/sf/briar/plugins/tor/TorPlugin.java
@@ -23,6 +23,7 @@ import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.logging.Logger;
+import java.util.regex.Pattern;
 import java.util.zip.ZipInputStream;
 
 import net.freehaven.tor.control.EventHandler;
@@ -54,6 +55,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 	private static final int SOCKS_PORT = 59050, CONTROL_PORT = 59051;
 	private static final int COOKIE_TIMEOUT = 3000; // Milliseconds
 	private static final int HOSTNAME_TIMEOUT = 30 * 1000; // Milliseconds
+	private static final Pattern ONION = Pattern.compile("[a-z2-7]{16}.onion");
 	private static final Logger LOG =
 			Logger.getLogger(TorPlugin.class.getName());
 
@@ -63,7 +65,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 	private final long maxLatency, pollingInterval;
 
 	private volatile boolean running = false;
-	private volatile Process torProcess = null;
+	private volatile Process tor = null;
 	private volatile ServerSocket socket = null;
 
 	TorPlugin(Executor pluginExecutor, Context appContext,
@@ -89,41 +91,59 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 	}
 
 	public boolean start() throws IOException {
+		// Check that we have a Tor binary for this architecture
+		if(!Build.CPU_ABI.startsWith("armeabi")) {
+			if(LOG.isLoggable(INFO))
+				LOG.info("No Tor binary for this architecture");
+			return false;
+		}
+		// Try to connect to an existing Tor process, if any
 		Socket s;
 		try {
-			s = new Socket("127.0.0.1", CONTROL_PORT);
+			s = new Socket("127.0.0.1", CONTROL_PORT); // FIXME: Never closed
 			if(LOG.isLoggable(INFO)) LOG.info("Tor is already running");
 		} catch(IOException e) {
+			// Install the binary, GeoIP database and config file if necessary
 			if(!isInstalled() && !install()) {
 				if(LOG.isLoggable(INFO)) LOG.info("Could not install Tor");
 				return false;
 			}
 			if(LOG.isLoggable(INFO)) LOG.info("Starting Tor");
+			// Watch for the auth cookie file being created/updated
 			File cookieFile = getCookieFile();
 			cookieFile.getParentFile().mkdirs();
 			cookieFile.createNewFile();
 			CountDownLatch latch = new CountDownLatch(1);
 			FileObserver obs = new WriteObserver(cookieFile, latch);
 			obs.startWatching();
+			// Start a new Tor process
 			String torPath = getTorFile().getAbsolutePath();
 			String configPath = getConfigFile().getAbsolutePath();
 			String[] command = { torPath, "-f", configPath };
 			String home = "HOME=" + getTorDirectory().getAbsolutePath();
 			String[] environment = { home };
 			File dir = getTorDirectory();
-			torProcess = Runtime.getRuntime().exec(command, environment, dir);
+			try {
+				tor = Runtime.getRuntime().exec(command, environment, dir);
+			} catch(SecurityException e1) {
+				if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e1.toString(), e1);
+				return false;
+			}
+			// Log the process's standard output until it detaches
 			if(LOG.isLoggable(INFO)) {
-				Scanner stdout = new Scanner(torProcess.getInputStream());
+				Scanner stdout = new Scanner(tor.getInputStream());
 				while(stdout.hasNextLine()) LOG.info(stdout.nextLine());
 				stdout.close();
 			}
 			try {
-				int exit = torProcess.waitFor();
+				// Wait for the process to detach successfully
+				int exit = tor.waitFor();
 				if(exit != 0) {
 					if(LOG.isLoggable(WARNING))
 						LOG.warning("Tor exited with value " + exit);
 					return false;
 				}
+				// Wait for the auth cookie file to be created/updated
 				if(!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
 					if(LOG.isLoggable(WARNING))
 						LOG.warning("Auth cookie not created");
@@ -135,14 +155,17 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 					LOG.warning("Interrupted while starting Tor");
 				return false;
 			}
-			s = new Socket("127.0.0.1", CONTROL_PORT);
+			// Now we should be able to connect to the new process
+			s = new Socket("127.0.0.1", CONTROL_PORT); // FIXME: Never closed
 		}
+		// Open a control connection and authenticate using the cookie file
 		TorControlConnection control = new TorControlConnection(s);
 		control.launchThread(true);
 		control.authenticate(read(getCookieFile()));
 		control.setEventHandler(this);
 		control.setEvents(Arrays.asList("NOTICE", "WARN", "ERR"));
 		running = true;
+		// Bind a server socket to receive incoming hidden service connections
 		pluginExecutor.execute(new Runnable() {
 			public void run() {
 				bind();
@@ -159,20 +182,25 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 		InputStream in = null;
 		OutputStream out = null;
 		try {
+			// Unzip the Tor binary to the filesystem
 			in = getTorInputStream();
 			out = new FileOutputStream(getTorFile());
 			copy(in, out);
+			// Unzip the GeoIP database to the filesystem
 			in = getGeoIpInputStream();
 			out = new FileOutputStream(getGeoIpFile());
 			copy(in, out);
+			// Copy the config file to the filesystem
 			in = getConfigInputStream();
 			out = new FileOutputStream(getConfigFile());
 			copy(in, out);
+			// Make the Tor binary executable
 			if(!setExecutable(getTorFile())) {
 				if(LOG.isLoggable(WARNING))
 					LOG.warning("Could not make Tor executable");
 				return false;
 			}
+			// Create a file to indicate that installation succeeded
 			File done = getDoneFile();
 			done.createNewFile();
 			return true;
@@ -227,6 +255,8 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 				if(LOG.isLoggable(WARNING))
 					LOG.warning("Interrupted while executing chmod");
 				Thread.currentThread().interrupt();
+			} catch(SecurityException e) {
+				if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 			}
 			return false;
 		}
@@ -265,10 +295,12 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 	}
 
 	private void bind() {
+		// If there's already a port number stored in config, reuse it
 		String portString = callback.getConfig().get("port");
 		int port;
 		if(StringUtils.isNullOrEmpty(portString)) port = 0;
 		else port = Integer.parseInt(portString);
+		// Bind a server socket to receive connections from the Tor process
 		ServerSocket ss = null;
 		try {
 			ss = new ServerSocket();
@@ -282,15 +314,18 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 			return;
 		}
 		socket = ss;
+		// Store the port number
 		final String localPort = String.valueOf(ss.getLocalPort());
 		TransportConfig c  = new TransportConfig();
 		c.put("port", localPort);
 		callback.mergeConfig(c);
+		// Create a hidden service if necessary
 		pluginExecutor.execute(new Runnable() {
 			public void run() {
 				publishHiddenService(localPort);
 			}
 		});
+		// Accept incoming hidden service connections from the Tor process
 		acceptContactConnections(ss);
 	}
 
@@ -308,11 +343,13 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 		if(!hostnameFile.exists()) {
 			if(LOG.isLoggable(INFO)) LOG.info("Creating hidden service");
 			try {
+				// Watch for the hostname file being created/updated
 				hostnameFile.getParentFile().mkdirs();
 				hostnameFile.createNewFile();
 				CountDownLatch latch = new CountDownLatch(1);
 				FileObserver obs = new WriteObserver(hostnameFile, latch);
 				obs.startWatching();
+				// Open a control connection and update the Tor config
 				String dir = getTorDirectory().getAbsolutePath();
 				List<String> config = Arrays.asList("HiddenServiceDir " + dir,
 						"HiddenServicePort 80 127.0.0.1:" + port);
@@ -323,6 +360,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 				control.authenticate(read(getCookieFile()));
 				control.setConf(config);
 				control.saveConf();
+				// Wait for the hostname file to be created/updated
 				if(!latch.await(HOSTNAME_TIMEOUT, MILLISECONDS)) {
 					if(LOG.isLoggable(WARNING))
 						LOG.warning("Hidden service not created");
@@ -337,6 +375,7 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 					LOG.warning("Interrupted while creating hidden service");
 			}
 		}
+		// Publish the hidden service's onion hostname in transport properties
 		try {
 			String hostname = new String(read(hostnameFile), "UTF-8").trim();
 			if(LOG.isLoggable(INFO)) LOG.info("Hidden service " + hostname);
@@ -379,9 +418,9 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 			control.shutdownTor("TERM");
 		} catch(IOException e) {
 			if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-			if(torProcess != null) {
+			if(tor != null) {
 				if(LOG.isLoggable(INFO)) LOG.info("Killing Tor");
-				torProcess.destroy();
+				tor.destroy();
 			}
 		}
 	}
@@ -419,7 +458,10 @@ class TorPlugin implements DuplexPlugin, EventHandler {
 		if(p == null) return null;
 		String onion = p.get("onion");
 		if(StringUtils.isNullOrEmpty(onion)) return null;
-		// FIXME: Check that it's an onion hostname
+		if(!ONION.matcher(onion).matches()) {
+			if(LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion);
+			return null;
+		}
 		try {
 			if(LOG.isLoggable(INFO)) LOG.info("Connecting to " + onion);
 			Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", SOCKS_PORT);