Don't connect to Tor if it's already running.

Fixes #572, #578.
This commit is contained in:
akwizgran
2016-08-05 13:59:25 +01:00
parent d15d82ccec
commit 36d15358a1

View File

@@ -150,74 +150,64 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
@Override @Override
public boolean start() throws IOException { public boolean start() throws IOException {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
// Try to connect to an existing Tor process if there is one // Install the binary, possibly overwriting an older version
boolean startProcess = false; if (!installBinary()) {
LOG.warning("Could not install Tor binary");
return false;
}
// Install the GeoIP database and config file if necessary
if (!isConfigInstalled() && !installConfig()) {
LOG.warning("Could not install Tor config");
return false;
}
LOG.info("Starting Tor");
// Watch for the auth cookie file being updated
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 = torFile.getAbsolutePath();
String configPath = configFile.getAbsolutePath();
String pid = String.valueOf(android.os.Process.myPid());
String[] cmd = {torPath, "-f", configPath, OWNER, pid};
String[] env = {"HOME=" + torDirectory.getAbsolutePath()};
Process torProcess;
try { try {
controlSocket = new Socket("127.0.0.1", CONTROL_PORT); torProcess = Runtime.getRuntime().exec(cmd, env, torDirectory);
LOG.info("Tor is already running"); } catch (SecurityException e1) {
} catch (IOException e) { if (LOG.isLoggable(WARNING))
LOG.info("Tor is not running"); LOG.log(WARNING, e1.toString(), e1);
startProcess = true; return false;
// Install the binary, possibly overwriting an older version }
if (!installBinary()) { // Log the process's standard output until it detaches
LOG.warning("Could not install Tor binary"); if (LOG.isLoggable(INFO)) {
return false; Scanner stdout = new Scanner(torProcess.getInputStream());
} while (stdout.hasNextLine()) LOG.info(stdout.nextLine());
// Install the GeoIP database and config file if necessary stdout.close();
if (!isConfigInstalled() && !installConfig()) { }
LOG.warning("Could not install Tor config"); try {
return false; // Wait for the process to detach or exit
} int exit = torProcess.waitFor();
LOG.info("Starting Tor"); if (exit != 0) {
// Watch for the auth cookie file being created/updated
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 = torFile.getAbsolutePath();
String configPath = configFile.getAbsolutePath();
String pid = String.valueOf(android.os.Process.myPid());
String[] cmd = {torPath, "-f", configPath, OWNER, pid};
String[] env = {"HOME=" + torDirectory.getAbsolutePath()};
Process torProcess;
try {
torProcess = Runtime.getRuntime().exec(cmd, env, torDirectory);
} catch (SecurityException e1) {
if (LOG.isLoggable(WARNING)) if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e1.toString(), e1); LOG.warning("Tor exited with value " + exit);
return false; return false;
} }
// Log the process's standard output until it detaches // Wait for the auth cookie file to be created/updated
if (LOG.isLoggable(INFO)) { if (!latch.await(COOKIE_TIMEOUT, MILLISECONDS)) {
Scanner stdout = new Scanner(torProcess.getInputStream()); LOG.warning("Auth cookie not created");
while (stdout.hasNextLine()) LOG.info(stdout.nextLine()); if (LOG.isLoggable(INFO)) listFiles(torDirectory);
stdout.close();
}
try {
// Wait for the process to detach or exit
int exit = torProcess.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)) {
LOG.warning("Auth cookie not created");
if (LOG.isLoggable(INFO)) listFiles(torDirectory);
return false;
}
} catch (InterruptedException e1) {
LOG.warning("Interrupted while starting Tor");
Thread.currentThread().interrupt();
return false; return false;
} }
// Now we should be able to connect to the new process } catch (InterruptedException e1) {
controlSocket = new Socket("127.0.0.1", CONTROL_PORT); LOG.warning("Interrupted while starting Tor");
Thread.currentThread().interrupt();
return false;
} }
// Open a control connection and authenticate using the cookie file // Open a control connection and authenticate using the cookie file
controlSocket = new Socket("127.0.0.1", CONTROL_PORT);
controlConnection = new TorControlConnection(controlSocket); controlConnection = new TorControlConnection(controlSocket);
controlConnection.authenticate(read(cookieFile)); controlConnection.authenticate(read(cookieFile));
// Tell Tor to exit when the control connection is closed // Tell Tor to exit when the control connection is closed
@@ -227,13 +217,11 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
// Register to receive events from the Tor process // Register to receive events from the Tor process
controlConnection.setEventHandler(this); controlConnection.setEventHandler(this);
controlConnection.setEvents(Arrays.asList(EVENTS)); controlConnection.setEvents(Arrays.asList(EVENTS));
// If Tor was already running, find out whether it's bootstrapped // Check whether Tor has already bootstrapped
if (!startProcess) { String phase = controlConnection.getInfo("status/bootstrap-phase");
String phase = controlConnection.getInfo("status/bootstrap-phase"); if (phase != null && phase.contains("PROGRESS=100")) {
if (phase != null && phase.contains("PROGRESS=100")) { LOG.info("Tor has already bootstrapped");
LOG.info("Tor has already bootstrapped"); connectionStatus.setBootstrapped();
connectionStatus.setBootstrapped();
}
} }
// Register to receive network status events // Register to receive network status events
networkStateReceiver = new NetworkStateReceiver(); networkStateReceiver = new NetworkStateReceiver();
@@ -271,6 +259,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
} }
private boolean installConfig() { private boolean installConfig() {
LOG.info("Installing Tor config");
InputStream in = null; InputStream in = null;
OutputStream out = null; OutputStream out = null;
try { try {
@@ -500,19 +489,15 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
tryToClose(socket); tryToClose(socket);
if (networkStateReceiver != null) if (networkStateReceiver != null)
appContext.unregisterReceiver(networkStateReceiver); appContext.unregisterReceiver(networkStateReceiver);
try { if (controlSocket != null && controlConnection != null) {
LOG.info("Stopping Tor"); try {
if (controlSocket == null) LOG.info("Stopping Tor");
controlSocket = new Socket("127.0.0.1", CONTROL_PORT); controlConnection.setConf("DisableNetwork", "1");
if (controlConnection == null) { controlConnection.shutdownTor("TERM");
controlConnection = new TorControlConnection(controlSocket); controlSocket.close();
controlConnection.authenticate(read(cookieFile)); } catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
controlConnection.setConf("DisableNetwork", "1");
controlConnection.shutdownTor("TERM");
controlSocket.close();
} catch (IOException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
wakeLock.release(); wakeLock.release();
} }