Bug 736096 - Reprioritize networks when the priorities get too high to prevent overflow. r=cjones
authorBlake Kaplan <mrbkap@gmail.com>
Thu, 29 Mar 2012 17:17:46 +0200
changeset 94120 d2612e79e4563442673f64b97dbd75d45dbe9f25
parent 94119 85a31c1e4963f5627a76ae92241eb388da40d00c
child 94121 f4fe6a11813922d3d25564d2d1240e55073e2ba0
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs736096
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 736096 - Reprioritize networks when the priorities get too high to prevent overflow. r=cjones
dom/wifi/WifiWorker.js
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1207,16 +1207,18 @@ function WifiWorker() {
     });
 
     WifiManager.getConfiguredNetworks(function(networks) {
       if (!networks) {
         debug("Unable to get configured networks");
         return;
       }
 
+      this._highestPriority = -1;
+
       // Convert between netId-based and ssid-based indexing.
       for (let net in networks) {
         let network = networks[net];
         if (!network.ssid) {
           delete networks[net]; // TODO support these?
           continue;
         }
 
@@ -1450,16 +1452,82 @@ WifiWorker.prototype = {
     if (!this._connectionInfoTimer)
       return;
 
     this._connectionInfoTimer.cancel();
     this._connectionInfoTimer = null;
     this._lastConnectionInfo = null;
   },
 
+  // Important side effect: calls WifiManager.saveConfig.
+  _reprioritizeNetworks: function(callback) {
+    // First, sort the networks in orer of their priority.
+    var ordered = Object.getOwnPropertyNames(this.configuredNetworks);
+    let self = this;
+    ordered.sort(function(a, b) {
+      var neta = self.configuredNetworks[a],
+          netb = self.configuredNetworks[b];
+
+      // Sort unsorted networks to the end of the list.
+      if (isNaN(neta.priority))
+        return isNaN(netb.priority) ? 0 : 1;
+      if (isNaN(netb.priority))
+        return -1;
+      return netb.priority - neta.priority;
+    });
+
+    // Skip unsorted networks.
+    let newPriority = 0, i;
+    for (i = ordered.length - 1; i >= 0; --i) {
+      if (!isNaN(this.configuredNetworks[ordered[i]].priority))
+        break;
+    }
+
+    // No networks we care about?
+    if (i < 0) {
+      WifiManager.saveConfig(callback);
+      return;
+    }
+
+    // Now assign priorities from 0 to length, starting with the smallest
+    // priority and heading towards the highest (note the dependency between
+    // total and i here).
+    let done = 0, errors = 0, total = i + 1;
+    for (; i >= 0; --i) {
+      let network = this.configuredNetworks[ordered[i]];
+      network.priority = newPriority++;
+
+      // Note: networkUpdated declared below since it happens logically after
+      // this loop.
+      WifiManager.updateNetwork(network, networkUpdated);
+    }
+
+    function networkUpdated(ok) {
+      if (!ok)
+        ++errors;
+      if (++done === total) {
+        if (errors > 0) {
+          callback(false);
+          return;
+        }
+
+        WifiManager.saveConfig(function(ok) {
+          if (!ok) {
+            callback(false);
+            return;
+          }
+
+          self._reloadConfiguredNetworks(function(ok) {
+            callback(ok);
+          });
+        });
+      }
+    }
+  },
+
   // nsIWifi
 
   _fireEvent: function(message, data) {
     this._mm.sendAsyncMessage("WifiManager:" + message, data);
   },
 
   _sendMessage: function(message, success, data, rid, mid) {
     this._mm.sendAsyncMessage(message + (success ? ":OK" : ":NO"),
@@ -1500,46 +1568,51 @@ WifiWorker.prototype = {
       if (enable && status === 0)
         WifiManager.start();
       this._sendMessage("WifiManager:setEnabled:Return",
                         (status === 0), enable, rid, mid);
     }).bind(this));
   },
 
   associate: function(network, rid, mid) {
+    const MAX_PRIORITY = 9999;
     const message = "WifiManager:associate:Return";
     let privnet = network;
     let self = this;
     function networkReady() {
       // saveConfig now before we disable most of the other networks.
-      WifiManager.saveConfig(function() {
+      function selectAndConnect() {
         WifiManager.enableNetwork(privnet.netId, true, function (ok) {
           if (ok)
             self._needToEnableNetworks = true;
           if (WifiManager.state === "DISCONNECTED" ||
               WifiManager.state === "SCANNING") {
             WifiManager.reconnect(function (ok) {
               self._sendMessage(message, ok, ok, rid, mid);
             });
           } else {
             self._sendMessage(message, ok, ok, rid, mid);
           }
         });
-      });
+      }
+
+      if (self._highestPriority >= MAX_PRIORITY)
+        self._reprioritizeNetworks(selectAndConnect);
+      else
+        WifiManager.saveConfig(selectAndConnect);
     }
 
     let ssid = privnet.ssid;
     let configured;
 
     if (ssid in this.configuredNetworks)
       configured = this.configuredNetworks[ssid];
 
     netFromDOM(privnet, configured);
 
-    // XXX Do we have to worry about overflow/going too high here?
     privnet.priority = ++this._highestPriority;
     if (configured) {
       privnet.netId = configured.netId;
       WifiManager.updateNetwork(privnet, (function(ok) {
         if (!ok) {
           this._sendMessage(message, false, "Network is misconfigured", rid, mid);
           return;
         }