summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/NetworkManager.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/gonk/NetworkManager.js')
-rw-r--r--dom/system/gonk/NetworkManager.js1219
1 files changed, 0 insertions, 1219 deletions
diff --git a/dom/system/gonk/NetworkManager.js b/dom/system/gonk/NetworkManager.js
deleted file mode 100644
index 9d7a5683e..000000000
--- a/dom/system/gonk/NetworkManager.js
+++ /dev/null
@@ -1,1219 +0,0 @@
-/* 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/FileUtils.jsm");
-Cu.import("resource://gre/modules/systemlibs.js");
-Cu.import("resource://gre/modules/Promise.jsm");
-
-const NETWORKMANAGER_CONTRACTID = "@mozilla.org/network/manager;1";
-const NETWORKMANAGER_CID =
- Components.ID("{1ba9346b-53b5-4660-9dc6-58f0b258d0a6}");
-
-const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET;
-
-XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
- return Cc["@mozilla.org/parentprocessmessagemanager;1"]
- .getService(Ci.nsIMessageBroadcaster);
-});
-
-XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
- "@mozilla.org/network/dns-service;1",
- "nsIDNSService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
- "@mozilla.org/network/service;1",
- "nsINetworkService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gTetheringService",
- "@mozilla.org/tethering/service;1",
- "nsITetheringService");
-
-const TOPIC_INTERFACE_REGISTERED = "network-interface-registered";
-const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered";
-const TOPIC_ACTIVE_CHANGED = "network-active-changed";
-const TOPIC_PREF_CHANGED = "nsPref:changed";
-const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown";
-const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed";
-const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status";
-const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled";
-
-const IPV4_ADDRESS_ANY = "0.0.0.0";
-const IPV6_ADDRESS_ANY = "::0";
-
-const IPV4_MAX_PREFIX_LENGTH = 32;
-const IPV6_MAX_PREFIX_LENGTH = 128;
-
-// Connection Type for Network Information API
-const CONNECTION_TYPE_CELLULAR = 0;
-const CONNECTION_TYPE_BLUETOOTH = 1;
-const CONNECTION_TYPE_ETHERNET = 2;
-const CONNECTION_TYPE_WIFI = 3;
-const CONNECTION_TYPE_OTHER = 4;
-const CONNECTION_TYPE_NONE = 5;
-
-const MANUAL_PROXY_CONFIGURATION = 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("-*- NetworkManager: " + s + "\n");
- };
- } else {
- debug = function(s) {};
- }
-}
-updateDebug();
-
-function defineLazyRegExp(obj, name, pattern) {
- obj.__defineGetter__(name, function() {
- delete obj[name];
- return obj[name] = new RegExp(pattern);
- });
-}
-
-function ExtraNetworkInfo(aNetwork) {
- let ips = {};
- let prefixLengths = {};
- aNetwork.info.getAddresses(ips, prefixLengths);
-
- this.state = aNetwork.info.state;
- this.type = aNetwork.info.type;
- this.name = aNetwork.info.name;
- this.ips = ips.value;
- this.prefixLengths = prefixLengths.value;
- this.gateways = aNetwork.info.getGateways();
- this.dnses = aNetwork.info.getDnses();
- this.httpProxyHost = aNetwork.httpProxyHost;
- this.httpProxyPort = aNetwork.httpProxyPort;
- this.mtu = aNetwork.mtu;
-}
-ExtraNetworkInfo.prototype = {
- getAddresses: function(aIps, aPrefixLengths) {
- aIps.value = this.ips.slice();
- aPrefixLengths.value = this.prefixLengths.slice();
-
- return this.ips.length;
- },
-
- getGateways: function(aCount) {
- if (aCount) {
- aCount.value = this.gateways.length;
- }
-
- return this.gateways.slice();
- },
-
- getDnses: function(aCount) {
- if (aCount) {
- aCount.value = this.dnses.length;
- }
-
- return this.dnses.slice();
- }
-};
-
-function NetworkInterfaceLinks()
-{
- this.resetLinks();
-}
-NetworkInterfaceLinks.prototype = {
- linkRoutes: null,
- gateways: null,
- interfaceName: null,
- extraRoutes: null,
-
- setLinks: function(linkRoutes, gateways, interfaceName) {
- this.linkRoutes = linkRoutes;
- this.gateways = gateways;
- this.interfaceName = interfaceName;
- },
-
- resetLinks: function() {
- this.linkRoutes = [];
- this.gateways = [];
- this.interfaceName = "";
- this.extraRoutes = [];
- },
-
- compareGateways: function(gateways) {
- if (this.gateways.length != gateways.length) {
- return false;
- }
-
- for (let i = 0; i < this.gateways.length; i++) {
- if (this.gateways[i] != gateways[i]) {
- return false;
- }
- }
-
- return true;
- }
-};
-
-/**
- * This component watches for network interfaces changing state and then
- * adjusts routes etc. accordingly.
- */
-function NetworkManager() {
- this.networkInterfaces = {};
- this.networkInterfaceLinks = {};
-
- try {
- this._manageOfflineStatus =
- Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
- } catch(ex) {
- // Ignore.
- }
- Services.prefs.addObserver(PREF_MANAGE_OFFLINE_STATUS, this, false);
- Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false);
- Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
-
- this.setAndConfigureActive();
-
- ppmm.addMessageListener('NetworkInterfaceList:ListInterface', this);
-
- // Used in resolveHostname().
- defineLazyRegExp(this, "REGEXP_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$");
- defineLazyRegExp(this, "REGEXP_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$");
-}
-NetworkManager.prototype = {
- classID: NETWORKMANAGER_CID,
- classInfo: XPCOMUtils.generateCI({classID: NETWORKMANAGER_CID,
- contractID: NETWORKMANAGER_CONTRACTID,
- classDescription: "Network Manager",
- interfaces: [Ci.nsINetworkManager]}),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkManager,
- Ci.nsISupportsWeakReference,
- Ci.nsIObserver,
- Ci.nsISettingsServiceCallback]),
-
- // nsIObserver
-
- observe: function(subject, topic, data) {
- switch (topic) {
- case TOPIC_PREF_CHANGED:
- if (data === PREF_NETWORK_DEBUG_ENABLED) {
- updateDebug();
- } else if (data === PREF_MANAGE_OFFLINE_STATUS) {
- this._manageOfflineStatus =
- Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS);
- debug(PREF_MANAGE_OFFLINE_STATUS + " has changed to " + this._manageOfflineStatus);
- }
- break;
- case TOPIC_XPCOM_SHUTDOWN:
- Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
- Services.prefs.removeObserver(PREF_MANAGE_OFFLINE_STATUS, this);
- Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this);
- break;
- }
- },
-
- receiveMessage: function(aMsg) {
- switch (aMsg.name) {
- case "NetworkInterfaceList:ListInterface": {
- let excludeMms = aMsg.json.excludeMms;
- let excludeSupl = aMsg.json.excludeSupl;
- let excludeIms = aMsg.json.excludeIms;
- let excludeDun = aMsg.json.excludeDun;
- let excludeFota = aMsg.json.excludeFota;
- let interfaces = [];
-
- for (let key in this.networkInterfaces) {
- let network = this.networkInterfaces[key];
- let i = network.info;
- if ((i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS && excludeMms) ||
- (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL && excludeSupl) ||
- (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS && excludeIms) ||
- (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN && excludeDun) ||
- (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA && excludeFota)) {
- continue;
- }
-
- let ips = {};
- let prefixLengths = {};
- i.getAddresses(ips, prefixLengths);
-
- interfaces.push({
- state: i.state,
- type: i.type,
- name: i.name,
- ips: ips.value,
- prefixLengths: prefixLengths.value,
- gateways: i.getGateways(),
- dnses: i.getDnses()
- });
- }
- return interfaces;
- }
- }
- },
-
- getNetworkId: function(aNetworkInfo) {
- let id = "device";
- try {
- if (aNetworkInfo instanceof Ci.nsIRilNetworkInfo) {
- let rilInfo = aNetworkInfo.QueryInterface(Ci.nsIRilNetworkInfo);
- id = "ril" + rilInfo.serviceId;
- }
- } catch (e) {}
-
- return id + "-" + aNetworkInfo.type;
- },
-
- // nsINetworkManager
-
- registerNetworkInterface: function(network) {
- if (!(network instanceof Ci.nsINetworkInterface)) {
- throw Components.Exception("Argument must be nsINetworkInterface.",
- Cr.NS_ERROR_INVALID_ARG);
- }
- let networkId = this.getNetworkId(network.info);
- if (networkId in this.networkInterfaces) {
- throw Components.Exception("Network with that type already registered!",
- Cr.NS_ERROR_INVALID_ARG);
- }
- this.networkInterfaces[networkId] = network;
- this.networkInterfaceLinks[networkId] = new NetworkInterfaceLinks();
-
- Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_REGISTERED, null);
- debug("Network '" + networkId + "' registered.");
- },
-
- _addSubnetRoutes: function(network) {
- let ips = {};
- let prefixLengths = {};
- let length = network.getAddresses(ips, prefixLengths);
- let promises = [];
-
- for (let i = 0; i < length; i++) {
- debug('Adding subnet routes: ' + ips.value[i] + '/' + prefixLengths.value[i]);
- promises.push(
- gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD,
- network.name, ips.value[i], prefixLengths.value[i])
- .catch(aError => {
- debug("_addSubnetRoutes error: " + aError);
- }));
- }
-
- return Promise.all(promises);
- },
-
- updateNetworkInterface: function(network) {
- if (!(network instanceof Ci.nsINetworkInterface)) {
- throw Components.Exception("Argument must be nsINetworkInterface.",
- Cr.NS_ERROR_INVALID_ARG);
- }
- let networkId = this.getNetworkId(network.info);
- if (!(networkId in this.networkInterfaces)) {
- throw Components.Exception("No network with that type registered.",
- Cr.NS_ERROR_INVALID_ARG);
- }
- debug("Network " + network.info.type + "/" + network.info.name +
- " changed state to " + network.info.state);
-
- // Keep a copy of network in case it is modified while we are updating.
- let extNetworkInfo = new ExtraNetworkInfo(network);
-
- // Note that since Lollipop we need to allocate and initialize
- // something through netd, so we add createNetwork/destroyNetwork
- // to deal with that explicitly.
-
- switch (extNetworkInfo.state) {
- case Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED:
-
- this._createNetwork(extNetworkInfo.name)
- // Remove pre-created default route and let setAndConfigureActive()
- // to set default route only on preferred network
- .then(() => this._removeDefaultRoute(extNetworkInfo))
- // Set DNS server as early as possible to prevent from
- // premature domain name lookup.
- .then(() => this._setDNS(extNetworkInfo))
- .then(() => {
- // Add host route for data calls
- if (!this.isNetworkTypeMobile(extNetworkInfo.type)) {
- return;
- }
-
- let currentInterfaceLinks = this.networkInterfaceLinks[networkId];
- let newLinkRoutes = extNetworkInfo.getDnses().concat(
- extNetworkInfo.httpProxyHost);
- // If gateways have changed, remove all old routes first.
- return this._handleGateways(networkId, extNetworkInfo.getGateways())
- .then(() => this._updateRoutes(currentInterfaceLinks.linkRoutes,
- newLinkRoutes,
- extNetworkInfo.getGateways(),
- extNetworkInfo.name))
- .then(() => currentInterfaceLinks.setLinks(newLinkRoutes,
- extNetworkInfo.getGateways(),
- extNetworkInfo.name));
- })
- .then(() => {
- if (extNetworkInfo.type !=
- Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) {
- return;
- }
- // Dun type is a special case where we add the default route to a
- // secondary table.
- return this.setSecondaryDefaultRoute(extNetworkInfo);
- })
- .then(() => this._addSubnetRoutes(extNetworkInfo))
- .then(() => {
- if (extNetworkInfo.mtu <= 0) {
- return;
- }
-
- return this._setMtu(extNetworkInfo);
- })
- .then(() => this.setAndConfigureActive())
- .then(() => {
- // Update data connection when Wifi connected/disconnected
- if (extNetworkInfo.type ==
- Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && this.mRil) {
- for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
- this.mRil.getRadioInterface(i).updateRILNetworkInterface();
- }
- }
-
- // Probing the public network accessibility after routing table is ready
- CaptivePortalDetectionHelper
- .notify(CaptivePortalDetectionHelper.EVENT_CONNECT,
- this.activeNetworkInfo);
- })
- .then(() => {
- // Notify outer modules like MmsService to start the transaction after
- // the configuration of the network interface is done.
- Services.obs.notifyObservers(network.info,
- TOPIC_CONNECTION_STATE_CHANGED,
- this.convertConnectionType(network.info));
- })
- .catch(aError => {
- debug("updateNetworkInterface error: " + aError);
- });
- break;
- case Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED:
- Promise.resolve()
- .then(() => {
- if (!this.isNetworkTypeMobile(extNetworkInfo.type)) {
- return;
- }
- // Remove host route for data calls
- return this._cleanupAllHostRoutes(networkId);
- })
- .then(() => {
- if (extNetworkInfo.type !=
- Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) {
- return;
- }
- // Remove secondary default route for dun.
- return this.removeSecondaryDefaultRoute(extNetworkInfo);
- })
- .then(() => {
- if (extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI ||
- extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET) {
- // Remove routing table in /proc/net/route
- return this._resetRoutingTable(extNetworkInfo.name);
- }
- if (extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE) {
- return this._removeDefaultRoute(extNetworkInfo)
- }
- })
- .then(() => {
- // Clear http proxy on active network.
- if (this.activeNetworkInfo &&
- extNetworkInfo.type == this.activeNetworkInfo.type) {
- this.clearNetworkProxy();
- }
-
- // Abort ongoing captive portal detection on the wifi interface
- CaptivePortalDetectionHelper
- .notify(CaptivePortalDetectionHelper.EVENT_DISCONNECT, extNetworkInfo);
- })
- .then(() => this.setAndConfigureActive())
- .then(() => {
- // Update data connection when Wifi connected/disconnected
- if (extNetworkInfo.type ==
- Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && this.mRil) {
- for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
- this.mRil.getRadioInterface(i).updateRILNetworkInterface();
- }
- }
- })
- .then(() => this._destroyNetwork(extNetworkInfo.name))
- .then(() => {
- // Notify outer modules like MmsService to start the transaction after
- // the configuration of the network interface is done.
- Services.obs.notifyObservers(network.info,
- TOPIC_CONNECTION_STATE_CHANGED,
- this.convertConnectionType(network.info));
- })
- .catch(aError => {
- debug("updateNetworkInterface error: " + aError);
- });
- break;
- }
- },
-
- unregisterNetworkInterface: function(network) {
- if (!(network instanceof Ci.nsINetworkInterface)) {
- throw Components.Exception("Argument must be nsINetworkInterface.",
- Cr.NS_ERROR_INVALID_ARG);
- }
- let networkId = this.getNetworkId(network.info);
- if (!(networkId in this.networkInterfaces)) {
- throw Components.Exception("No network with that type registered.",
- Cr.NS_ERROR_INVALID_ARG);
- }
-
- // This is for in case a network gets unregistered without being
- // DISCONNECTED.
- if (this.isNetworkTypeMobile(network.info.type)) {
- this._cleanupAllHostRoutes(networkId);
- }
-
- delete this.networkInterfaces[networkId];
-
- Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_UNREGISTERED, null);
- debug("Network '" + networkId + "' unregistered.");
- },
-
- _manageOfflineStatus: true,
-
- networkInterfaces: null,
-
- networkInterfaceLinks: null,
-
- _networkTypePriorityList: [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET,
- Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
- Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE],
- get networkTypePriorityList() {
- return this._networkTypePriorityList;
- },
- set networkTypePriorityList(val) {
- if (val.length != this._networkTypePriorityList.length) {
- throw "Priority list length should equal to " +
- this._networkTypePriorityList.length;
- }
-
- // Check if types in new priority list are valid and also make sure there
- // are no duplicate types.
- let list = [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET,
- Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
- Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE];
- while (list.length) {
- let type = list.shift();
- if (val.indexOf(type) == -1) {
- throw "There is missing network type";
- }
- }
-
- this._networkTypePriorityList = val;
- },
-
- getPriority: function(type) {
- if (this._networkTypePriorityList.indexOf(type) == -1) {
- // 0 indicates the lowest priority.
- return 0;
- }
-
- return this._networkTypePriorityList.length -
- this._networkTypePriorityList.indexOf(type);
- },
-
- get allNetworkInfo() {
- let allNetworkInfo = {};
-
- for (let networkId in this.networkInterfaces) {
- if (this.networkInterfaces.hasOwnProperty(networkId)) {
- allNetworkInfo[networkId] = this.networkInterfaces[networkId].info;
- }
- }
-
- return allNetworkInfo;
- },
-
- _preferredNetworkType: DEFAULT_PREFERRED_NETWORK_TYPE,
- get preferredNetworkType() {
- return this._preferredNetworkType;
- },
- set preferredNetworkType(val) {
- if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
- Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
- Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) {
- throw "Invalid network type";
- }
- this._preferredNetworkType = val;
- },
-
- _activeNetwork: null,
-
- get activeNetworkInfo() {
- return this._activeNetwork && this._activeNetwork.info;
- },
-
- _overriddenActive: null,
-
- overrideActive: function(network) {
- if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
- Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
- Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) {
- throw "Invalid network type";
- }
-
- this._overriddenActive = network;
- this.setAndConfigureActive();
- },
-
- _updateRoutes: function(oldLinks, newLinks, gateways, interfaceName) {
- // Returns items that are in base but not in target.
- function getDifference(base, target) {
- return base.filter(function(i) { return target.indexOf(i) < 0; });
- }
-
- let addedLinks = getDifference(newLinks, oldLinks);
- let removedLinks = getDifference(oldLinks, newLinks);
-
- if (addedLinks.length === 0 && removedLinks.length === 0) {
- return Promise.resolve();
- }
-
- return this._setHostRoutes(false, removedLinks, interfaceName, gateways)
- .then(this._setHostRoutes(true, addedLinks, interfaceName, gateways));
- },
-
- _setHostRoutes: function(doAdd, ipAddresses, networkName, gateways) {
- let getMaxPrefixLength = (aIp) => {
- return aIp.match(this.REGEXP_IPV4) ? IPV4_MAX_PREFIX_LENGTH : IPV6_MAX_PREFIX_LENGTH;
- }
-
- let promises = [];
-
- ipAddresses.forEach((aIpAddress) => {
- let gateway = this.selectGateway(gateways, aIpAddress);
- if (gateway) {
- promises.push((doAdd)
- ? gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD,
- networkName, aIpAddress,
- getMaxPrefixLength(aIpAddress), gateway)
- : gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_REMOVE,
- networkName, aIpAddress,
- getMaxPrefixLength(aIpAddress), gateway));
- }
- });
-
- return Promise.all(promises);
- },
-
- isValidatedNetwork: function(aNetworkInfo) {
- let isValid = false;
- try {
- isValid = (this.getNetworkId(aNetworkInfo) in this.networkInterfaces);
- } catch (e) {
- debug("Invalid network interface: " + e);
- }
-
- return isValid;
- },
-
- addHostRoute: function(aNetworkInfo, aHost) {
- if (!this.isValidatedNetwork(aNetworkInfo)) {
- return Promise.reject("Invalid network info.");
- }
-
- return this.resolveHostname(aNetworkInfo, aHost)
- .then((ipAddresses) => {
- let promises = [];
- let networkId = this.getNetworkId(aNetworkInfo);
-
- ipAddresses.forEach((aIpAddress) => {
- let promise =
- this._setHostRoutes(true, [aIpAddress], aNetworkInfo.name, aNetworkInfo.getGateways())
- .then(() => this.networkInterfaceLinks[networkId].extraRoutes.push(aIpAddress));
-
- promises.push(promise);
- });
-
- return Promise.all(promises);
- });
- },
-
- removeHostRoute: function(aNetworkInfo, aHost) {
- if (!this.isValidatedNetwork(aNetworkInfo)) {
- return Promise.reject("Invalid network info.");
- }
-
- return this.resolveHostname(aNetworkInfo, aHost)
- .then((ipAddresses) => {
- let promises = [];
- let networkId = this.getNetworkId(aNetworkInfo);
-
- ipAddresses.forEach((aIpAddress) => {
- let found = this.networkInterfaceLinks[networkId].extraRoutes.indexOf(aIpAddress);
- if (found < 0) {
- return; // continue
- }
-
- let promise =
- this._setHostRoutes(false, [aIpAddress], aNetworkInfo.name, aNetworkInfo.getGateways())
- .then(() => {
- this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1);
- }, () => {
- // We should remove it even if the operation failed.
- this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1);
- });
- promises.push(promise);
- });
-
- return Promise.all(promises);
- });
- },
-
- isNetworkTypeSecondaryMobile: function(type) {
- return (type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS ||
- type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL ||
- type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS ||
- type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN ||
- type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA);
- },
-
- isNetworkTypeMobile: function(type) {
- return (type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE ||
- this.isNetworkTypeSecondaryMobile(type));
- },
-
- _handleGateways: function(networkId, gateways) {
- let currentNetworkLinks = this.networkInterfaceLinks[networkId];
- if (currentNetworkLinks.gateways.length == 0 ||
- currentNetworkLinks.compareGateways(gateways)) {
- return Promise.resolve();
- }
-
- let currentExtraRoutes = currentNetworkLinks.extraRoutes;
- return this._cleanupAllHostRoutes(networkId)
- .then(() => {
- // If gateways have changed, re-add extra host routes with new gateways.
- if (currentExtraRoutes.length > 0) {
- this._setHostRoutes(true,
- currentExtraRoutes,
- currentNetworkLinks.interfaceName,
- gateways)
- .then(() => {
- currentNetworkLinks.extraRoutes = currentExtraRoutes;
- });
- }
- });
- },
-
- _cleanupAllHostRoutes: function(networkId) {
- let currentNetworkLinks = this.networkInterfaceLinks[networkId];
- let hostRoutes = currentNetworkLinks.linkRoutes.concat(
- currentNetworkLinks.extraRoutes);
-
- if (hostRoutes.length === 0) {
- return Promise.resolve();
- }
-
- return this._setHostRoutes(false,
- hostRoutes,
- currentNetworkLinks.interfaceName,
- currentNetworkLinks.gateways)
- .catch((aError) => {
- debug("Error (" + aError + ") on _cleanupAllHostRoutes, keep proceeding.");
- })
- .then(() => currentNetworkLinks.resetLinks());
- },
-
- selectGateway: function(gateways, host) {
- for (let i = 0; i < gateways.length; i++) {
- let gateway = gateways[i];
- if (gateway.match(this.REGEXP_IPV4) && host.match(this.REGEXP_IPV4) ||
- gateway.indexOf(":") != -1 && host.indexOf(":") != -1) {
- return gateway;
- }
- }
- return null;
- },
-
- _setSecondaryRoute: function(aDoAdd, aInterfaceName, aRoute) {
- return new Promise((aResolve, aReject) => {
- if (aDoAdd) {
- gNetworkService.addSecondaryRoute(aInterfaceName, aRoute,
- (aSuccess) => {
- if (!aSuccess) {
- aReject("addSecondaryRoute failed");
- return;
- }
- aResolve();
- });
- } else {
- gNetworkService.removeSecondaryRoute(aInterfaceName, aRoute,
- (aSuccess) => {
- if (!aSuccess) {
- debug("removeSecondaryRoute failed")
- }
- // Always resolve.
- aResolve();
- });
- }
- });
- },
-
- setSecondaryDefaultRoute: function(network) {
- let gateways = network.getGateways();
- let promises = [];
-
- for (let i = 0; i < gateways.length; i++) {
- let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false;
- // First, we need to add a host route to the gateway in the secondary
- // routing table to make the gateway reachable. Host route takes the max
- // prefix and gateway address 'any'.
- let hostRoute = {
- ip: gateways[i],
- prefix: isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH,
- gateway: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY
- };
- // Now we can add the default route through gateway. Default route takes the
- // min prefix and destination ip 'any'.
- let defaultRoute = {
- ip: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY,
- prefix: 0,
- gateway: gateways[i]
- };
-
- let promise = this._setSecondaryRoute(true, network.name, hostRoute)
- .then(() => this._setSecondaryRoute(true, network.name, defaultRoute));
-
- promises.push(promise);
- }
-
- return Promise.all(promises);
- },
-
- removeSecondaryDefaultRoute: function(network) {
- let gateways = network.getGateways();
- let promises = [];
-
- for (let i = 0; i < gateways.length; i++) {
- let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false;
- // Remove both default route and host route.
- let defaultRoute = {
- ip: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY,
- prefix: 0,
- gateway: gateways[i]
- };
- let hostRoute = {
- ip: gateways[i],
- prefix: isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH,
- gateway: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY
- };
-
- let promise = this._setSecondaryRoute(false, network.name, defaultRoute)
- .then(() => this._setSecondaryRoute(false, network.name, hostRoute));
-
- promises.push(promise);
- }
-
- return Promise.all(promises);
- },
-
- /**
- * Determine the active interface and configure it.
- */
- setAndConfigureActive: function() {
- debug("Evaluating whether active network needs to be changed.");
- let oldActive = this._activeNetwork;
-
- if (this._overriddenActive) {
- debug("We have an override for the active network: " +
- this._overriddenActive.info.name);
- // The override was just set, so reconfigure the network.
- if (this._activeNetwork != this._overriddenActive) {
- this._activeNetwork = this._overriddenActive;
- this._setDefaultRouteAndProxy(this._activeNetwork, oldActive);
- Services.obs.notifyObservers(this.activeNetworkInfo,
- TOPIC_ACTIVE_CHANGED, null);
- }
- return;
- }
-
- // The active network is already our preferred type.
- if (this.activeNetworkInfo &&
- this.activeNetworkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED &&
- this.activeNetworkInfo.type == this._preferredNetworkType) {
- debug("Active network is already our preferred type.");
- return this._setDefaultRouteAndProxy(this._activeNetwork, oldActive);
- }
-
- // Find a suitable network interface to activate.
- this._activeNetwork = null;
- let anyConnected = false;
-
- for (let key in this.networkInterfaces) {
- let network = this.networkInterfaces[key];
- if (network.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
- continue;
- }
- anyConnected = true;
-
- // Set active only for default connections.
- if (network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_WIFI &&
- network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE &&
- network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET) {
- continue;
- }
-
- if (network.info.type == this.preferredNetworkType) {
- this._activeNetwork = network;
- debug("Found our preferred type of network: " + network.info.name);
- break;
- }
-
- // Initialize the active network with the first connected network.
- if (!this._activeNetwork) {
- this._activeNetwork = network;
- continue;
- }
-
- // Compare the prioriy between two network types. If found incoming
- // network with higher priority, replace the active network.
- if (this.getPriority(this._activeNetwork.type) < this.getPriority(network.type)) {
- this._activeNetwork = network;
- }
- }
-
- return Promise.resolve()
- .then(() => {
- if (!this._activeNetwork) {
- return Promise.resolve();
- }
-
- return this._setDefaultRouteAndProxy(this._activeNetwork, oldActive);
- })
- .then(() => {
- if (this._activeNetwork != oldActive) {
- Services.obs.notifyObservers(this.activeNetworkInfo,
- TOPIC_ACTIVE_CHANGED, null);
- }
-
- if (this._manageOfflineStatus) {
- Services.io.offline = !anyConnected &&
- (gTetheringService.state ===
- Ci.nsITetheringService.TETHERING_STATE_INACTIVE);
- }
- });
- },
-
- resolveHostname: function(aNetworkInfo, aHostname) {
- // Sanity check for null, undefined and empty string... etc.
- if (!aHostname) {
- return Promise.reject(new Error("hostname is empty: " + aHostname));
- }
-
- if (aHostname.match(this.REGEXP_IPV4) ||
- aHostname.match(this.REGEXP_IPV6)) {
- return Promise.resolve([aHostname]);
- }
-
- // Wrap gDNSService.asyncResolveExtended to a promise, which
- // resolves with an array of ip addresses or rejects with
- // the reason otherwise.
- let hostResolveWrapper = aNetId => {
- return new Promise((aResolve, aReject) => {
- // Callback for gDNSService.asyncResolveExtended.
- let onLookupComplete = (aRequest, aRecord, aStatus) => {
- if (!Components.isSuccessCode(aStatus)) {
- aReject(new Error("Failed to resolve '" + aHostname +
- "', with status: " + aStatus));
- return;
- }
-
- let retval = [];
- while (aRecord.hasMore()) {
- retval.push(aRecord.getNextAddrAsString());
- }
-
- if (!retval.length) {
- aReject(new Error("No valid address after DNS lookup!"));
- return;
- }
-
- debug("hostname is resolved: " + aHostname);
- debug("Addresses: " + JSON.stringify(retval));
-
- aResolve(retval);
- };
-
- debug('Calling gDNSService.asyncResolveExtended: ' + aNetId + ', ' + aHostname);
- gDNSService.asyncResolveExtended(aHostname,
- 0,
- aNetId,
- onLookupComplete,
- Services.tm.mainThread);
- });
- };
-
- // TODO: |getNetId| will be implemented as a sync call in nsINetworkManager
- // once Bug 1141903 is landed.
- return gNetworkService.getNetId(aNetworkInfo.name)
- .then(aNetId => hostResolveWrapper(aNetId));
- },
-
- convertConnectionType: function(aNetworkInfo) {
- // If there is internal interface change (e.g., MOBILE_MMS, MOBILE_SUPL),
- // the function will return null so that it won't trigger type change event
- // in NetworkInformation API.
- if (aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI &&
- aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE &&
- aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET) {
- return null;
- }
-
- if (aNetworkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED) {
- return CONNECTION_TYPE_NONE;
- }
-
- switch (aNetworkInfo.type) {
- case Ci.nsINetworkInfo.NETWORK_TYPE_WIFI:
- return CONNECTION_TYPE_WIFI;
- case Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE:
- return CONNECTION_TYPE_CELLULAR;
- case Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET:
- return CONNECTION_TYPE_ETHERNET;
- }
- },
-
- _setDNS: function(aNetworkInfo) {
- return new Promise((aResolve, aReject) => {
- let dnses = aNetworkInfo.getDnses();
- let gateways = aNetworkInfo.getGateways();
- gNetworkService.setDNS(aNetworkInfo.name, dnses.length, dnses,
- gateways.length, gateways, (aError) => {
- if (aError) {
- aReject("setDNS failed");
- return;
- }
- aResolve();
- });
- });
- },
-
- _setMtu: function(aNetworkInfo) {
- return new Promise((aResolve, aReject) => {
- gNetworkService.setMtu(aNetworkInfo.name, aNetworkInfo.mtu, (aSuccess) => {
- if (!aSuccess) {
- debug("setMtu failed");
- }
- // Always resolve.
- aResolve();
- });
- });
- },
-
- _createNetwork: function(aInterfaceName) {
- return new Promise((aResolve, aReject) => {
- gNetworkService.createNetwork(aInterfaceName, (aSuccess) => {
- if (!aSuccess) {
- aReject("createNetwork failed");
- return;
- }
- aResolve();
- });
- });
- },
-
- _destroyNetwork: function(aInterfaceName) {
- return new Promise((aResolve, aReject) => {
- gNetworkService.destroyNetwork(aInterfaceName, (aSuccess) => {
- if (!aSuccess) {
- debug("destroyNetwork failed")
- }
- // Always resolve.
- aResolve();
- });
- });
- },
-
- _resetRoutingTable: function(aInterfaceName) {
- return new Promise((aResolve, aReject) => {
- gNetworkService.resetRoutingTable(aInterfaceName, (aSuccess) => {
- if (!aSuccess) {
- debug("resetRoutingTable failed");
- }
- // Always resolve.
- aResolve();
- });
- });
- },
-
- _removeDefaultRoute: function(aNetworkInfo) {
- return new Promise((aResolve, aReject) => {
- let gateways = aNetworkInfo.getGateways();
- gNetworkService.removeDefaultRoute(aNetworkInfo.name, gateways.length,
- gateways, (aSuccess) => {
- if (!aSuccess) {
- debug("removeDefaultRoute failed");
- }
- // Always resolve.
- aResolve();
- });
- });
- },
-
- _setDefaultRouteAndProxy: function(aNetwork, aOldNetwork) {
- if (aOldNetwork) {
- return this._removeDefaultRoute(aOldNetwork.info)
- .then(() => this._setDefaultRouteAndProxy(aNetwork, null));
- }
-
- return new Promise((aResolve, aReject) => {
- let networkInfo = aNetwork.info;
- let gateways = networkInfo.getGateways();
-
- gNetworkService.setDefaultRoute(networkInfo.name, gateways.length, gateways,
- (aSuccess) => {
- if (!aSuccess) {
- gNetworkService.destroyNetwork(networkInfo.name, function() {
- aReject("setDefaultRoute failed");
- });
- return;
- }
- this.setNetworkProxy(aNetwork);
- aResolve();
- });
- });
- },
-
- setNetworkProxy: function(aNetwork) {
- try {
- if (!aNetwork.httpProxyHost || aNetwork.httpProxyHost === "") {
- // Sets direct connection to internet.
- this.clearNetworkProxy();
-
- debug("No proxy support for " + aNetwork.info.name + " network interface.");
- return;
- }
-
- debug("Going to set proxy settings for " + aNetwork.info.name + " network interface.");
- // Sets manual proxy configuration.
- Services.prefs.setIntPref("network.proxy.type", MANUAL_PROXY_CONFIGURATION);
-
- // Do not use this proxy server for all protocols.
- Services.prefs.setBoolPref("network.proxy.share_proxy_settings", false);
- Services.prefs.setCharPref("network.proxy.http", aNetwork.httpProxyHost);
- Services.prefs.setCharPref("network.proxy.ssl", aNetwork.httpProxyHost);
- let port = aNetwork.httpProxyPort === 0 ? 8080 : aNetwork.httpProxyPort;
- Services.prefs.setIntPref("network.proxy.http_port", port);
- Services.prefs.setIntPref("network.proxy.ssl_port", port);
- } catch(ex) {
- debug("Exception " + ex + ". Unable to set proxy setting for " +
- aNetwork.info.name + " network interface.");
- }
- },
-
- clearNetworkProxy: function() {
- debug("Going to clear all network proxy.");
-
- Services.prefs.clearUserPref("network.proxy.type");
- Services.prefs.clearUserPref("network.proxy.share_proxy_settings");
- Services.prefs.clearUserPref("network.proxy.http");
- Services.prefs.clearUserPref("network.proxy.http_port");
- Services.prefs.clearUserPref("network.proxy.ssl");
- Services.prefs.clearUserPref("network.proxy.ssl_port");
- },
-};
-
-var CaptivePortalDetectionHelper = (function() {
-
- const EVENT_CONNECT = "Connect";
- const EVENT_DISCONNECT = "Disconnect";
- let _ongoingInterface = null;
- let _available = ("nsICaptivePortalDetector" in Ci);
- let getService = function() {
- return Cc['@mozilla.org/toolkit/captive-detector;1']
- .getService(Ci.nsICaptivePortalDetector);
- };
-
- let _performDetection = function(interfaceName, callback) {
- let capService = getService();
- let capCallback = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]),
- prepare: function() {
- capService.finishPreparation(interfaceName);
- },
- complete: function(success) {
- _ongoingInterface = null;
- callback(success);
- }
- };
-
- // Abort any unfinished captive portal detection.
- if (_ongoingInterface != null) {
- capService.abort(_ongoingInterface);
- _ongoingInterface = null;
- }
- try {
- capService.checkCaptivePortal(interfaceName, capCallback);
- _ongoingInterface = interfaceName;
- } catch (e) {
- debug('Fail to detect captive portal due to: ' + e.message);
- }
- };
-
- let _abort = function(interfaceName) {
- if (_ongoingInterface !== interfaceName) {
- return;
- }
-
- let capService = getService();
- capService.abort(_ongoingInterface);
- _ongoingInterface = null;
- };
-
- return {
- EVENT_CONNECT: EVENT_CONNECT,
- EVENT_DISCONNECT: EVENT_DISCONNECT,
- notify: function(eventType, network) {
- switch (eventType) {
- case EVENT_CONNECT:
- // perform captive portal detection on wifi interface
- if (_available && network &&
- network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) {
- _performDetection(network.name, function() {
- // TODO: bug 837600
- // We can disconnect wifi in here if user abort the login procedure.
- });
- }
-
- break;
- case EVENT_DISCONNECT:
- if (_available &&
- network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) {
- _abort(network.name);
- }
- break;
- }
- }
- };
-}());
-
-XPCOMUtils.defineLazyGetter(NetworkManager.prototype, "mRil", function() {
- try {
- return Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
- } catch (e) {}
-
- return null;
-});
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkManager]);