/* -*- indent-tabs-mode: nil; js-indent-level: 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"; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/systemlibs.js"); XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService", "@mozilla.org/network/service;1", "nsINetworkService"); this.EXPORTED_SYMBOLS = ["WifiNetUtil"]; const DHCP_PROP = "init.svc.dhcpcd"; const DHCP = "dhcpcd"; const DEBUG = false; this.WifiNetUtil = function(controlMessage) { function debug(msg) { if (DEBUG) { dump('-------------- NetUtil: ' + msg); } } var util = {}; util.runDhcp = function (ifname, gen, callback) { util.stopDhcp(ifname, function() { gNetworkService.dhcpRequest(ifname, function(success, dhcpInfo) { util.runIpConfig(ifname, dhcpInfo, function(data) { callback(data, gen); }); }); }); }; util.stopDhcp = function (ifname, callback) { // This function does exactly what dhcp_stop does. Unforunately, if we call // this function twice before the previous callback is returned. We may block // our self waiting for the callback. It slows down the wifi startup procedure. // Therefore, we have to roll our own version here. let dhcpService = DHCP_PROP + "_" + ifname; let suffix = (ifname.substr(0, 3) === "p2p") ? "p2p" : ifname; let processName = DHCP + "_" + suffix; // The implementation of |dhcp_do_request| would wait until the // |result_prop_name| (e.g. dhcp.wlan0.result) to be non-null // or 30 second timeout. So we manually change the result property // to 'ko' to avoid timeout. // // http://androidxref.com/4.4.4_r1/xref/system/core/libnetutils/dhcp_utils.c#234 setProperty('dhcp.' + suffix + '.result', 'ko', function() { stopProcess(dhcpService, processName, callback); }); }; util.startDhcpServer = function (config, callback) { gNetworkService.setDhcpServer(true, config, function (error) { callback(!error); }); }; util.stopDhcpServer = function (callback) { gNetworkService.setDhcpServer(false, null, function (error) { callback(!error); }); }; util.runIpConfig = function (name, data, callback) { if (!data) { debug("IP config failed to run"); callback({ info: data }); return; } setProperty("net." + name + ".dns1", ipToString(data.dns1), function(ok) { if (!ok) { debug("Unable to set net.<ifname>.dns1"); return; } setProperty("net." + name + ".dns2", ipToString(data.dns2), function(ok) { if (!ok) { debug("Unable to set net.<ifname>.dns2"); return; } setProperty("net." + name + ".gw", ipToString(data.gateway), function(ok) { if (!ok) { debug("Unable to set net.<ifname>.gw"); return; } callback({ info: data }); }); }); }); }; //-------------------------------------------------- // Helper functions. //-------------------------------------------------- function stopProcess(service, process, callback) { var count = 0; var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); function tick() { let result = libcutils.property_get(service); if (result === null) { callback(); return; } if (result === "stopped" || ++count >= 5) { // Either we succeeded or ran out of time. timer = null; callback(); return; } // Else it's still running, continue waiting. timer.initWithCallback(tick, 1000, Ci.nsITimer.TYPE_ONE_SHOT); } setProperty("ctl.stop", process, tick); } // Wrapper around libcutils.property_set that returns true if setting the // value was successful. // Note that the callback is not called asynchronously. function setProperty(key, value, callback) { let ok = true; try { libcutils.property_set(key, value); } catch(e) { ok = false; } callback(ok); } function ipToString(n) { return String((n >> 0) & 0xFF) + "." + ((n >> 8) & 0xFF) + "." + ((n >> 16) & 0xFF) + "." + ((n >> 24) & 0xFF); } return util; };