commit 580e2c01a607dbe07c680041a1e33d9dd750b617 Author: Matthew Finkel sysrqb@torproject.org Date: Wed Aug 25 14:30:10 2021 +0000
Bug 40004: Convert tl-protocol to async.
We resolve the issue of deadlocks within Firefox, and other unknown bugs, during initialization by using asynchronous programming in the controller implementation. At the same time, we take advantage of torbutton's async 'controller' module instead of duplicating logic. --- src/chrome/content/network-settings.js | 125 ++++++++-------- src/components/tl-process.js | 10 +- src/components/tl-protocol.js | 261 ++++++++++++--------------------- 3 files changed, 159 insertions(+), 237 deletions(-)
diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js index 81d7138..5a3d441 100644 --- a/src/chrome/content/network-settings.js +++ b/src/chrome/content/network-settings.js @@ -115,7 +115,7 @@ var gBridgeDBBridges = undefined; // Array of bridge lines. var gBridgeDBRequestEventListeners = [];
-function initDialogCommon() +async function initDialogCommon() { loadSharedXUL();
@@ -268,10 +268,10 @@ function resizeDialogToFitContent() }
-function initDialog() +async function initDialog() { gIsInitialBootstrap = window.arguments[0]; - initDialogCommon(); + await initDialogCommon();
if (window.arguments.length > 1) gInitialPanelID = window.arguments[1]; @@ -297,8 +297,8 @@ function initDialog() if (haveWizard) { // Add wizardfinish event handler. - document.addEventListener("wizardfinish", (aEvent) => { - if (!onWizardFinish()) + document.addEventListener("wizardfinish", function (aEvent) { + if (!(onWizardFinish())) aEvent.preventDefault(); });
@@ -375,9 +375,9 @@ function initDialog() }
-function initLocaleDialog() +async function initLocaleDialog() { - initDialogCommon(); + await initDialogCommon();
// Add wizardfinish event handler. document.addEventListener("wizardfinish", (aEvent) => { @@ -590,22 +590,22 @@ function getWizard() }
-function onWizardFirstPanelConnect() +async function onWizardFirstPanelConnect() { // If the user configured bridge or proxy settings, prompt before // discarding their data. if (isBridgeConfigured() || isProxyConfigured()) showPanel(kWizardDiscardSettingsPageID); else - removeSettingsAndConnect() + await removeSettingsAndConnect() }
-function removeSettingsAndConnect() +async function removeSettingsAndConnect() { - applySettings(true); // Use default settings. + await applySettings(true); // Use default settings. if (!gTorProcessService.TorIsBootstrapDone) - readTorSettings(); // Ensure UI matches the settings that were used. + await readTorSettings(); // Ensure UI matches the settings that were used. }
@@ -648,10 +648,10 @@ function onBridgeTypeRadioChange() }
-function onOpenBridgeDBRequestPrompt() +async function onOpenBridgeDBRequestPrompt() { // Obtain the meek client path and args from the tor configuration. - let reply = gProtocolSvc.TorGetConf("ClientTransportPlugin"); + let reply = await gProtocolSvc.TorGetConf("ClientTransportPlugin"); if (!gProtocolSvc.TorCommandSucceeded(reply)) return;
@@ -908,8 +908,9 @@ var gObserver = { showCopyLogButton(true); if (kTorBootstrapErrorTopic == aTopic) { - stopTorBootstrap(); - showErrorMessage(aSubject.wrappedJSObject, true); + stopTorBootstrap().then((value) => { + showErrorMessage(aSubject.wrappedJSObject, true); + }); } return; } @@ -1019,7 +1020,7 @@ function updateBootstrapProgress(aStatusObj) }
-function readTorSettings() +async function readTorSettings() { TorLauncherLogger.log(2, "readTorSettings " + "----------------------------------------------"); @@ -1028,8 +1029,8 @@ function readTorSettings() try { // TODO: retrieve > 1 key at one time inside initProxySettings() et al. - didSucceed = initBridgeSettings() && - initProxySettings() && initFirewallSettings(); + didSucceed = await initBridgeSettings() && + await initProxySettings() && await initFirewallSettings(); } catch (e) { TorLauncherLogger.safelog(4, "Error in readTorSettings: ", e); }
@@ -1048,13 +1049,13 @@ function readTorSettings() }
-function onTorStarted() +async function onTorStarted() { - if (readTorSettings()) + if (await readTorSettings()) { showPanel(); if (gInitialPanelID) - advanceToWizardPanel(gInitialPanelID); + await advanceToWizardPanel(gInitialPanelID); } }
@@ -1087,7 +1088,7 @@ function showPanel(aPanelID)
// This function assumes that you are starting on the first page. -function advanceToWizardPanel(aPanelID) +async function advanceToWizardPanel(aPanelID) { var wizard = getWizard(); if (!wizard) @@ -1095,7 +1096,7 @@ function advanceToWizardPanel(aPanelID)
if (kWizardProgressPageID == aPanelID) { - showProgressPanel(); + await showProgressPanel(); return; }
@@ -1592,7 +1593,8 @@ function onWizardFinish() return false; }
- return applySettings(false); + applySettings(false).then(result => { if (result) window.setTimeout(function() { close(); }, 0);}); + return false; }
@@ -1616,19 +1618,20 @@ function onNetworkSettingsFinish() return false; }
- return applySettings(false); + applySettings(false).then(result => { if (result) window.setTimeout(function() { close(); }, 0);}); + return false; }
// When the progress panel is open, cancel stops bootstrapping... unless // we are showing an error, in which case the action is "Reconfigure". -function onProgressCancelOrReconfigure(aWizard) +async function onProgressCancelOrReconfigure(aWizard) { let progressContent = document.getElementById("progressContent"); if (!progressContent || !progressContent.hasAttribute("isShowingReconfigure")) { - stopTorBootstrap(); + await stopTorBootstrap(); }
if (aWizard) @@ -1737,10 +1740,10 @@ function closeHelp()
// Returns true if successful. -function initProxySettings() +async function initProxySettings() { let proxyType, proxyAddrPort, proxyUsername, proxyPassword; - let reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks4Proxy, null); + let reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks4Proxy, null); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false;
@@ -1751,7 +1754,7 @@ function initProxySettings() } else { - reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5Proxy, null); + reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks5Proxy, null); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false;
@@ -1759,12 +1762,12 @@ function initProxySettings() { proxyType = "SOCKS5"; proxyAddrPort = reply.retVal; - reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyUsername, null); + reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyUsername, null); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false;
proxyUsername = reply.retVal; - reply = gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyPassword, null); + reply = await gProtocolSvc.TorGetConfStr(kTorConfKeySocks5ProxyPassword, null); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false;
@@ -1772,7 +1775,7 @@ function initProxySettings() } else { - reply = gProtocolSvc.TorGetConfStr(kTorConfKeyHTTPSProxy, null); + reply = await gProtocolSvc.TorGetConfStr(kTorConfKeyHTTPSProxy, null); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false;
@@ -1780,7 +1783,7 @@ function initProxySettings() { proxyType = "HTTP"; proxyAddrPort = reply.retVal; - reply = gProtocolSvc.TorGetConfStr( + reply = await gProtocolSvc.TorGetConfStr( kTorConfKeyHTTPSProxyAuthenticator, null); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false; @@ -1818,13 +1821,13 @@ function initProxySettings()
// Returns true if successful. -function initFirewallSettings() +async function initFirewallSettings() { if (getWizard()) return true; // The wizard does not directly expose firewall settings.
var allowedPorts; - var reply = gProtocolSvc.TorGetConfStr(kTorConfKeyReachableAddresses, null); + var reply = await gProtocolSvc.TorGetConfStr(kTorConfKeyReachableAddresses, null); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false;
@@ -1854,7 +1857,7 @@ function initFirewallSettings()
// Returns true if successful. -function initBridgeSettings() +async function initBridgeSettings() { let typeList = TorLauncherUtil.defaultBridgeTypes; let canUseDefaultBridges = (typeList && (typeList.length > 0)); @@ -1871,14 +1874,14 @@ function initBridgeSettings() { showMenuListPlaceholderText(kDefaultBridgeTypeMenuList);
- let reply = gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false); + let reply = await gProtocolSvc.TorGetConfBool(kTorConfKeyUseBridges, false); if (!gProtocolSvc.TorCommandSucceeded(reply)) return false;
useBridges = reply.retVal;
// Get the list of configured bridges from tor. - let bridgeReply = gProtocolSvc.TorGetConf(kTorConfKeyBridgeList); + let bridgeReply = await gProtocolSvc.TorGetConf(kTorConfKeyBridgeList); if (!gProtocolSvc.TorCommandSucceeded(bridgeReply)) return false;
@@ -1953,21 +1956,21 @@ function initBridgeSettings()
// Returns true if settings were successfully applied. -function applySettings(aUseDefaults) +async function applySettings(aUseDefaults) { TorLauncherLogger.log(2, "applySettings ---------------------" + "----------------------------------------------"); var didSucceed = false; try { - didSucceed = applyBridgeSettings(aUseDefaults) && - applyProxySettings(aUseDefaults) && - applyFirewallSettings(aUseDefaults); + didSucceed = await applyBridgeSettings(aUseDefaults) && + await applyProxySettings(aUseDefaults) && + await applyFirewallSettings(aUseDefaults); } catch (e) { TorLauncherLogger.safelog(4, "Error in applySettings: ", e); }
if (didSucceed) - useSettings(); + await useSettings();
TorLauncherLogger.log(2, "applySettings done");
@@ -1975,11 +1978,11 @@ function applySettings(aUseDefaults) }
-function useSettings() +async function useSettings() { var settings = {}; settings[kTorConfKeyDisableNetwork] = false; - let didApply = setConfAndReportErrors(settings, null); + let didApply = await setConfAndReportErrors(settings, null); if (!didApply) return;
@@ -1997,7 +2000,7 @@ function useSettings()
gIsPostRestartBootstrapNeeded = false;
- gProtocolSvc.TorSendCommand("SAVECONF"); + await gProtocolSvc.TorSendCommand("SAVECONF"); gTorProcessService.TorClearBootstrapError();
// If bootstrapping has finished or we are not responsible for starting @@ -2009,11 +2012,11 @@ function useSettings() return; }
- showProgressPanel(); + await showProgressPanel(); }
-function stopTorBootstrap() +async function stopTorBootstrap() { // Tell tor to disable use of the network; this should stop the bootstrap // process. @@ -2023,7 +2026,7 @@ function stopTorBootstrap() let settings = {}; settings["DisableNetwork"] = true; let errObj = {}; - if (!gProtocolSvc.TorSetConfWithReply(settings, errObj)) + if (!await gProtocolSvc.TorSetConfWithReply(settings, errObj)) TorLauncherLogger.log(5, kErrorPrefix + errObj.details); } catch(e) @@ -2033,7 +2036,7 @@ function stopTorBootstrap() }
-function showProgressPanel() +async function showProgressPanel() { let progressContent = document.getElementById("progressContent"); if (progressContent) @@ -2072,7 +2075,7 @@ function showProgressPanel()
// Request the most recent bootstrap status info so that a // TorBootstrapStatus notification is generated as soon as possible. - gProtocolSvc.TorRetrieveBootstrapStatus(); + await gProtocolSvc.TorRetrieveBootstrapStatus();
// Also start a fail-safe timer to ensure that the progress bar is displayed // within 2 seconds in all cases. @@ -2089,14 +2092,14 @@ function showProgressMeterIfNoError()
// Returns true if settings were successfully applied. -function applyProxySettings(aUseDefaults) +async function applyProxySettings(aUseDefaults) { let settings = aUseDefaults ? getDefaultProxySettings() : getAndValidateProxySettings(false); if (!settings) return false;
- return setConfAndReportErrors(settings, "configureSettings"); + return await setConfAndReportErrors(settings, "configureSettings"); }
@@ -2187,7 +2190,7 @@ function reportValidationError(aStrKey)
// Returns true if settings were successfully applied. -function applyFirewallSettings(aUseDefaults) +async function applyFirewallSettings(aUseDefaults) { let settings; if (aUseDefaults) @@ -2200,7 +2203,7 @@ function applyFirewallSettings(aUseDefaults) if (!settings) return false;
- return setConfAndReportErrors(settings, null); + return await setConfAndReportErrors(settings, null); }
@@ -2327,7 +2330,7 @@ function initDefaultBridgeTypeMenu()
// Returns true if settings were successfully applied. -function applyBridgeSettings(aUseDefaults) +async function applyBridgeSettings(aUseDefaults) { let settings = (aUseDefaults) ? getDefaultBridgeSettings() : getAndValidateBridgeSettings(); @@ -2337,7 +2340,7 @@ function applyBridgeSettings(aUseDefaults) if (aUseDefaults) TorLauncherUtil.setCharPref(kPrefDefaultBridgeType, "");
- return setConfAndReportErrors(settings, "configureSettings"); + return await setConfAndReportErrors(settings, "configureSettings"); }
@@ -2450,10 +2453,10 @@ function parseAndValidateBridges(aStr)
// Returns true if successful. // aShowOnErrorPanelID is only used when displaying the wizard. -function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID) +async function setConfAndReportErrors(aSettingsObj, aShowOnErrorPanelID) { var errObj = {}; - var didSucceed = gProtocolSvc.TorSetConfWithReply(aSettingsObj, errObj); + var didSucceed = await gProtocolSvc.TorSetConfWithReply(aSettingsObj, errObj); if (!didSucceed) { if (aShowOnErrorPanelID) diff --git a/src/components/tl-process.js b/src/components/tl-process.js index a4374f9..bafc295 100644 --- a/src/components/tl-process.js +++ b/src/components/tl-process.js @@ -86,7 +86,7 @@ TorProcessService.prototype = lockFactory: function(aDoLock) {},
// nsIObserver implementation. - observe: function(aSubject, aTopic, aParam) + observe: async function(aSubject, aTopic, aParam) { const kOpenNetworkSettingsTopic = "TorOpenNetworkSettings"; const kUserQuitTopic = "TorUserRequestedQuit"; @@ -254,7 +254,7 @@ TorProcessService.prototype = // We configure default bridges each time we start tor in case // new default bridge preference values are available (e.g., due // to a TBB update). - this._configureDefaultBridges(); + await this._configureDefaultBridges(); }
this.mObsSvc.notifyObservers(null, "TorProcessIsReady", null); @@ -706,7 +706,7 @@ TorProcessService.prototype = return this.kDefaultBridgesStatus_InUse; },
- _configureDefaultBridges: function() + _configureDefaultBridges: async function() { var settings = {}; var bridgeArray = TorLauncherUtil.defaultBridges; @@ -714,7 +714,7 @@ TorProcessService.prototype = settings["UseBridges"] = useBridges; settings["Bridge"] = bridgeArray; var errObj = {}; - var didSucceed = this.mProtocolSvc.TorSetConfWithReply(settings, errObj); + var didSucceed = await this.mProtocolSvc.TorSetConfWithReply(settings, errObj);
// If the network settings wizard was not opened at startup, enable the // network so that bootstrapping will proceed with the default bridges. @@ -722,7 +722,7 @@ TorProcessService.prototype = { settings = {}; settings["DisableNetwork"] = false; - if (!this.mProtocolSvc.TorSetConfWithReply(settings, + if (!await this.mProtocolSvc.TorSetConfWithReply(settings, (didSucceed) ? errObj : null)) { didSucceed = false; diff --git a/src/components/tl-protocol.js b/src/components/tl-protocol.js index 0e8075a..93b22bb 100644 --- a/src/components/tl-protocol.js +++ b/src/components/tl-protocol.js @@ -14,12 +14,16 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetters(this, { + setTimeout: "resource://gre/modules/Timer.jsm", +}); XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherUtil", "resource://torlauncher/modules/tl-util.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TorLauncherLogger", "resource://torlauncher/modules/tl-logger.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); +let { configureControlPortModule, controller } = Cu.import("resource://torbutton/modules/tor-control-port.js", {});
function TorProtocolService() @@ -198,6 +202,12 @@ function TorProtocolService() TorLauncherLogger.log(3, "SOCKS host: " + this.mSOCKSPortInfo.host); TorLauncherLogger.log(3, "SOCKS port: " + this.mSOCKSPortInfo.port); } + + // Set the global control port info parameters. + // These values may be overwritten by torbutton when it initializes, but + // torbutton's values *should* be identical. + configureControlPortModule(this.mControlIPCFile, this.mControlHost, + this.mControlPort, this.mControlPassword); } catch(e) { @@ -323,13 +333,13 @@ TorProtocolService.prototype = // Perform a GETCONF command. // If a fatal error occurs, null is returned. Otherwise, a reply object is // returned. - TorGetConf: function(aKey) + TorGetConf: async function(aKey) { if (!aKey || (aKey.length < 1)) return null;
var cmd = "GETCONF"; - var reply = this.TorSendCommand(cmd, aKey); + var reply = await this.TorSendCommand(cmd, aKey); if (!this.TorCommandSucceeded(reply)) return reply;
@@ -338,9 +348,9 @@ TorProtocolService.prototype =
// Returns a reply object. If the GETCONF command succeeded, reply.retVal // is set (if there is no setting for aKey, it is set to aDefault). - TorGetConfStr: function(aKey, aDefault) + TorGetConfStr: async function(aKey, aDefault) { - var reply = this.TorGetConf(aKey); + var reply = await this.TorGetConf(aKey); if (this.TorCommandSucceeded(reply)) { if (reply.lineArray.length > 0) @@ -354,9 +364,9 @@ TorProtocolService.prototype =
// Returns a reply object. If the GETCONF command succeeded, reply.retVal // is set (if there is no setting for aKey, it is set to aDefault). - TorGetConfBool: function(aKey, aDefault) + TorGetConfBool: async function(aKey, aDefault) { - var reply = this.TorGetConf(aKey); + var reply = await this.TorGetConf(aKey); if (this.TorCommandSucceeded(reply)) { if (reply.lineArray.length > 0) @@ -376,7 +386,7 @@ TorProtocolService.prototype = // passed in the SETCONF command. // If a fatal error occurs, null is returned. Otherwise, a reply object is // returned. - TorSetConf: function(aSettingsObj) + TorSetConf: async function(aSettingsObj) { if (!aSettingsObj) return null; @@ -420,14 +430,14 @@ TorProtocolService.prototype = return null; }
- return this.TorSendCommand("SETCONF", cmdArgs); + return await this.TorSendCommand("SETCONF", cmdArgs); }, // TorSetConf()
// Returns true if successful. // Upon failure, aErrorObj.details will be set to a string. - TorSetConfWithReply: function(aSettingsObj, aErrorObj) + TorSetConfWithReply: async function(aSettingsObj, aErrorObj) { - var reply = this.TorSetConf(aSettingsObj); + var reply = await this.TorSetConf(aSettingsObj); var didSucceed = this.TorCommandSucceeded(reply); if (!didSucceed) { @@ -450,11 +460,11 @@ TorProtocolService.prototype = },
// If successful, sends a "TorBootstrapStatus" notification. - TorRetrieveBootstrapStatus: function() + TorRetrieveBootstrapStatus: async function() { var cmd = "GETINFO"; var key = "status/bootstrap-phase"; - var reply = this.TorSendCommand(cmd, key); + var reply = await this.TorSendCommand(cmd, key); if (!this.TorCommandSucceeded(reply)) { TorLauncherLogger.log(4, "TorRetrieveBootstrapStatus: command failed"); @@ -548,7 +558,7 @@ TorProtocolService.prototype =
// Executes a command on the control port. // Return a reply object or null if a fatal error occurs. - TorSendCommand: function(aCmd, aArgs) + TorSendCommand: async function(aCmd, aArgs) { var reply; for (var attempt = 0; !reply && (attempt < 2); ++attempt) @@ -556,10 +566,10 @@ TorProtocolService.prototype = var conn; try { - conn = this._getConnection(); + conn = await this._getConnection(); if (conn) { - reply = this._sendCommand(conn, aCmd, aArgs) + reply = await conn.sendCommand(aCmd + (aArgs ? " " + aArgs : "")); if (reply) this._returnConnection(conn); // Return for reuse. else @@ -573,6 +583,22 @@ TorProtocolService.prototype = } }
+ // We failed to acquire the controller after multiple attempts. + // Try again after some time. + if (!conn) { + TorLauncherLogger.safelog(2, "TorSendCommand: Acquiring control connection failed: ", aCmd + ", " + aArgs); + let thisTorSendCommand = this.TorSendCommand.bind(this); + return await new Promise(resolve => setTimeout(function() { + TorLauncherLogger.safelog(2, "TorSendCommand: Trying again, resolving TorSendCommand: ", aCmd + ", " + aArgs); + resolve(thisTorSendCommand(aCmd, aArgs)); + }, 250) + )}; + + if (!reply) + return reply; + + reply = this.TorParseCommandResponse(reply); + return reply; }, // TorSendCommand()
@@ -581,6 +607,21 @@ TorProtocolService.prototype = return !!(aReply && (this.kCmdStatusOK == aReply.statusCode)); },
+ // Helper function for converting a raw controller response into a parsed object. + TorParseCommandResponse: function(reply) + { + if (!reply) + return {}; + let lines = reply.split("\r\n"); + reply = {}; + for (let line in lines) { + if (this._parseOneReplyLine(lines[line], reply) || reply._parseError) { + break; + } + } + return reply; + }, + // TorCleanupConnection() is called during browser shutdown. TorCleanupConnection: function() { @@ -588,12 +629,12 @@ TorProtocolService.prototype = this._shutDownEventMonitor(); },
- TorStartEventMonitor: function() + TorStartEventMonitor: async function() { if (this.mEventMonitorConnection) return;
- var conn = this._openAuthenticatedConnection(true); + var conn = await this._openAuthenticatedConnection(true); if (!conn) { TorLauncherLogger.log(4, @@ -603,7 +644,9 @@ TorProtocolService.prototype =
// TODO: optionally monitor INFO and DEBUG log messages. var events = "STATUS_CLIENT NOTICE WARN ERR"; - var reply = this._sendCommand(conn, "SETEVENTS", events); + //var events = "STATUS_CLIENT WARN ERR"; + var reply = await conn.sendCommand("SETEVENTS " + events); + reply = this.TorParseCommandResponse(reply); if (!this.TorCommandSucceeded(reply)) { TorLauncherLogger.log(4, "SETEVENTS failed"); @@ -671,9 +714,9 @@ TorProtocolService.prototype =
// Return true if a control connection is established (will create a // connection if necessary). - TorHaveControlConnection: function() + TorHaveControlConnection: async function() { - var conn = this._getConnection(); + var conn = await this._getConnection(); this._returnConnection(conn); return (conn != null); }, @@ -703,7 +746,7 @@ TorProtocolService.prototype = // inStream // nsIInputStream // binInStream // nsIBinaryInputStream // binOutStream // nsIBinaryOutputStream - _getConnection: function() + _getConnection: async function() { if (this.mControlConnection) { @@ -714,7 +757,7 @@ TorProtocolService.prototype = } } else - this.mControlConnection = this._openAuthenticatedConnection(false); + this.mControlConnection = await this._openAuthenticatedConnection(false);
if (this.mControlConnection) this.mControlConnection.inUse = true; @@ -728,101 +771,27 @@ TorProtocolService.prototype = this.mControlConnection.inUse = false; },
- _openAuthenticatedConnection: function(aIsEventConnection) + _openAuthenticatedConnection: async function(aIsEventConnection) { var conn; - try - { - let sts = Cc["@mozilla.org/network/socket-transport-service;1"] - .getService(Ci.nsISocketTransportService); - let socket; - if (this.mControlIPCFile) - { - let exists = this.mControlIPCFile.exists(); - if (!exists) - { - TorLauncherLogger.log(5, "Control port IPC object does not exist: " + - this.mControlIPCFile.path); - } - else - { - let isSpecial = this.mControlIPCFile.isSpecial(); - if (!isSpecial) - { - TorLauncherLogger.log(5, - "Control port IPC object is not a special file: " + - this.mControlIPCFile.path); - } - else - { - TorLauncherLogger.log(2, "Opening control connection to " + - this.mControlIPCFile.path); - socket = sts.createUnixDomainTransport(this.mControlIPCFile); - } - } - } - else - { - TorLauncherLogger.log(2, "Opening control connection to " + - this.mControlHost + ":" + this.mControlPort); - socket = sts.createTransport([], this.mControlHost, - this.mControlPort, null); - } - - if (!socket) - return null; - - // Our event monitor connection is non-blocking and unbuffered (an - // asyncWait() call is used so we only read data when we know that - // some is available). - // Our main control connection is blocking and unbuffered (using - // buffering may prevent data from being sent before we enter a - // blocking readBytes() call. - var flags = (aIsEventConnection) ? 0 - : socket.OPEN_BLOCKING | socket.OPEN_UNBUFFERED; - // If using a blocking socket, we set segment size and count to 1 to - // avoid buffering inside the Mozilla code. See Tor ticket # 8642. - var segSize = (aIsEventConnection) ? 0 : 1; - var segCount = (aIsEventConnection) ? 0 : 1; - var inStream = socket.openInputStream(flags, segSize, segCount); - var outStream = socket.openOutputStream(flags, segSize, segCount); - - var binInStream = Cc["@mozilla.org/binaryinputstream;1"] - .createInstance(Ci.nsIBinaryInputStream); - var binOutStream = Cc["@mozilla.org/binaryoutputstream;1"] - .createInstance(Ci.nsIBinaryOutputStream); - binInStream.setInputStream(inStream); - binOutStream.setOutputStream(outStream); - conn = { useCount: 0, socket: socket, inStream: inStream, - binInStream: binInStream, binOutStream: binOutStream }; - - // AUTHENTICATE - var pwdArg = this._strEscape(this.mControlPassword); - if (pwdArg && (pwdArg.length > 0) && (pwdArg.charAt(0) != '"')) - { - // Surround non-hex strings with double quotes. - const kIsHexRE = /^[A-Fa-f0-9]*$/; - if (!kIsHexRE.test(pwdArg)) - pwdArg = '"' + pwdArg + '"'; - } - var reply = this._sendCommand(conn, "AUTHENTICATE", pwdArg); - if (!this.TorCommandSucceeded(reply)) - { - TorLauncherLogger.log(4, "authenticate failed"); - return null; - } + try { + const avoidCache = true; + conn = controller(e => { throw e; }, avoidCache);
if (!aIsEventConnection && TorLauncherUtil.shouldStartAndOwnTor && !TorLauncherUtil.shouldOnlyConfigureTor) { // Try to become the primary controller (TAKEOWNERSHIP). - reply = this._sendCommand(conn, "TAKEOWNERSHIP", null); + const takeOwnership = "TAKEOWNERSHIP"; + let reply = await conn.sendCommand(takeOwnership); + reply = this.TorParseCommandResponse(reply); if (!this.TorCommandSucceeded(reply)) TorLauncherLogger.log(4, "take ownership failed"); else { - reply = this._sendCommand(conn, "RESETCONF", - "__OwningControllerProcess"); + const resetConf = "RESETCONF __OwningControllerProcess"; + reply = await conn.sendCommand(takeOwnership); + reply = this.TorParseCommandResponse(reply); if (!this.TorCommandSucceeded(reply)) TorLauncherLogger.log(4, "clear owning controller process failed"); } @@ -952,6 +921,7 @@ TorProtocolService.prototype = aReplyObj._parseError = false; }
+ if (aLine.length < 4) { TorLauncherLogger.safelog(4, "Unexpected response: ", aLine); @@ -1396,77 +1366,26 @@ TorProtocolService.prototype = return;
var _this = this; - var eventReader = // An implementation of nsIInputStreamCallback. - { - onInputStreamReady: function(aInStream) - { - if (!_this.mEventMonitorConnection || - (_this.mEventMonitorConnection.inStream != aInStream)) - { - return; - } - - try - { - var binStream = _this.mEventMonitorConnection.binInStream; - var bytes = binStream.readBytes(binStream.available()); - if (!_this.mEventMonitorBuffer) - _this.mEventMonitorBuffer = bytes; - else - _this.mEventMonitorBuffer += bytes; - _this._processEventData(); - - _this._waitForEventData(); - } - catch (e) - { - // Probably we got here because tor exited. If tor is restarted by - // Tor Launcher, the event monitor will be restarted too. - TorLauncherLogger.safelog(4, "Event monitor read error", e); - _this._shutDownEventMonitor(); - } - } - }; - - var curThread = Cc["@mozilla.org/thread-manager;1"].getService() - .currentThread; - var asyncInStream = this.mEventMonitorConnection.inStream - .QueryInterface(Ci.nsIAsyncInputStream); - asyncInStream.asyncWait(eventReader, 0, 0, curThread); + this.mEventMonitorConnection.watchEvent("STATUS_CLIENT", null, function (data) { + return _this._processEventData.bind(_this, data)(); + }, true); },
- _processEventData: function() + _processEventData: function(line) { - var replyData = this.mEventMonitorBuffer; - if (!replyData) + if (!line) return;
- var idx = -1; - do + TorLauncherLogger.safelog(2, "Event response: ", line); + if (!this.mEventMonitorInProgressReply) + this.mEventMonitorInProgressReply = {}; + var replyObj = this.mEventMonitorInProgressReply; + var isComplete = this._parseOneReplyLine(line, replyObj); + if (isComplete) { - idx = replyData.indexOf('\n'); - if (idx >= 0) - { - let line = replyData.substring(0, idx); - replyData = replyData.substring(idx + 1); - let len = line.length; - if ((len > 0) && ('\r' == line.substr(len - 1))) - line = line.substr(0, len - 1); - - TorLauncherLogger.safelog(2, "Event response: ", line); - if (!this.mEventMonitorInProgressReply) - this.mEventMonitorInProgressReply = {}; - var replyObj = this.mEventMonitorInProgressReply; - var isComplete = this._parseOneReplyLine(line, replyObj); - if (isComplete) - { - this._processEventReply(replyObj); - this.mEventMonitorInProgressReply = null; - } - } - } while ((idx >= 0) && replyData) - - this.mEventMonitorBuffer = replyData; + this._processEventReply(replyObj); + this.mEventMonitorInProgressReply = null; + } },
_processEventReply: function(aReply)