[tor-launcher/master] Use SETEVENTS to monitor bootstrap status.

commit 87ee9efd3ff25be118b63e862a1c446e2e513e8e Author: Kathy Brade <brade@torproject.org> Date: Wed Apr 17 13:52:59 2013 -0400 Use SETEVENTS to monitor bootstrap status. --- src/chrome/content/network-settings.js | 7 +- src/components/tl-process.js | 89 +++++++---------------- src/components/tl-protocol.js | 127 +++++++++++++++++++------------- 3 files changed, 107 insertions(+), 116 deletions(-) diff --git a/src/chrome/content/network-settings.js b/src/chrome/content/network-settings.js index 9bdd527..97dcf82 100644 --- a/src/chrome/content/network-settings.js +++ b/src/chrome/content/network-settings.js @@ -359,9 +359,10 @@ function applySettings() gProtocolSvc.TorSendCommand("SAVECONF"); - // Start bootstrap monitor before we open the modal progress dialog. - gTorProcessService.TorMonitorBootstrap(true); - openProgressDialog(); + gIsBootstrapComplete = gTorProcessService.TorIsBootstrapDone; + if (!gIsBootstrapComplete) + openProgressDialog(); + if (gIsBootstrapComplete) close(); } diff --git a/src/components/tl-process.js b/src/components/tl-process.js index 0148529..4e73536 100644 --- a/src/components/tl-process.js +++ b/src/components/tl-process.js @@ -34,8 +34,6 @@ TorProcessService.prototype = kInitialControlConnDelayMS: 25, kMaxControlConnRetryMS: 500, kControlConnTimeoutMS: 30000, // Wait at most 30 seconds for tor to start. - kInitialMonitorDelayMS: 1000, // TODO: how can we avoid this delay? - kMonitorDelayMS: 200, // nsISupports implementation. QueryInterface: function(aIID) @@ -67,6 +65,7 @@ TorProcessService.prototype = { const kOpenNetworkSettingsTopic = "TorOpenNetworkSettings"; const kUserQuitTopic = "TorUserRequestedQuit"; + const kBootstrapStatusTopic = "TorBootstrapStatus"; if (!this.mObsSvc) { @@ -79,6 +78,7 @@ TorProcessService.prototype = this.mObsSvc.addObserver(this, "quit-application-granted", false); this.mObsSvc.addObserver(this, kOpenNetworkSettingsTopic, false); this.mObsSvc.addObserver(this, kUserQuitTopic, false); + this.mObsSvc.addObserver(this, kBootstrapStatusTopic, false); if (TorLauncherUtil.shouldStartAndOwnTor) this._startTor(); @@ -89,7 +89,7 @@ TorProcessService.prototype = this.mObsSvc.removeObserver(this, "quit-application-granted"); this.mObsSvc.removeObserver(this, kOpenNetworkSettingsTopic); this.mObsSvc.removeObserver(this, kUserQuitTopic); - this.TorMonitorBootstrap(false); + this.mObsSvc.removeObserver(this, kBootstrapStatusTopic); if (this.mTorProcess) { TorLauncherLogger.log(4, "Shutting down tor process (pid " @@ -112,7 +112,6 @@ TorProcessService.prototype = this.mControlConnTimer = null; } - this.TorMonitorBootstrap(false); this.mTorProcess = null; this.mObsSvc.notifyObservers(null, "TorProcessExited", null); @@ -135,10 +134,7 @@ TorProcessService.prototype = this.mIsTorProcessReady = true; this.mProtocolSvc.TorStartEventMonitor(); - var isInitialBootstrap = - TorLauncherUtil.getBoolPref(this.kPrefPromptAtStartup); - if (!isInitialBootstrap) - this.TorMonitorBootstrap(true); + this.mProtocolSvc.TorRetrieveBootstrapStatus(); this.mObsSvc.notifyObservers(null, "TorProcessIsReady", null); } @@ -161,16 +157,9 @@ TorProcessService.prototype = this.mControlConnTimer .TYPE_ONE_SHOT); } } - else if (aSubject == this.mTimer) - { - this._checkBootStrapStatus(); - if (this.mTimer) - { - this.mTimer.init(this, this.kMonitorDelayMS, - this.mTimer.TYPE_ONE_SHOT); - } - } } + else if (kBootstrapStatusTopic == aTopic) + this._processBootstrapStatus(aSubject.wrappedJSObject); else if (kOpenNetworkSettingsTopic == aTopic) this._openNetworkSettings(false); else if (kUserQuitTopic == aTopic) @@ -209,40 +198,22 @@ TorProcessService.prototype = lockFactory: function (aDoLock) {}, + // Public Properties and Methods /////////////////////////////////////////// get TorIsProcessReady() { return (this.mTorProcess) ? this.mIsTorProcessReady : false; }, - TorMonitorBootstrap: function(aEnable) + get TorIsBootstrapDone() { - if (!this.mProtocolSvc) - return; - - if (!aEnable) - { - if (this.mTimer) - { - this.mTimer.cancel(); - this.mTimer = null; - } - - return; - } - - if (this.mTimer) - return; - - this.mTimer = Cc["@mozilla.org/timer;1"] - .createInstance(Ci.nsITimer); - this.mTimer.init(this, this.kInitialMonitorDelayMS, - this.mTimer.TYPE_ONE_SHOT); + return this.mIsBootstrapDone; }, // Private Member Variables //////////////////////////////////////////////// mIsTorProcessReady: false, + mIsBootstrapDone: false, mIsQuitting: false, mObsSvc: null, mProtocolSvc: null, @@ -251,7 +222,6 @@ TorProcessService.prototype = mTBBTopDir: null, // nsIFile for top of TBB installation (cached) mControlConnTimer: null, mControlConnDelayMS: 0, - mTimer: null, mQuitSoon: false, // Quit was requested by the user; do so soon. @@ -373,39 +343,32 @@ TorProcessService.prototype = this.mControlConnTimer.TYPE_ONE_SHOT); }, - _checkBootStrapStatus: function() + _processBootstrapStatus: function(aStatusObj) { - var statusObj = this.mProtocolSvc.TorGetBootStrapStatus(); - if (!statusObj) + if (!aStatusObj) return; - statusObj._errorOccurred = (("WARN" == statusObj.TYPE) && - ("warn" == statusObj.RECOMMENDATION)); - - // Notify observers. - if (this.mObsSvc) - { - statusObj.wrappedJSObject = statusObj; - this.mObsSvc.notifyObservers(statusObj, "TorBootstrapStatus", null); - } - // TODO: keep viewable log of RECOMMENDATION == "ignore" messages. - if (100 == statusObj.PROGRESS) + if (100 == aStatusObj.PROGRESS) { - this.TorMonitorBootstrap(false); + this.mIsBootstrapDone = true; TorLauncherUtil.setBoolPref(this.kPrefPromptAtStartup, false); } - else if (statusObj._errorOccurred) + else { - this.TorMonitorBootstrap(false); - TorLauncherUtil.setBoolPref(this.kPrefPromptAtStartup, true); - TorLauncherLogger.log(5, "Tor bootstrap error: " + statusObj.WARNING); + this.mIsBootstrapDone = false; - var s = TorLauncherUtil.getFormattedLocalizedString( - "tor_bootstrap_failed", [statusObj.WARNING], 1); - TorLauncherUtil.showAlert(null, s); + if (aStatusObj._errorOccurred) + { + TorLauncherUtil.setBoolPref(this.kPrefPromptAtStartup, true); + TorLauncherLogger.log(5, "Tor bootstrap error: " + aStatusObj.WARNING); + + var s = TorLauncherUtil.getFormattedLocalizedString( + "tor_bootstrap_failed", [aStatusObj.WARNING], 1); + TorLauncherUtil.showAlert(null, s); + } } - }, // _checkBootstrapStatus() + }, // _processBootstrapStatus() // Blocks until network settings dialog is closed. _openNetworkSettings: function(aIsInitialBootstrap) diff --git a/src/components/tl-protocol.js b/src/components/tl-protocol.js index 22df4a6..94ab21d 100644 --- a/src/components/tl-protocol.js +++ b/src/components/tl-protocol.js @@ -4,7 +4,8 @@ // // vim: set sw=2 sts=2 ts=8 et syntax=javascript: -// Notes: decided to avoid IDL/xpt since it will complicate build process +// To avoid deadlock due to JavaScript threading limitations, this component +// should never make a direct call into the process component. const Cc = Components.classes; const Ci = Components.interfaces; @@ -246,25 +247,16 @@ TorProtocolService.prototype = return this.TorSendCommand("SETCONF", cmdArgs); }, // TorSetConf() - // If successful, returns a JS object with these fields: - // status.TYPE -- "NOTICE" or "WARN" - // status.PROGRESS -- integer - // status.TAG -- string - // status.SUMMARY -- string - // status.WARNING -- string (optional) - // status.REASON -- string (optional) - // status.COUNT -- integer (optional) - // status.RECOMMENDATION -- string (optional) - // Returns null upon failure. - TorGetBootStrapStatus: function() + // If successful, sends a "TorBootstrapStatus" notification. + TorRetrieveBootstrapStatus: function() { var cmd = "GETINFO"; var key = "status/bootstrap-phase"; var reply = this.TorSendCommand(cmd, key); if (!this.TorCommandSucceeded(reply)) { - TorLauncherLogger.log(4, "TorGetBootStrapStatus: command failed"); - return null; + TorLauncherLogger.log(4, "TorRetrieveBootstrapStatus: command failed"); + return; } // A typical reply looks like: @@ -272,48 +264,82 @@ TorProtocolService.prototype = // 250 OK reply = this._parseReply(cmd, key, reply); if (reply.lineArray) - { - var sawBootstrap = false; - var statusObj = {}; - statusObj.TYPE = "NOTICE"; + this._parseBootstrapStatus(reply.lineArray[0]); + }, - // The following code assumes that this is a one-line response. - var paramArray = this._splitReplyLine(reply.lineArray[0]); - for (var i = 0; i < paramArray.length; ++i) - { - var tokenAndVal = paramArray[i]; - var token, val; - var idx = tokenAndVal.indexOf('='); - if (idx < 0) - token = tokenAndVal; - else - { - token = tokenAndVal.substring(0, idx); - var valObj = {}; - if (!this._strUnescape(tokenAndVal.substring(idx + 1), valObj)) - continue; // skip this token/value pair. + // If successful, returns a JS object with these fields: + // status.TYPE -- "NOTICE" or "WARN" + // status.PROGRESS -- integer + // status.TAG -- string + // status.SUMMARY -- string + // status.WARNING -- string (optional) + // status.REASON -- string (optional) + // status.COUNT -- integer (optional) + // status.RECOMMENDATION -- string (optional) + // A "TorBootstrapStatus" notification is also sent. + // Returns null upon failure. + _parseBootstrapStatus: function(aStatusMsg) + { + if (!aStatusMsg || (0 == aStatusMsg.length)) + return null; - val = valObj.result; - } + var sawBootstrap = false; + var sawCircuitEstablished = false; + var statusObj = {}; + statusObj.TYPE = "NOTICE"; - if ("BOOTSTRAP" == token) - sawBootstrap = true; - else if (("WARN" == token) || ("NOTICE" == token)) - statusObj.TYPE = token; - else if (("COUNT" == token) || ("PROGRESS" == token)) - statusObj[token] = parseInt(val, 10); - else - statusObj[token] = val; + // The following code assumes that this is a one-line response. + var paramArray = this._splitReplyLine(aStatusMsg); + for (var i = 0; i < paramArray.length; ++i) + { + var tokenAndVal = paramArray[i]; + var token, val; + var idx = tokenAndVal.indexOf('='); + if (idx < 0) + token = tokenAndVal; + else + { + token = tokenAndVal.substring(0, idx); + var valObj = {}; + if (!this._strUnescape(tokenAndVal.substring(idx + 1), valObj)) + continue; // skip this token/value pair. + + val = valObj.result; } - if (!sawBootstrap) - TorLauncherLogger.log(4, "TorGetBootStrapStatus: missing BOOTSTRAP"); + if ("BOOTSTRAP" == token) + sawBootstrap = true; + else if ("CIRCUIT_ESTABLISHED" == token) + sawCircuitEstablished = true; + else if (("WARN" == token) || ("NOTICE" == token)) + statusObj.TYPE = token; + else if (("COUNT" == token) || ("PROGRESS" == token)) + statusObj[token] = parseInt(val, 10); else - this._dumpObj("BootstrapStatus", statusObj); // TODO: remove this. + statusObj[token] = val; } + if (!sawBootstrap) + { + if (sawCircuitEstablished) + TorLauncherLogger.log(2, "_parseBootstrapStatus: CIRCUIT_ESTABLISHED"); + else + TorLauncherLogger.log(4, "_parseBootstrapStatus: missing BOOTSTRAP"); + + return null; + } + + // this._dumpObj("BootstrapStatus", statusObj); + statusObj._errorOccurred = (("WARN" == statusObj.TYPE) && + ("warn" == statusObj.RECOMMENDATION)); + + // Notify observers. + var obsSvc = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); + statusObj.wrappedJSObject = statusObj; + obsSvc.notifyObservers(statusObj, "TorBootstrapStatus", null); return statusObj; - }, // TorGetBootStrapStatus() + }, // _parseBootstrapStatus() // Executes a command on the control port. // Return a reply object or null if a fatal error occurs. @@ -422,7 +448,6 @@ TorProtocolService.prototype = // Private Member Variables //////////////////////////////////////////////// - mObsSvc: null, mControlPort: null, mControlHost: null, mControlPassword: null, // JS string that contains hex-encoded password. @@ -1136,6 +1161,7 @@ TorProtocolService.prototype = if ((idx > 0)) { let eventType = s.substring(0, idx); + let msg = s.substr(idx + 1); switch (eventType) { case "DEBUG": @@ -1144,13 +1170,14 @@ TorProtocolService.prototype = case "WARN": case "ERR": var now = new Date(); - let logObj = { date: now, type: eventType, msg: s.substr(idx) }; + let logObj = { date: now, type: eventType, msg: msg }; if (!this.mTorLog) this.mTorLog = []; this.mTorLog.push(logObj); break; case "STATUS_CLIENT": - /*FALLTHRU*/ + this._parseBootstrapStatus(msg); + break; default: this._dumpObj(eventType + "_event", aReply); }
participants (1)
-
brade@torproject.org