Bug 738063 - B2G Wifi: Consolidate ctypes-related worker code. r=mrbkap,cjones
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Fri, 30 Mar 2012 12:04:30 -0700
changeset 90745 a54e169714884ffb789be6fc51f5dd8477053795
parent 90744 7fde5b6ebd13e413a244f12b50e9119c55cbd0b7
child 90746 db7260efc9a774c4da1dc4e9df64125049666452
push id22382
push userbmo@edmorley.co.uk
push dateSat, 31 Mar 2012 21:44:34 +0000
treeherdermozilla-central@bbe5086163c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap, cjones
bugs738063
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 738063 - B2G Wifi: Consolidate ctypes-related worker code. r=mrbkap,cjones
dom/system/gonk/net_worker.js
dom/system/gonk/systemlibs.js
dom/wifi/Makefile.in
dom/wifi/WifiWorker.js
dom/wifi/libcutils.js
dom/wifi/network_worker.js
dom/wifi/wifi_worker.js
--- a/dom/system/gonk/net_worker.js
+++ b/dom/system/gonk/net_worker.js
@@ -4,70 +4,26 @@
 
 "use strict";
 
 const DEBUG = true;
 
 importScripts("systemlibs.js");
 
 /**
- * Some reusable data that we pass to C.
- */
-let ints = ctypes.int.array(8)();
-
-/**
- * Convert integer representation of an IP address to the string
- * representation.
- *
- * @param ip
- *        IP address in number format.
- */
-function ipToString(ip) {
-  return ((ip >>  0) & 0xFF) + "." +
-         ((ip >>  8) & 0xFF) + "." +
-         ((ip >> 16) & 0xFF) + "." +
-         ((ip >> 24) & 0xFF);
-}
-
-/**
- * Convert string representation of an IP address to the integer
- * representation.
- *
- * @param string
- *        String containing the IP address.
- */
-function stringToIP(string) {
-  let ip = 0;
-  let start, end = -1;
-  for (let i = 0; i < 4; i++) {
-    start = end + 1;
-    end = string.indexOf(".", start);
-    if (end == -1) {
-      end = string.length;
-    }
-    let num = parseInt(string.slice(start, end), 10);
-    if (isNaN(num)) {
-      return null;
-    }
-    ip |= num << (i * 8);
-  }
-  return ip;
-}
-
-/**
  * Get network interface properties from the system property table.
  *
  * @param ifname
  *        Name of the network interface.
  */
 function getIFProperties(ifname) {
   let gateway_str = libcutils.property_get("net." + ifname + ".gw");
   return {
     ifname:      ifname,
-    gateway:     stringToIP(gateway_str),
+    gateway:     netHelpers.stringToIP(gateway_str),
     gateway_str: gateway_str,
     dns1_str:    libcutils.property_get("net." + ifname + ".dns1"),
     dns2_str:    libcutils.property_get("net." + ifname + ".dns2"),
   };
 }
 
 /**
  * Routines accessible to the main thread.
@@ -100,40 +56,22 @@ function setDefaultRouteAndDNS(options) 
   libcutils.property_set("net.dnschange", (parseInt(dnschange, 10) + 1).toString());
 }
 
 /**
  * Run DHCP and set default route and DNS servers for a given
  * network interface.
  */
 function runDHCPAndSetDefaultRouteAndDNS(options) {
-  let rv = libnetutils.dhcp_do_request(options.ifname,
-                                       ints.addressOfElement(0),
-                                       ints.addressOfElement(1),
-                                       ints.addressOfElement(2),
-                                       ints.addressOfElement(3),
-                                       ints.addressOfElement(4),
-                                       ints.addressOfElement(5),
-                                       ints.addressOfElement(6));
-  let options = {
-    ifname:         options.ifname,
-    ipaddr:         ints[0],
-    mask:           ints[2],
-    gateway:        ints[1],
-    dns1:           ints[3],
-    dns2:           ints[4],
-    dhcpServer:     ints[5],
-    dns1_str:       ipToString(ints[3]),
-    dns2_str:       ipToString(ints[4]),
-    dhcpLease:      ints[6]
-  };
+  let dhcp = libnetutils.dhcp_do_request(options.ifname);
+  dhcp.ifname = options.ifname;
 
   //TODO this could be race-y... by the time we've finished the DHCP request
   // and are now fudging with the routes, another network interface may have
   // come online that's preferred...
-  setDefaultRouteAndDNS(options);
+  setDefaultRouteAndDNS(dhcp);
 }
 
 if (!this.debug) {
   this.debug = function debug(message) {
     dump("Network Worker: " + message + "\n");
   };
 }
--- a/dom/system/gonk/systemlibs.js
+++ b/dom/system/gonk/systemlibs.js
@@ -73,17 +73,16 @@ let libcutils = (function() {
         throw Error('libcutils.property_set("' + key + '", "' + value +
                     '") failed with error ' + rv);
       }
     }
 
   };
 })();
 
-
 /**
  * Network-related functions from libnetutils.
  */
 let libnetutils = (function () {
   let library;
   try {
     library = ctypes.open("libnetutils.so");
   } catch(ex) {
@@ -92,17 +91,17 @@ let libnetutils = (function () {
     // no-op functions when library.declare() is called.
     library = {
       declare: function fake_declare() {
         return function fake_libnetutils_function() {};
       }
     };
   }
 
-  return {
+  let iface = {
     ifc_enable: library.declare("ifc_enable", ctypes.default_abi,
                                 ctypes.int,
                                 ctypes.char.ptr),
     ifc_disable: library.declare("ifc_disable", ctypes.default_abi,
                                  ctypes.int,
                                  ctypes.char.ptr),
     ifc_add_host_route: library.declare("ifc_add_host_route",
                                         ctypes.default_abi,
@@ -133,39 +132,180 @@ let libnetutils = (function () {
     ifc_configure: library.declare("ifc_configure", ctypes.default_abi,
                                    ctypes.int,
                                    ctypes.char.ptr,
                                    ctypes.int,
                                    ctypes.int,
                                    ctypes.int,
                                    ctypes.int,
                                    ctypes.int),
-    dhcp_do_request: library.declare("dhcp_do_request", ctypes.default_abi,
-                                     ctypes.int,
-                                     ctypes.char.ptr,
-                                     ctypes.int.ptr,
-                                     ctypes.int.ptr,
-                                     ctypes.int.ptr,
-                                     ctypes.int.ptr,
-                                     ctypes.int.ptr,
-                                     ctypes.int.ptr,
-                                     ctypes.int.ptr),
     dhcp_stop: library.declare("dhcp_stop", ctypes.default_abi,
                                ctypes.int,
                                ctypes.char.ptr),
     dhcp_release_lease: library.declare("dhcp_release_lease", ctypes.default_abi,
                                         ctypes.int,
                                         ctypes.char.ptr),
     dhcp_get_errmsg: library.declare("dhcp_get_errmsg", ctypes.default_abi,
                                      ctypes.char.ptr),
-    dhcp_do_request_renew: library.declare("dhcp_do_request_renew",
-                                           ctypes.default_abi,
-                                           ctypes.int,
-                                           ctypes.char.ptr,
-                                           ctypes.int.ptr,
-                                           ctypes.int.ptr,
-                                           ctypes.int.ptr,
-                                           ctypes.int.ptr,
-                                           ctypes.int.ptr,
-                                           ctypes.int.ptr,
-                                           ctypes.int.ptr)
   };
+
+  // dhcp_do_request's interface changed in SDK version 15. We try to hide
+  // this here by implementing the same JS API for both versions.
+
+  let sdkVersion = libcutils.property_get("ro.build.version.sdk") || "0";
+  sdkVersion = parseInt(sdkVersion, 10);
+  if (sdkVersion >= 15) {
+    let ipaddrbuf = ctypes.char.array(4096)();
+    let gatewaybuf = ctypes.char.array(4096)();
+    let prefixLen = ctypes.int();
+    let dns1buf = ctypes.char.array(4096)();
+    let dns2buf = ctypes.char.array(4096)();
+    let serverbuf = ctypes.char.array(4096)();
+    let lease = ctypes.int();
+    let c_dhcp_do_request =
+      library.declare("dhcp_do_request", ctypes.default_abi,
+                      ctypes.int,      // return value
+                      ctypes.char.ptr, // ifname
+                      ctypes.char.ptr, // ipaddr
+                      ctypes.char.ptr, // gateway
+                      ctypes.int.ptr,  // prefixlen
+                      ctypes.char.ptr, // dns1
+                      ctypes.char.ptr, // dns2
+                      ctypes.char.ptr, // server
+                      ctypes.int.ptr); // lease
+
+
+    iface.dhcp_do_request = function dhcp_do_request(ifname) {
+      let ret = c_dhcp_do_request(ifname,
+                                  ipaddrbuf,
+                                  gatewaybuf,
+                                  prefixLen.address(),
+                                  dns1buf,
+                                  dns2buf,
+                                  serverbuf,
+                                  lease.address());
+
+      let obj = {
+        ret: ret | 0,
+        ipaddr_str: ipaddrbuf.readString(),
+        mask: netHelpers.makeMask(prefixLen),
+        gateway_str: gatewaybuf.readString(),
+        dns1_str: dns1buf.readString(),
+        dns2_str: dns2buf.readString(),
+        server_str: serverbuf.readString(),
+        lease: lease | 0
+      };
+      obj.ipaddr = netHelpers.stringToIP(obj.ipaddr_str);
+      obj.gateway = netHelpers.stringToIP(obj.gateway_str);
+      obj.dns1 = netHelpers.stringToIP(obj.dns1_str);
+      obj.dns2 = netHelpers.stringToIP(obj.dns2_str);
+      obj.server = netHelpers.stringToIP(obj.server_str);
+      return obj;
+    };
+    // dhcp_do_request_renew() went away in newer libnetutils.
+    iface.dhcp_do_request_renew = iface.dhcp_do_request;
+  } else {
+    let ints = ctypes.int.array(8)();
+    let c_dhcp_do_request =
+      library.declare("dhcp_do_request", ctypes.default_abi,
+                      ctypes.int,      // return value
+                      ctypes.char.ptr, // ifname
+                      ctypes.int.ptr,  // ipaddr
+                      ctypes.int.ptr,  // gateway
+                      ctypes.int.ptr,  // mask
+                      ctypes.int.ptr,  // dns1
+                      ctypes.int.ptr,  // dns2
+                      ctypes.int.ptr,  // server
+                      ctypes.int.ptr); // lease
+    let c_dhcp_do_request_renew =
+      library.declare("dhcp_do_request_renew", ctypes.default_abi,
+                      ctypes.int,      // return value
+                      ctypes.char.ptr, // ifname
+                      ctypes.int.ptr,  // ipaddr
+                      ctypes.int.ptr,  // gateway
+                      ctypes.int.ptr,  // mask
+                      ctypes.int.ptr,  // dns1
+                      ctypes.int.ptr,  // dns2
+                      ctypes.int.ptr,  // server
+                      ctypes.int.ptr); // lease
+
+    let wrapCFunc = function wrapCFunc(c_fn) {
+      return function (ifname) {
+        let ret = c_fn(ifname,
+                       ints.addressOfElement(0),
+                       ints.addressOfElement(1),
+                       ints.addressOfElement(2),
+                       ints.addressOfElement(3),
+                       ints.addressOfElement(4),
+                       ints.addressOfElement(5),
+                       ints.addressOfElement(6));
+        return {ret: ret | 0,
+                ipaddr: ints[0] | 0,
+                gateway: ints[1] | 0,
+                mask: ints[2] | 0,
+                dns1: ints[3] | 0,
+                dns2: ints[4] | 0,
+                server: ints[5] | 0,
+                lease: ints[6] | 0};
+      };
+    };
+    iface.dhcp_do_request = wrapCFunc(c_dhcp_do_request);
+    iface.dhcp_do_request_renew = wrapCFunc(c_dhcp_do_request_renew);
+  }
+
+  return iface;
 })();
+
+/**
+ * Helpers for conversions.
+ */
+let netHelpers = {
+
+  /**
+   * Convert integer representation of an IP address to the string
+   * representation.
+   *
+   * @param ip
+   *        IP address in number format.
+   */
+  ipToString: function ipToString(ip) {
+    return ((ip >>  0) & 0xFF) + "." +
+           ((ip >>  8) & 0xFF) + "." +
+           ((ip >> 16) & 0xFF) + "." +
+           ((ip >> 24) & 0xFF);
+  },
+
+  /**
+   * Convert string representation of an IP address to the integer
+   * representation.
+   *
+   * @param string
+   *        String containing the IP address.
+   */
+  stringToIP: function stringToIP(string) {
+    let ip = 0;
+    let start, end = -1;
+    for (let i = 0; i < 4; i++) {
+      start = end + 1;
+      end = string.indexOf(".", start);
+      if (end == -1) {
+        end = string.length;
+      }
+      let num = parseInt(string.slice(start, end), 10);
+      if (isNaN(num)) {
+        return null;
+      }
+      ip |= num << (i * 8);
+    }
+    return ip;
+  },
+
+  /**
+   * Make a subnet mask.
+   */
+  makeMask: function makeMask(len) {
+    let mask = 0;
+    for (let i = 0; i < len; ++i) {
+      mask |= (1 << i);
+    }
+    return mask;
+  }
+};
--- a/dom/wifi/Makefile.in
+++ b/dom/wifi/Makefile.in
@@ -57,16 +57,14 @@ XPIDLSRCS = \
 EXTRA_COMPONENTS = \
   WifiWorker.js \
   WifiWorker.manifest \
   DOMWifiManager.js \
   DOMWifiManager.manifest \
   $(NULL)
 
 EXTRA_JS_MODULES = \
-  libcutils.js \
   libhardware_legacy.js \
-  libnetutils.js \
-  network_worker.js \
+  wifi_worker.js \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -44,17 +44,17 @@ const {classes: Cc, interfaces: Ci, util
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 const DEBUG = true; // set to false to suppress debug messages
 
 const WIFIWORKER_CONTRACTID = "@mozilla.org/wifi/worker;1";
 const WIFIWORKER_CID        = Components.ID("{a14e8977-d259-433a-a88d-58dd44657e5b}");
 
-const WIFIWORKER_WORKER     = "resource://gre/modules/network_worker.js";
+const WIFIWORKER_WORKER     = "resource://gre/modules/wifi_worker.js";
 
 // A note about errors and error handling in this file:
 // The libraries that we use in this file are intended for C code. For
 // C code, it is natural to return -1 for errors and 0 for success.
 // Therefore, the code that interacts directly with the worker uses this
 // convention (note: command functions do get boolean results since the
 // command always succeeds and we do a string/boolean check for the
 // expected results).
deleted file mode 100644
--- a/dom/wifi/libcutils.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-
-"use strict";
-
-let libcutils = (function () {
-  let library = ctypes.open("libcutils.so");
-
-  return {
-    property_get: library.declare("property_get", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr),
-    property_set: library.declare("property_set", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr)
-  };
-})();
rename from dom/wifi/network_worker.js
rename to dom/wifi/wifi_worker.js
--- a/dom/wifi/network_worker.js
+++ b/dom/wifi/wifi_worker.js
@@ -1,20 +1,33 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-importScripts("libhardware_legacy.js", "libnetutils.js", "libcutils.js");
+importScripts("libhardware_legacy.js", "systemlibs.js");
 
 var cbuf = ctypes.char.array(4096)();
 var hwaddr = ctypes.uint8_t.array(6)();
 var len = ctypes.size_t();
 var ints = ctypes.int.array(8)();
 
+// TODO: consolidate with implementation in systemlibs.js
+let libcutils = (function () {
+  let library = ctypes.open("libcutils.so");
+
+  return {
+    property_get: library.declare("property_get", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr),
+    property_set: library.declare("property_set", ctypes.default_abi, ctypes.int, ctypes.char.ptr, ctypes.char.ptr)
+  };
+})();
+
 self.onmessage = function(e) {
   var data = e.data;
   var id = data.id;
   var cmd = data.cmd;
 
   switch (cmd) {
   case "command":
     len.value = 4096;
@@ -60,20 +73,19 @@ self.onmessage = function(e) {
     break;
   case "dhcp_get_errmsg":
     var error = libnetutils.get_dhcp_get_errmsg();
     postMessage({ id: id, error: error.readString() });
     break;
   case "dhcp_do_request":
   case "dhcp_do_request_renew":
     var out = libnetutils[cmd](data.ifname);
-    postMessage({ id: id, status: out.ret, ipaddr: out.ipaddr,
-                  gateway: out.gateway, mask: out.mask,
-                  dns1: out.dns1, dns2: out.dns2, server: out.server,
-                  lease: out.lease });
+    out.id = id;
+    out.status = out.ret;
+    postMessage(out);
     break;
   case "property_get":
     var ret = libcutils.property_get(data.key, cbuf, data.defaultValue);
     postMessage({ id: id, status: ret, value: cbuf.readString() });
     break;
   case "property_set":
     var ret = libcutils.property_set(data.key, data.value);
     postMessage({ id: id, status: ret });