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

brade at torproject.org brade at torproject.org
Wed Apr 17 17:53:24 UTC 2013


commit 87ee9efd3ff25be118b63e862a1c446e2e513e8e
Author: Kathy Brade <brade at 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);
       }



More information about the tor-commits mailing list