This is an automated email from the git hooks/post-receive script.
pierov pushed a commit to branch tor-browser-102.4.0esr-12.0-1
in repository tor-browser.
The following commit(s) were added to refs/heads/tor-browser-102.4.0esr-12.0-1 by this push:
new ed7d92b0d031 fixup! Bug 40933: Add tor-launcher functionality
ed7d92b0d031 is described below
commit ed7d92b0d03166825f51d64cc57f59c3594b996b
Author: Pier Angelo Vendrame <pierov(a)torproject.org>
AuthorDate: Fri Oct 21 19:35:58 2022 +0200
fixup! Bug 40933: Add tor-launcher functionality
Bug 41386: Fix a pair of errors when handling the case of tor already
running
---
.../components/tor-launcher/TorMonitorService.jsm | 107 +++++++++++++++------
toolkit/components/tor-launcher/TorProcess.jsm | 22 ++---
2 files changed, 88 insertions(+), 41 deletions(-)
diff --git a/toolkit/components/tor-launcher/TorMonitorService.jsm b/toolkit/components/tor-launcher/TorMonitorService.jsm
index 881f4a5a7355..27572c30370f 100644
--- a/toolkit/components/tor-launcher/TorMonitorService.jsm
+++ b/toolkit/components/tor-launcher/TorMonitorService.jsm
@@ -5,7 +5,9 @@
var EXPORTED_SYMBOLS = ["TorMonitorService"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
+const { clearTimeout, setTimeout } = ChromeUtils.import(
+ "resource://gre/modules/Timer.jsm"
+);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
@@ -13,7 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
const { TorParsers, TorStatuses } = ChromeUtils.import(
"resource://gre/modules/TorParsers.jsm"
);
-const { TorProcess, TorProcessStatus } = ChromeUtils.import(
+const { TorProcess } = ChromeUtils.import(
"resource://gre/modules/TorProcess.jsm"
);
@@ -69,6 +71,7 @@ const TorMonitorService = {
_connection: null,
_eventsToMonitor: Object.freeze(["STATUS_CLIENT", "NOTICE", "WARN", "ERR"]),
_torLog: [], // Array of objects with date, type, and msg properties.
+ _startTimeout: null,
_isBootstrapDone: false,
_bootstrapErrorOccurred: false,
@@ -91,7 +94,7 @@ const TorMonitorService = {
this._controlTor();
} else {
logger.info(
- "Not starting the event monitor, as e do not own the Tor daemon."
+ "Not starting the event monitor, as we do not own the Tor daemon."
);
}
logger.debug("TorMonitorService initialized");
@@ -104,6 +107,8 @@ const TorMonitorService = {
uninit() {
if (this._torProcess) {
this._torProcess.forget();
+ this._torProcess.onExit = null;
+ this._torProcess.onRestart = null;
this._torProcess = null;
}
this._shutDownEventMonitor();
@@ -181,35 +186,42 @@ const TorMonitorService = {
// Private methods
async _startProcess() {
- this._torProcess = new TorProcess();
- this._torProcess.onExit = () => {
- Services.obs.notifyObservers(null, TorTopics.ProcessExited);
- };
- this._torProcess.onRestart = async () => {
- this._shutDownEventMonitor();
- await this._controlTor();
- Services.obs.notifyObservers(null, TorTopics.ProcessRestarted);
- };
+ // TorProcess should be instanced once, then always reused and restarted
+ // only through the prompt it exposes when the controlled process dies.
+ if (!this._torProcess) {
+ this._torProcess = new TorProcess();
+ this._torProcess.onExit = () => {
+ this._shutDownEventMonitor();
+ Services.obs.notifyObservers(null, TorTopics.ProcessExited);
+ };
+ this._torProcess.onRestart = async () => {
+ this._shutDownEventMonitor();
+ await this._controlTor();
+ Services.obs.notifyObservers(null, TorTopics.ProcessRestarted);
+ };
+ }
+
+ // Already running, but we did not start it
+ if (this._torProcess.isRunning) {
+ return false;
+ }
+
try {
await this._torProcess.start();
- if (!this._torProcess.isRunning) {
- this._torProcess = null;
- return false;
+ if (this._torProcess.isRunning) {
+ logger.info("tor started");
}
} catch (e) {
// TorProcess already logs the error.
this._bootstrapErrorOccurred = true;
this._lastWarningPhase = "startup";
this._lastWarningReason = e.toString();
- this._torProcess = null;
- return false;
}
- logger.info("tor started");
- return true;
+ return this._torProcess.isRunning;
},
async _controlTor() {
- if (!this._torProcess && !(await this._startProcess())) {
+ if (!this._torProcess?.isRunning && !(await this._startProcess())) {
logger.error("Tor not running, not starting to monitor it.");
return;
}
@@ -217,7 +229,6 @@ const TorMonitorService = {
let delayMS = ControlConnTimings.initialDelayMS;
const callback = async () => {
if (await this._startEventMonitor()) {
- this._status = TorProcessStatus.Running;
this.retrieveBootstrapStatus().catch(e => {
logger.warn("Could not get the initial bootstrap status", e);
});
@@ -225,6 +236,14 @@ const TorMonitorService = {
// FIXME: TorProcess is misleading here. We should use a topic related
// to having a control port connection, instead.
Services.obs.notifyObservers(null, TorTopics.ProcessIsReady);
+
+ // We reset this here hoping that _shutDownEventMonitor can interrupt
+ // the current monitor, either by calling clearTimeout and preventing it
+ // from starting, or by closing the control port connection.
+ if (this._startTimeout === null) {
+ logger.warn("Someone else reset _startTimeout!");
+ }
+ this._startTimeout = null;
} else if (
Date.now() - this._torProcessStartTime >
ControlConnTimings.timeoutMS
@@ -234,18 +253,28 @@ const TorMonitorService = {
this._lastWarningPhase = "startup";
this._lastWarningReason = s;
logger.info(s);
+ if (this._startTimeout === null) {
+ logger.warn("Someone else reset _startTimeout!");
+ }
+ this._startTimeout = null;
} else {
delayMS *= 2;
if (delayMS > ControlConnTimings.maxRetryMS) {
delayMS = ControlConnTimings.maxRetryMS;
}
- setTimeout(() => {
+ this._startTimeout = setTimeout(() => {
logger.debug(`Control port not ready, waiting ${delayMS / 1000}s.`);
callback();
}, delayMS);
}
};
- setTimeout(callback, delayMS);
+ // Check again, in the unfortunate case in which the execution was alrady
+ // queued, but was waiting network code.
+ if (this._startTimeout === null) {
+ this._startTimeout = setTimeout(callback, delayMS);
+ } else {
+ logger.error("Possible race? Refusing to start the timeout again");
+ }
},
async _startEventMonitor() {
@@ -259,6 +288,16 @@ const TorMonitorService = {
conn = await controller(avoidCache);
} catch (e) {
logger.error("Cannot open a control port connection", e);
+ if (conn) {
+ try {
+ conn.close();
+ } catch (e) {
+ logger.error(
+ "Also, the connection is not null but cannot be closed",
+ e
+ );
+ }
+ }
return false;
}
@@ -273,12 +312,19 @@ const TorMonitorService = {
return false;
}
+ // FIXME: At the moment it is not possible to start the event monitor
+ // when we do start the tor process. So, does it make sense to keep this
+ // control?
if (this._torProcess) {
this._torProcess.connectionWorked();
}
if (!TorLauncherUtil.shouldOnlyConfigureTor) {
- this._takeTorOwnership(conn);
+ try {
+ await this._takeTorOwnership(conn);
+ } catch (e) {
+ logger.warn("Could not take ownership of the Tor daemon", e);
+ }
}
this._connection = conn;
@@ -449,12 +495,13 @@ const TorMonitorService = {
},
_shutDownEventMonitor() {
- if (this._connection) {
- this._connection.close();
- this._connection = null;
- this._eventMonitorInProgressReply = null;
- this._isBootstrapDone = false;
- this.clearBootstrapError();
+ this._connection?.close();
+ this._connection = null;
+ if (this._startTimeout !== null) {
+ clearTimeout(this._startTimeout);
+ this._startTimeout = null;
}
+ this._isBootstrapDone = false;
+ this.clearBootstrapError();
},
};
diff --git a/toolkit/components/tor-launcher/TorProcess.jsm b/toolkit/components/tor-launcher/TorProcess.jsm
index 3dd194817d0a..a8ad7b73c95e 100644
--- a/toolkit/components/tor-launcher/TorProcess.jsm
+++ b/toolkit/components/tor-launcher/TorProcess.jsm
@@ -1,6 +1,6 @@
"use strict";
-var EXPORTED_SYMBOLS = ["TorProcess", "TorProcessStatus"];
+var EXPORTED_SYMBOLS = ["TorProcess"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
@@ -49,7 +49,7 @@ class TorProcess {
_exeFile = null;
_dataDir = null;
_args = [];
- _torProcess = null; // nsIProcess
+ _subprocess = null;
_status = TorProcessStatus.Unknown;
_torProcessStartTime = null; // JS Date.now()
_didConnectToTorControlPort = false; // Have we ever made a connection?
@@ -69,7 +69,7 @@ class TorProcess {
}
async start() {
- if (this._torProcess) {
+ if (this._subprocess) {
return;
}
@@ -135,13 +135,13 @@ class TorProcess {
environmentAppend: true,
stderr: "pipe",
};
- this._torProcess = await Subprocess.call(options);
+ this._subprocess = await Subprocess.call(options);
this._watchProcess();
this._status = TorProcessStatus.Running;
this._torProcessStartTime = Date.now();
} catch (e) {
this._status = TorProcessStatus.Exited;
- this._torProcess = null;
+ this._subprocess = null;
logger.error("startTor error:", e);
throw e;
}
@@ -162,7 +162,7 @@ class TorProcess {
// 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._subprocess = null;
this._status = TorProcessStatus.Exited;
}
@@ -174,14 +174,14 @@ class TorProcess {
}
async _watchProcess() {
- const watched = this._torProcess;
+ const watched = this._subprocess;
if (!watched) {
return;
}
try {
const { exitCode } = await watched.wait();
- if (watched !== this._torProcess) {
+ if (watched !== this._subprocess) {
logger.debug(`A Tor process exited with code ${exitCode}.`);
} else if (exitCode) {
logger.warn(`The watched Tor process exited with code ${exitCode}.`);
@@ -192,13 +192,13 @@ class TorProcess {
logger.error("Failed to watch the tor process", e);
}
- if (watched === this._torProcess) {
+ if (watched === this._subprocess) {
this._processExitedUnexpectedly();
}
}
_processExitedUnexpectedly() {
- this._torProcess = null;
+ this._subprocess = null;
this._status = TorProcessStatus.Exited;
// TODO: Move this logic somewhere else?
@@ -238,7 +238,7 @@ class TorProcess {
}
});
} else if (this.onExit) {
- this.onExit(unexpected);
+ this.onExit();
}
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.