summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/NetworkService.js
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/system/gonk/NetworkService.js
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/system/gonk/NetworkService.js')
-rw-r--r--dom/system/gonk/NetworkService.js862
1 files changed, 862 insertions, 0 deletions
diff --git a/dom/system/gonk/NetworkService.js b/dom/system/gonk/NetworkService.js
new file mode 100644
index 000000000..7147f40c7
--- /dev/null
+++ b/dom/system/gonk/NetworkService.js
@@ -0,0 +1,862 @@
+/* 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/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1";
+const NETWORKSERVICE_CID = Components.ID("{48c13741-aec9-4a86-8962-432011708261}");
+
+const TOPIC_PREF_CHANGED = "nsPref:changed";
+const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
+const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled";
+
+XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker",
+ "@mozilla.org/network/worker;1",
+ "nsINetworkWorker");
+
+// 1xx - Requested action is proceeding
+const NETD_COMMAND_PROCEEDING = 100;
+// 2xx - Requested action has been successfully completed
+const NETD_COMMAND_OKAY = 200;
+// 4xx - The command is accepted but the requested action didn't
+// take place.
+const NETD_COMMAND_FAIL = 400;
+// 5xx - The command syntax or parameters error
+const NETD_COMMAND_ERROR = 500;
+// 6xx - Unsolicited broadcasts
+const NETD_COMMAND_UNSOLICITED = 600;
+
+const WIFI_CTRL_INTERFACE = "wl0.1";
+
+var debug;
+function updateDebug() {
+ let debugPref = false; // set default value here.
+ try {
+ debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED);
+ } catch (e) {}
+
+ if (debugPref) {
+ debug = function(s) {
+ dump("-*- NetworkService: " + s + "\n");
+ };
+ } else {
+ debug = function(s) {};
+ }
+}
+updateDebug();
+
+function netdResponseType(aCode) {
+ return Math.floor(aCode / 100) * 100;
+}
+
+function isError(aCode) {
+ let type = netdResponseType(aCode);
+ return (type !== NETD_COMMAND_PROCEEDING && type !== NETD_COMMAND_OKAY);
+}
+
+function Task(aId, aParams, aSetupFunction) {
+ this.id = aId;
+ this.params = aParams;
+ this.setupFunction = aSetupFunction;
+}
+
+function NetworkWorkerRequestQueue(aNetworkService) {
+ this.networkService = aNetworkService;
+ this.tasks = [];
+}
+NetworkWorkerRequestQueue.prototype = {
+ runQueue: function() {
+ if (this.tasks.length === 0) {
+ return;
+ }
+
+ let task = this.tasks[0];
+ debug("run task id: " + task.id);
+
+ if (typeof task.setupFunction === 'function') {
+ // If setupFunction returns false, skip sending to Network Worker but call
+ // handleWorkerMessage() directly with task id, as if the response was
+ // returned from Network Worker.
+ if (!task.setupFunction()) {
+ this.networkService.handleWorkerMessage({id: task.id});
+ return;
+ }
+ }
+
+ gNetworkWorker.postMessage(task.params);
+ },
+
+ enqueue: function(aId, aParams, aSetupFunction) {
+ debug("enqueue id: " + aId);
+ this.tasks.push(new Task(aId, aParams, aSetupFunction));
+
+ if (this.tasks.length === 1) {
+ this.runQueue();
+ }
+ },
+
+ dequeue: function(aId) {
+ debug("dequeue id: " + aId);
+
+ if (!this.tasks.length || this.tasks[0].id != aId) {
+ debug("Id " + aId + " is not on top of the queue");
+ return;
+ }
+
+ this.tasks.shift();
+ if (this.tasks.length > 0) {
+ // Run queue on the next tick.
+ Services.tm.currentThread.dispatch(() => {
+ this.runQueue();
+ }, Ci.nsIThread.DISPATCH_NORMAL);
+ }
+ }
+};
+
+
+/**
+ * This component watches for network interfaces changing state and then
+ * adjusts routes etc. accordingly.
+ */
+function NetworkService() {
+ debug("Starting NetworkService.");
+
+ let self = this;
+
+ if (gNetworkWorker) {
+ let networkListener = {
+ onEvent: function(aEvent) {
+ self.handleWorkerMessage(aEvent);
+ }
+ };
+ gNetworkWorker.start(networkListener);
+ }
+ // Callbacks to invoke when a reply arrives from the net_worker.
+ this.controlCallbacks = Object.create(null);
+
+ this.addedRoutes = new Map();
+ this.netWorkerRequestQueue = new NetworkWorkerRequestQueue(this);
+ this.shutdown = false;
+
+ Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false);
+ Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
+}
+
+NetworkService.prototype = {
+ classID: NETWORKSERVICE_CID,
+ classInfo: XPCOMUtils.generateCI({classID: NETWORKSERVICE_CID,
+ contractID: NETWORKSERVICE_CONTRACTID,
+ classDescription: "Network Service",
+ interfaces: [Ci.nsINetworkService]}),
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkService,
+ Ci.nsIObserver]),
+
+ addedRoutes: null,
+
+ shutdown: false,
+
+ // nsIObserver
+
+ observe: function(aSubject, aTopic, aData) {
+ switch (aTopic) {
+ case TOPIC_PREF_CHANGED:
+ if (aData === PREF_NETWORK_DEBUG_ENABLED) {
+ updateDebug();
+ }
+ break;
+ case TOPIC_XPCOM_SHUTDOWN:
+ debug("NetworkService shutdown");
+ this.shutdown = true;
+ if (gNetworkWorker) {
+ gNetworkWorker.shutdown();
+ gNetworkWorker = null;
+ }
+
+ Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
+ Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this);
+ break;
+ }
+ },
+
+ // Helpers
+
+ idgen: 0,
+ controlMessage: function(aParams, aCallback, aSetupFunction) {
+ if (this.shutdown) {
+ return;
+ }
+
+ let id = this.idgen++;
+ aParams.id = id;
+ if (aCallback) {
+ this.controlCallbacks[id] = aCallback;
+ }
+
+ // For now, we use aSetupFunction to determine if this command needs to be
+ // queued or not.
+ if (aSetupFunction) {
+ this.netWorkerRequestQueue.enqueue(id, aParams, aSetupFunction);
+ return;
+ }
+
+ if (gNetworkWorker) {
+ gNetworkWorker.postMessage(aParams);
+ }
+ },
+
+ handleWorkerMessage: function(aResponse) {
+ debug("NetworkManager received message from worker: " + JSON.stringify(aResponse));
+ let id = aResponse.id;
+ if (aResponse.broadcast === true) {
+ Services.obs.notifyObservers(null, aResponse.topic, aResponse.reason);
+ return;
+ }
+ let callback = this.controlCallbacks[id];
+ if (callback) {
+ callback.call(this, aResponse);
+ delete this.controlCallbacks[id];
+ }
+
+ this.netWorkerRequestQueue.dequeue(id);
+ },
+
+ // nsINetworkService
+
+ getNetworkInterfaceStats: function(aInterfaceName, aCallback) {
+ debug("getNetworkInterfaceStats for " + aInterfaceName);
+
+ let file = new FileUtils.File("/proc/net/dev");
+ if (!file) {
+ aCallback.networkStatsAvailable(false, 0, 0, Date.now());
+ return;
+ }
+
+ NetUtil.asyncFetch({
+ uri: NetUtil.newURI(file),
+ loadUsingSystemPrincipal: true
+ }, function(inputStream, status) {
+ let rxBytes = 0,
+ txBytes = 0,
+ now = Date.now();
+
+ if (Components.isSuccessCode(status)) {
+ // Find record for corresponding interface.
+ let statExpr = /(\S+): +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+/;
+ let data =
+ NetUtil.readInputStreamToString(inputStream, inputStream.available())
+ .split("\n");
+ for (let i = 2; i < data.length; i++) {
+ let parseResult = statExpr.exec(data[i]);
+ if (parseResult && parseResult[1] === aInterfaceName) {
+ rxBytes = parseInt(parseResult[2], 10);
+ txBytes = parseInt(parseResult[3], 10);
+ break;
+ }
+ }
+ }
+
+ // netd always return success even interface doesn't exist.
+ aCallback.networkStatsAvailable(true, rxBytes, txBytes, now);
+ });
+ },
+
+ setNetworkTetheringAlarm(aEnable, aInterface) {
+ // Method called when enabling disabling tethering, it checks if there is
+ // some alarm active and move from interfaceAlarm to globalAlarm because
+ // interfaceAlarm doens't work in tethering scenario due to forwarding.
+ debug("setNetworkTetheringAlarm for tethering" + aEnable);
+
+ let filename = aEnable ? "/proc/net/xt_quota/" + aInterface + "Alert" :
+ "/proc/net/xt_quota/globalAlert";
+
+ let file = new FileUtils.File(filename);
+ if (!file) {
+ return;
+ }
+
+ NetUtil.asyncFetch({
+ uri: NetUtil.newURI(file),
+ loadUsingSystemPrincipal: true
+ }, (inputStream, status) => {
+ if (Components.isSuccessCode(status)) {
+ let data = NetUtil.readInputStreamToString(inputStream, inputStream.available())
+ .split("\n");
+ if (data) {
+ let threshold = parseInt(data[0], 10);
+
+ this._setNetworkTetheringAlarm(aEnable, aInterface, threshold);
+ }
+ }
+ });
+ },
+
+ _setNetworkTetheringAlarm(aEnable, aInterface, aThreshold, aCallback) {
+ debug("_setNetworkTetheringAlarm for tethering" + aEnable);
+
+ let cmd = aEnable ? "setTetheringAlarm" : "removeTetheringAlarm";
+
+ let params = {
+ cmd: cmd,
+ ifname: aInterface,
+ threshold: aThreshold,
+ };
+
+ this.controlMessage(params, function(aData) {
+ let code = aData.resultCode;
+ let reason = aData.resultReason;
+ let enableString = aEnable ? "Enable" : "Disable";
+ debug(enableString + " tethering Alarm result: Code " + code + " reason " + reason);
+ if (aCallback) {
+ aCallback.networkUsageAlarmResult(null);
+ }
+ });
+ },
+
+ setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) {
+ if (!aInterfaceName) {
+ aCallback.networkUsageAlarmResult(-1);
+ return;
+ }
+
+ let self = this;
+ this._disableNetworkInterfaceAlarm(aInterfaceName, function(aResult) {
+ if (aThreshold < 0) {
+ if (!isError(aResult.resultCode)) {
+ aCallback.networkUsageAlarmResult(null);
+ return;
+ }
+ aCallback.networkUsageAlarmResult(aResult.reason);
+ return
+ }
+
+ // Check if tethering is enabled
+ let params = {
+ cmd: "getTetheringStatus"
+ };
+
+ self.controlMessage(params, function(aResult) {
+ if (isError(aResult.resultCode)) {
+ aCallback.networkUsageAlarmResult(aResult.reason);
+ return;
+ }
+
+ if (aResult.resultReason.indexOf('started') == -1) {
+ // Tethering disabled, set interfaceAlarm
+ self._setNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback);
+ return;
+ }
+
+ // Tethering enabled, set globalAlarm
+ self._setNetworkTetheringAlarm(true, aInterfaceName, aThreshold, aCallback);
+ });
+ });
+ },
+
+ _setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) {
+ debug("setNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes");
+
+ let params = {
+ cmd: "setNetworkInterfaceAlarm",
+ ifname: aInterfaceName,
+ threshold: aThreshold
+ };
+
+ params.report = true;
+
+ this.controlMessage(params, function(aResult) {
+ if (!isError(aResult.resultCode)) {
+ aCallback.networkUsageAlarmResult(null);
+ return;
+ }
+
+ this._enableNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback);
+ });
+ },
+
+ _enableNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) {
+ debug("enableNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes");
+
+ let params = {
+ cmd: "enableNetworkInterfaceAlarm",
+ ifname: aInterfaceName,
+ threshold: aThreshold
+ };
+
+ params.report = true;
+
+ this.controlMessage(params, function(aResult) {
+ if (!isError(aResult.resultCode)) {
+ aCallback.networkUsageAlarmResult(null);
+ return;
+ }
+ aCallback.networkUsageAlarmResult(aResult.reason);
+ });
+ },
+
+ _disableNetworkInterfaceAlarm: function(aInterfaceName, aCallback) {
+ debug("disableNetworkInterfaceAlarm for " + aInterfaceName);
+
+ let params = {
+ cmd: "disableNetworkInterfaceAlarm",
+ ifname: aInterfaceName,
+ };
+
+ params.report = true;
+
+ this.controlMessage(params, function(aResult) {
+ aCallback(aResult);
+ });
+ },
+
+ setWifiOperationMode: function(aInterfaceName, aMode, aCallback) {
+ debug("setWifiOperationMode on " + aInterfaceName + " to " + aMode);
+
+ let params = {
+ cmd: "setWifiOperationMode",
+ ifname: aInterfaceName,
+ mode: aMode
+ };
+
+ params.report = true;
+
+ this.controlMessage(params, function(aResult) {
+ if (isError(aResult.resultCode)) {
+ aCallback.wifiOperationModeResult("netd command error");
+ } else {
+ aCallback.wifiOperationModeResult(null);
+ }
+ });
+ },
+
+ resetRoutingTable: function(aInterfaceName, aCallback) {
+ let options = {
+ cmd: "removeNetworkRoute",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(options, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ setDNS: function(aInterfaceName, aDnsesCount, aDnses, aGatewaysCount,
+ aGateways, aCallback) {
+ debug("Going to set DNS to " + aInterfaceName);
+ let options = {
+ cmd: "setDNS",
+ ifname: aInterfaceName,
+ domain: "mozilla." + aInterfaceName + ".domain",
+ dnses: aDnses,
+ gateways: aGateways
+ };
+ this.controlMessage(options, function(aResult) {
+ aCallback.setDnsResult(aResult.success ? null : aResult.reason);
+ });
+ },
+
+ setDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) {
+ debug("Going to change default route to " + aInterfaceName);
+ let options = {
+ cmd: "setDefaultRoute",
+ ifname: aInterfaceName,
+ gateways: aGateways
+ };
+ this.controlMessage(options, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ removeDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) {
+ debug("Remove default route for " + aInterfaceName);
+ let options = {
+ cmd: "removeDefaultRoute",
+ ifname: aInterfaceName,
+ gateways: aGateways
+ };
+ this.controlMessage(options, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ _routeToString: function(aInterfaceName, aHost, aPrefixLength, aGateway) {
+ return aHost + "-" + aPrefixLength + "-" + aGateway + "-" + aInterfaceName;
+ },
+
+ modifyRoute: function(aAction, aInterfaceName, aHost, aPrefixLength, aGateway) {
+ let command;
+
+ switch (aAction) {
+ case Ci.nsINetworkService.MODIFY_ROUTE_ADD:
+ command = 'addHostRoute';
+ break;
+ case Ci.nsINetworkService.MODIFY_ROUTE_REMOVE:
+ command = 'removeHostRoute';
+ break;
+ default:
+ debug('Unknown action: ' + aAction);
+ return Promise.reject();
+ }
+
+ let route = this._routeToString(aInterfaceName, aHost, aPrefixLength, aGateway);
+ let setupFunc = () => {
+ let count = this.addedRoutes.get(route);
+ debug(command + ": " + route + " -> " + count);
+
+ // Return false if there is no need to send the command to network worker.
+ if ((aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD && count) ||
+ (aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE &&
+ (!count || count > 1))) {
+ return false;
+ }
+
+ return true;
+ };
+
+ debug(command + " " + aHost + " on " + aInterfaceName);
+ let options = {
+ cmd: command,
+ ifname: aInterfaceName,
+ gateway: aGateway,
+ prefixLength: aPrefixLength,
+ ip: aHost
+ };
+
+ return new Promise((aResolve, aReject) => {
+ this.controlMessage(options, (aData) => {
+ let count = this.addedRoutes.get(route);
+
+ // Remove route from addedRoutes on success or failure.
+ if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE) {
+ if (count > 1) {
+ this.addedRoutes.set(route, count - 1);
+ } else {
+ this.addedRoutes.delete(route);
+ }
+ }
+
+ if (aData.error) {
+ aReject(aData.reason);
+ return;
+ }
+
+ if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD) {
+ this.addedRoutes.set(route, count ? count + 1 : 1);
+ }
+
+ aResolve();
+ }, setupFunc);
+ });
+ },
+
+ addSecondaryRoute: function(aInterfaceName, aRoute, aCallback) {
+ debug("Going to add route to secondary table on " + aInterfaceName);
+ let options = {
+ cmd: "addSecondaryRoute",
+ ifname: aInterfaceName,
+ ip: aRoute.ip,
+ prefix: aRoute.prefix,
+ gateway: aRoute.gateway
+ };
+ this.controlMessage(options, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ removeSecondaryRoute: function(aInterfaceName, aRoute, aCallback) {
+ debug("Going to remove route from secondary table on " + aInterfaceName);
+ let options = {
+ cmd: "removeSecondaryRoute",
+ ifname: aInterfaceName,
+ ip: aRoute.ip,
+ prefix: aRoute.prefix,
+ gateway: aRoute.gateway
+ };
+ this.controlMessage(options, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ // Enable/Disable DHCP server.
+ setDhcpServer: function(aEnabled, aConfig, aCallback) {
+ if (null === aConfig) {
+ aConfig = {};
+ }
+
+ aConfig.cmd = "setDhcpServer";
+ aConfig.enabled = aEnabled;
+
+ this.controlMessage(aConfig, function(aResponse) {
+ if (!aResponse.success) {
+ aCallback.dhcpServerResult('Set DHCP server error');
+ return;
+ }
+ aCallback.dhcpServerResult(null);
+ });
+ },
+
+ // Enable/disable WiFi tethering by sending commands to netd.
+ setWifiTethering: function(aEnable, aConfig, aCallback) {
+ // config should've already contained:
+ // .ifname
+ // .internalIfname
+ // .externalIfname
+ aConfig.wifictrlinterfacename = WIFI_CTRL_INTERFACE;
+ aConfig.cmd = "setWifiTethering";
+
+ // The callback function in controlMessage may not be fired immediately.
+ this.controlMessage(aConfig, (aData) => {
+ let code = aData.resultCode;
+ let reason = aData.resultReason;
+ let enable = aData.enable;
+ let enableString = aEnable ? "Enable" : "Disable";
+
+ debug(enableString + " Wifi tethering result: Code " + code + " reason " + reason);
+
+ this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname);
+
+ if (isError(code)) {
+ aCallback.wifiTetheringEnabledChange("netd command error");
+ } else {
+ aCallback.wifiTetheringEnabledChange(null);
+ }
+ });
+ },
+
+ // Enable/disable USB tethering by sending commands to netd.
+ setUSBTethering: function(aEnable, aConfig, aCallback) {
+ aConfig.cmd = "setUSBTethering";
+ // The callback function in controlMessage may not be fired immediately.
+ this.controlMessage(aConfig, (aData) => {
+ let code = aData.resultCode;
+ let reason = aData.resultReason;
+ let enable = aData.enable;
+ let enableString = aEnable ? "Enable" : "Disable";
+
+ debug(enableString + " USB tethering result: Code " + code + " reason " + reason);
+
+ this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname);
+
+ if (isError(code)) {
+ aCallback.usbTetheringEnabledChange("netd command error");
+ } else {
+ aCallback.usbTetheringEnabledChange(null);
+ }
+ });
+ },
+
+ // Switch usb function by modifying property of persist.sys.usb.config.
+ enableUsbRndis: function(aEnable, aCallback) {
+ debug("enableUsbRndis: " + aEnable);
+
+ let params = {
+ cmd: "enableUsbRndis",
+ enable: aEnable
+ };
+ // Ask net work to report the result when this value is set to true.
+ if (aCallback) {
+ params.report = true;
+ } else {
+ params.report = false;
+ }
+
+ // The callback function in controlMessage may not be fired immediately.
+ //this._usbTetheringAction = TETHERING_STATE_ONGOING;
+ this.controlMessage(params, function(aData) {
+ aCallback.enableUsbRndisResult(aData.result, aData.enable);
+ });
+ },
+
+ updateUpStream: function(aPrevious, aCurrent, aCallback) {
+ let params = {
+ cmd: "updateUpStream",
+ preInternalIfname: aPrevious.internalIfname,
+ preExternalIfname: aPrevious.externalIfname,
+ curInternalIfname: aCurrent.internalIfname,
+ curExternalIfname: aCurrent.externalIfname
+ };
+
+ this.controlMessage(params, function(aData) {
+ let code = aData.resultCode;
+ let reason = aData.resultReason;
+ debug("updateUpStream result: Code " + code + " reason " + reason);
+ aCallback.updateUpStreamResult(!isError(code), aData.curExternalIfname);
+ });
+ },
+
+ getInterfaces: function(callback) {
+ let params = {
+ cmd: "getInterfaces",
+ isAsync: true
+ };
+
+ this.controlMessage(params, function(data) {
+ debug("getInterfaces result: " + JSON.stringify(data));
+ let success = !isError(data.resultCode);
+ callback.getInterfacesResult(success, data.interfaceList);
+ });
+ },
+
+ getInterfaceConfig: function(ifname, callback) {
+ let params = {
+ cmd: "getInterfaceConfig",
+ ifname: ifname,
+ isAsync: true
+ };
+
+ this.controlMessage(params, function(data) {
+ debug("getInterfaceConfig result: " + JSON.stringify(data));
+ let success = !isError(data.resultCode);
+ let result = { ip: data.ipAddr,
+ prefix: data.prefixLength,
+ link: data.flag,
+ mac: data.macAddr };
+ callback.getInterfaceConfigResult(success, result);
+ });
+ },
+
+ setInterfaceConfig: function(config, callback) {
+ config.cmd = "setInterfaceConfig";
+ config.isAsync = true;
+
+ this.controlMessage(config, function(data) {
+ debug("setInterfaceConfig result: " + JSON.stringify(data));
+ let success = !isError(data.resultCode);
+ callback.setInterfaceConfigResult(success);
+ });
+ },
+
+ configureInterface: function(aConfig, aCallback) {
+ let params = {
+ cmd: "configureInterface",
+ ifname: aConfig.ifname,
+ ipaddr: aConfig.ipaddr,
+ mask: aConfig.mask,
+ gateway_long: aConfig.gateway,
+ dns1_long: aConfig.dns1,
+ dns2_long: aConfig.dns2,
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ dhcpRequest: function(aInterfaceName, aCallback) {
+ let params = {
+ cmd: "dhcpRequest",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.dhcpRequestResult(!aResult.error, aResult.error ? null : aResult);
+ });
+ },
+
+ stopDhcp: function(aInterfaceName, aCallback) {
+ let params = {
+ cmd: "stopDhcp",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ enableInterface: function(aInterfaceName, aCallback) {
+ let params = {
+ cmd: "enableInterface",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ disableInterface: function(aInterfaceName, aCallback) {
+ let params = {
+ cmd: "disableInterface",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ resetConnections: function(aInterfaceName, aCallback) {
+ let params = {
+ cmd: "resetConnections",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ createNetwork: function(aInterfaceName, aCallback) {
+ let params = {
+ cmd: "createNetwork",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ destroyNetwork: function(aInterfaceName, aCallback) {
+ let params = {
+ cmd: "destroyNetwork",
+ ifname: aInterfaceName
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ },
+
+ getNetId: function(aInterfaceName) {
+ let params = {
+ cmd: "getNetId",
+ ifname: aInterfaceName
+ };
+
+ return new Promise((aResolve, aReject) => {
+ this.controlMessage(params, result => {
+ if (result.error) {
+ aReject(result.reason);
+ return;
+ }
+ aResolve(result.netId);
+ });
+ });
+ },
+
+ setMtu: function (aInterfaceName, aMtu, aCallback) {
+ debug("Set MTU on " + aInterfaceName + ": " + aMtu);
+
+ let params = {
+ cmd: "setMtu",
+ ifname: aInterfaceName,
+ mtu: aMtu
+ };
+
+ this.controlMessage(params, function(aResult) {
+ aCallback.nativeCommandResult(!aResult.error);
+ });
+ }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkService]);