[tbb-commits] [tor-browser] 04/10: fixup! Bug 40933: Add tor-launcher functionality

gitolite role git at cupani.torproject.org
Mon Oct 10 20:17:18 UTC 2022


This is an automated email from the git hooks/post-receive script.

richard pushed a commit to branch tor-browser-102.3.0esr-12.0-2
in repository tor-browser.

commit 1a64d858c5ab472eec6fc48a43b9ff54942971a5
Author: Pier Angelo Vendrame <pierov at torproject.org>
AuthorDate: Mon Oct 10 15:26:50 2022 +0200

    fixup! Bug 40933: Add tor-launcher functionality
    
    Bug 40853: Use Subprocess.jsm to launch tor.
---
 .../components/tor-launcher/TorMonitorService.jsm  |  16 +-
 toolkit/components/tor-launcher/TorProcess.jsm     | 205 +++++++++++----------
 2 files changed, 110 insertions(+), 111 deletions(-)

diff --git a/toolkit/components/tor-launcher/TorMonitorService.jsm b/toolkit/components/tor-launcher/TorMonitorService.jsm
index 16d7fc927adc..201ac6275c56 100644
--- a/toolkit/components/tor-launcher/TorMonitorService.jsm
+++ b/toolkit/components/tor-launcher/TorMonitorService.jsm
@@ -103,6 +103,10 @@ const TorMonitorService = {
   // control connection is closed. Therefore, as a matter of facts, calling this
   // function also makes the child Tor instance stop.
   uninit() {
+    if (this._torProcess) {
+      this._torProcess.forget();
+      this._torProcess = null;
+    }
     this._shutDownEventMonitor();
   },
 
@@ -179,12 +183,11 @@ const TorMonitorService = {
 
   async _startProcess() {
     this._torProcess = new TorProcess();
-    this._torProcess.onExit = unexpected => {
-      this._shutDownEventMonitor(!unexpected);
+    this._torProcess.onExit = () => {
       Services.obs.notifyObservers(null, TorTopics.ProcessExited);
     };
     this._torProcess.onRestart = async () => {
-      this._shutDownEventMonitor(false);
+      this._shutDownEventMonitor();
       await this._controlTor();
       Services.obs.notifyObservers(null, TorTopics.ProcessRestarted);
     };
@@ -434,13 +437,8 @@ const TorMonitorService = {
     }
   },
 
-  _shutDownEventMonitor(shouldCallStop = true) {
+  _shutDownEventMonitor() {
     if (this._connection) {
-      if (this.ownsTorDaemon && this._torProcess && shouldCallStop) {
-        this._torProcess.stop();
-        this._torProcess = null;
-      }
-
       this._connection.close();
       this._connection = null;
       this._eventMonitorInProgressReply = null;
diff --git a/toolkit/components/tor-launcher/TorProcess.jsm b/toolkit/components/tor-launcher/TorProcess.jsm
index 78bf2504c9b6..a23fd324efff 100644
--- a/toolkit/components/tor-launcher/TorProcess.jsm
+++ b/toolkit/components/tor-launcher/TorProcess.jsm
@@ -8,6 +8,10 @@ const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
+const { Subprocess } = ChromeUtils.import(
+  "resource://gre/modules/Subprocess.jsm"
+);
+
 ChromeUtils.defineModuleGetter(
   this,
   "TorProtocolService",
@@ -32,11 +36,6 @@ const TorProcessTopics = Object.freeze({
   ProcessDidNotStart: "TorProcessDidNotStart",
 });
 
-const ProcessTopics = Object.freeze({
-  ProcessFailed: "process-failed",
-  ProcessFinished: "process-finished",
-});
-
 // Logger adapted from CustomizableUI.jsm
 XPCOMUtils.defineLazyGetter(this, "logger", () => {
   const { ConsoleAPI } = ChromeUtils.import(
@@ -73,15 +72,6 @@ class TorProcess {
     );
   }
 
-  observe(aSubject, aTopic, aParam) {
-    if (
-      ProcessTopics.ProcessFailed === aTopic ||
-      ProcessTopics.ProcessFinished === aTopic
-    ) {
-      this._processExited();
-    }
-  }
-
   async start() {
     if (this._torProcess) {
       return;
@@ -112,31 +102,27 @@ class TorProcess {
       // Set an environment variable that points to the Tor data directory.
       // This is used by meek-client-torbrowser to find the location for
       // the meek browser profile.
-      const env = Cc["@mozilla.org/process/environment;1"].getService(
-        Ci.nsIEnvironment
-      );
-      env.set("TOR_BROWSER_TOR_DATA_DIR", this._dataDir.path);
+      const environment = {
+        TOR_BROWSER_TOR_DATA_DIR: this._dataDir.path,
+      };
 
       // On Windows, prepend the Tor program directory to PATH. This is needed
       // so that pluggable transports can find OpenSSL DLLs, etc.
       // See https://trac.torproject.org/projects/tor/ticket/10845
       if (TorLauncherUtil.isWindows) {
         let path = this._exeFile.parent.path;
+        const env = Cc["@mozilla.org/process/environment;1"].getService(
+          Ci.nsIEnvironment
+        );
         if (env.exists("PATH")) {
           path += ";" + env.get("PATH");
         }
-        env.set("PATH", path);
+        environment.PATH = path;
       }
 
       this._status = TorProcessStatus.Starting;
       this._didConnectToTorControlPort = false;
 
-      var p = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
-      p.startHidden = true;
-      p.init(this._exeFile);
-
-      logger.debug(`Starting ${this._exeFile.path}`, this._args);
-
       // useful for simulating slow tor daemon launch
       const kPrefTorDaemonLaunchDelay = "extensions.torlauncher.launch_delay";
       const launchDelay = Services.prefs.getIntPref(
@@ -146,46 +132,48 @@ class TorProcess {
       if (launchDelay > 0) {
         await new Promise(resolve => setTimeout(() => resolve(), launchDelay));
       }
-      p.runwAsync(this._args, this._args.length, this, false);
-      // FIXME: This should be okay, unless the observer is called just before
-      // assigning the correct state.
-      // We should check for the control connection status, rather than the
-      // process status.
-      if (this._status === TorProcessStatus.Starting) {
-        this._status = TorProcessStatus.Running;
-      }
 
-      this._torProcess = p;
+      logger.debug(`Starting ${this._exeFile.path}`, this._args);
+      const options = {
+        command: this._exeFile.path,
+        arguments: this._args,
+        environment,
+        environmentAppend: true,
+        stderr: "pipe",
+      };
+      this._torProcess = await Subprocess.call(options);
+      this._watchProcess();
+      this._status = TorProcessStatus.Running;
       this._torProcessStartTime = Date.now();
     } catch (e) {
       this._status = TorProcessStatus.Exited;
-      const s = TorLauncherUtil.getLocalizedString("tor_failed_to_start");
-      TorLauncherUtil.notifyUserOfError(
-        s,
+      this._torProcess = null;
+      logger.error("startTor error:", e);
+      Services.obs.notifyObservers(
         null,
-        TorProcessTopics.ProcessDidNotStart
+        TorProcessTopics.ProcessDidNotStart,
+        null
       );
-      logger.error("startTor error:", e);
     }
   }
 
-  stop() {
-    if (this._torProcess) {
-      // We now rely on the TAKEOWNERSHIP feature to shut down tor when we
-      // close the control port connection.
-      //
-      // Previously, we sent a SIGNAL HALT command to the tor control port,
-      // but that caused hangs upon exit in the Firefox 24.x based browser.
-      // Apparently, Firefox does not like to process socket I/O while
-      // quitting if the browser did not finish starting up (e.g., when
-      // someone presses the Quit button on our Network Settings window
-      // during startup).
-      //
-      // However, we set the Subprocess object to null to distinguish the cases
-      // in which we wanted to explicitly kill the tor process, from the cases
-      // in which it exited for any other reason, e.g., a crash.
-      this._torProcess = null;
-    }
+  // Forget about a process.
+  //
+  // Instead of killing the tor process, we  rely on the TAKEOWNERSHIP feature
+  // to shut down tor when we close the control port connection.
+  //
+  // Previously, we sent a SIGNAL HALT command to the tor control port,
+  // but that caused hangs upon exit in the Firefox 24.x based browser.
+  // Apparently, Firefox does not like to process socket I/O while
+  // quitting if the browser did not finish starting up (e.g., when
+  // someone presses the Quit button on our Network Settings window
+  // during startup).
+  //
+  // Still, before closing the owning connection, this class should forget about
+  // the process, so that future notifications will be ignored.
+  forget() {
+    this._torProcess = null;
+    this._status = TorProcessStatus.Exited;
   }
 
   // The owner of the process can use this function to tell us that they
@@ -195,58 +183,71 @@ class TorProcess {
     this._didConnectToTorControlPort = true;
   }
 
-  _processExited() {
-    // When we stop tor intentionally, we also set _torProcess to null.
-    // So, if this._torProcess is not null, it exited for some other reason.
-    const unexpected = !!this._torProcess;
-    if (unexpected) {
-      logger.warn("The tor process exited unexpectedly.");
-    } else {
-      logger.info("The tor process exited.");
+  async _watchProcess() {
+    const watched = this._torProcess;
+    if (!watched) {
+      return;
     }
+    try {
+      const { exitCode } = await watched.wait();
 
-    this._torProcess = null;
-    this._status = TorProcessStatus.Exited;
-
-    let restart = false;
-    if (unexpected) {
-      // TODO: Move this logic somewhere else?
-      let s;
-      if (!this._didConnectToTorControlPort) {
-        // tor might be misconfigured, becauser we could never connect to it
-        const key = "tor_exited_during_startup";
-        s = TorLauncherUtil.getLocalizedString(key);
+      if (watched !== this._torProcess) {
+        logger.debug(`A Tor process exited with code ${exitCode}.`);
+      } else if (exitCode) {
+        logger.warn(`The watched Tor process exited with code ${exitCode}.`);
       } else {
-        // tor exited suddenly, so configuration should be okay
-        s =
-          TorLauncherUtil.getLocalizedString("tor_exited") +
-          "\n\n" +
-          TorLauncherUtil.getLocalizedString("tor_exited2");
+        logger.info("The Tor process exited.");
       }
-      logger.info(s);
-      var defaultBtnLabel = TorLauncherUtil.getLocalizedString("restart_tor");
-      var cancelBtnLabel = "OK";
-      try {
-        const kSysBundleURI = "chrome://global/locale/commonDialogs.properties";
-        var sysBundle = Services.strings.createBundle(kSysBundleURI);
-        cancelBtnLabel = sysBundle.GetStringFromName(cancelBtnLabel);
-      } catch (e) {}
+    } catch (e) {
+      logger.error("Failed to watch the tor process", e);
+    }
 
-      restart = TorLauncherUtil.showConfirm(
-        null,
-        s,
-        defaultBtnLabel,
-        cancelBtnLabel
-      );
-      if (restart) {
-        this.start().then(() => {
-          if (this.onRestart) {
-            this.onRestart();
-          }
-        });
-      }
+    if (watched === this._torProcess) {
+      this._processExitedUnexpectedly();
     }
-    if (!restart && this.onExit) {
+  }
+
+  _processExitedUnexpectedly() {
+    this._torProcess = null;
+    this._status = TorProcessStatus.Exited;
+
+    // TODO: Move this logic somewhere else?
+    let s;
+    if (!this._didConnectToTorControlPort) {
+      // tor might be misconfigured, becauser we could never connect to it
+      const key = "tor_exited_during_startup";
+      s = TorLauncherUtil.getLocalizedString(key);
+    } else {
+      // tor exited suddenly, so configuration should be okay
+      s =
+        TorLauncherUtil.getLocalizedString("tor_exited") +
+        "\n\n" +
+        TorLauncherUtil.getLocalizedString("tor_exited2");
+    }
+    logger.info(s);
+    const defaultBtnLabel = TorLauncherUtil.getLocalizedString("restart_tor");
+    let cancelBtnLabel = "OK";
+    try {
+      const kSysBundleURI = "chrome://global/locale/commonDialogs.properties";
+      const sysBundle = Services.strings.createBundle(kSysBundleURI);
+      cancelBtnLabel = sysBundle.GetStringFromName(cancelBtnLabel);
+    } catch (e) {
+      logger.warn("Could not localize the cancel button", e);
+    }
+
+    const restart = TorLauncherUtil.showConfirm(
+      null,
+      s,
+      defaultBtnLabel,
+      cancelBtnLabel
+    );
+    if (restart) {
+      this.start().then(() => {
+        if (this.onRestart) {
+          this.onRestart();
+        }
+      });
+    } else if (this.onExit) {
       this.onExit(unexpected);
     }
   }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the tbb-commits mailing list