Bug 1000040 - Part 2: Implement EthernetManager; r=vicamo

This commit is contained in:
Liang-Heng Chen 2016-02-19 16:06:29 +08:00
parent e6a935e206
commit 135c4b8b2b
10 changed files with 883 additions and 17 deletions

View File

@ -453,6 +453,8 @@
@RESPATH@/components/DOMWifiManager.manifest
@RESPATH@/components/DOMWifiP2pManager.js
@RESPATH@/components/DOMWifiP2pManager.manifest
@RESPATH@/components/EthernetManager.js
@RESPATH@/components/EthernetManager.manifest
@RESPATH@/components/NetworkInterfaceListService.js
@RESPATH@/components/NetworkInterfaceListService.manifest
@RESPATH@/components/NetworkManager.js

View File

@ -0,0 +1,655 @@
/* -*- 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";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const TOPIC_INTERFACE_STATE_CHANGED = "network-interface-state-changed";
const ETHERNET_NETWORK_IFACE_PREFIX = "eth";
const DEFAULT_ETHERNET_NETWORK_IFACE = "eth0";
const INTERFACE_IPADDR_NULL = "0.0.0.0";
const INTERFACE_GATEWAY_NULL = "0.0.0.0";
const INTERFACE_PREFIX_NULL = 0;
const INTERFACE_MACADDR_NULL = "00:00:00:00:00:00";
const NETWORK_INTERFACE_UP = "up";
const NETWORK_INTERFACE_DOWN = "down";
const IP_MODE_DHCP = "dhcp";
const IP_MODE_STATIC = "static";
const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled";
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
"@mozilla.org/network/manager;1",
"nsINetworkManager");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
"@mozilla.org/network/service;1",
"nsINetworkService");
let 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("-*- EthernetManager: " + s + "\n");
};
} else {
debug = function(s) {};
}
}
updateDebug();
// nsINetworkInterface
function EthernetInterface(attr) {
this.info.state = attr.state;
this.info.type = attr.type;
this.info.name = attr.name;
this.info.ipMode = attr.ipMode;
this.info.ips = [attr.ip];
this.info.prefixLengths = [attr.prefixLength];
this.info.gateways = [attr.gateway];
this.info.dnses = attr.dnses;
this.httpProxyHost = "";
this.httpProxyPort = 0;
}
EthernetInterface.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]),
updateConfig: function(config) {
debug("Interface " + this.info.name + " updateConfig " + JSON.stringify(config));
this.info.state = (config.state != undefined) ?
config.state : this.info.state;
this.info.ips = (config.ip != undefined) ? [config.ip] : this.info.ips;
this.info.prefixLengths = (config.prefixLength != undefined) ?
[config.prefixLength] : this.info.prefixLengths;
this.info.gateways = (config.gateway != undefined) ?
[config.gateway] : this.info.gateways;
this.info.dnses = (config.dnses != undefined) ? config.dnses : this.info.dnses;
this.httpProxyHost = (config.httpProxyHost != undefined) ?
config.httpProxyHost : this.httpProxyHost;
this.httpProxyPort = (config.httpProxyPort != undefined) ?
config.httpProxyPort : this.httpProxyPort;
this.info.ipMode = (config.ipMode != undefined) ?
config.ipMode : this.info.ipMode;
},
info: {
getAddresses: function(ips, prefixLengths) {
ips.value = this.ips.slice();
prefixLengths.value = this.prefixLengths.slice();
return this.ips.length;
},
getGateways: function(count) {
if (count) {
count.value = this.gateways.length;
}
return this.gateways.slice();
},
getDnses: function(count) {
if (count) {
count.value = this.dnses.length;
}
return this.dnses.slice();
}
}
};
// nsIEthernetManager
/*
* Network state transition diagram
*
* ---------- enable --------- connect ----------- disconnect --------------
* | Disabled | -----> | Enabled | -------> | Connected | <----------> | Disconnected |
* ---------- --------- ----------- connect --------------
* ^ | | |
* | disable | | |
* -----------------------------------------------------------------------
*/
function EthernetManager() {
debug("EthernetManager start");
// Interface list.
this.ethernetInterfaces = {};
// Used to memorize last connection information.
this.lastStaticConfig = {};
Services.obs.addObserver(this, "xpcom-shutdown", false);
}
EthernetManager.prototype = {
classID: Components.ID("a96441dd-36b3-4f7f-963b-2c032e28a039"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIEthernetManager]),
ethernetInterfaces: null,
lastStaticConfig: null,
observer: function(subject, topic, data) {
switch (topic) {
case "xpcom-shutdown":
debug("xpcom-shutdown");
this._shutdown();
Services.obs.removeObserver(this, "xpcom-shutdown");
break;
}
},
_shutdown: function() {
debug("Shuting down");
(function onRemove(ifnameList) {
if (!ifnameList.length) {
return;
}
let ifname = ifnameList.shift();
this.removeInterface(ifname, { notify: onRemove.bind(this, ifnameList) });
}).call(this, Object.keys(this.ethernetInterfaces));
},
get interfaceList() {
return Object.keys(this.ethernetInterfaces);
},
scan: function(callback) {
debug("Scan");
gNetworkService.getInterfaces(function(success, list) {
let ethList = [];
if (!success) {
if (callback) {
callback.notify(ethList);
}
return;
}
for (let i = 0; i < list.length; i++) {
debug("Found interface " + list[i]);
if (!list[i].startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
continue;
}
ethList.push(list[i]);
}
if (callback) {
callback.notify(ethList);
}
});
},
addInterface: function(ifname, callback) {
debug("Add interface " + ifname);
if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
if (this.ethernetInterfaces[ifname]) {
if (callback) {
callback.notify(true, "Interface already exists.");
}
return;
}
gNetworkService.getInterfaceConfig(ifname, function(success, result) {
if (!success) {
if (callback) {
callback.notify(false, "Netd error.");
}
return;
}
// Since the operation may still succeed with an invalid interface name,
// check the mac address as well.
if (result.macAddr == INTERFACE_MACADDR_NULL) {
if (callback) {
callback.notify(false, "Interface not found.");
}
return;
}
this.ethernetInterfaces[ifname] = new EthernetInterface({
state: result.link == NETWORK_INTERFACE_UP ?
Ci.nsINetworkInfo.NETWORK_STATE_DISABLED :
Ci.nsINetworkInfo.NETWORK_STATE_ENABLED,
name: ifname,
type: Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET,
ip: result.ip,
prefixLength: result.prefix,
ipMode: IP_MODE_DHCP
});
// Register the interface to NetworkManager.
gNetworkManager.registerNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Add interface " + ifname + " succeeded with " +
JSON.stringify(this.ethernetInterfaces[ifname]));
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
removeInterface: function(ifname, callback) {
debug("Remove interface " + ifname);
if (!ifname || !ifname.startsWith(ETHERNET_NETWORK_IFACE_PREFIX)) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
if (!this.ethernetInterfaces[ifname]) {
if (callback) {
callback.notify(true, "Interface does not exist.");
}
return;
}
// Make sure interface is disable before removing.
this.disable(ifname, { notify: function(success, message) {
// Unregister the interface from NetworkManager and also remove it from
// the interface list.
gNetworkManager.unregisterNetworkInterface(this.ethernetInterfaces[ifname]);
delete this.ethernetInterfaces[ifname];
debug("Remove interface " + ifname + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this)});
},
updateInterfaceConfig: function(ifname, config, callback) {
debug("Update interface config with " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
if (!config) {
if (callback) {
callback.notify(false, "No config to update.");
}
return;
}
// Network state can not be modified externally.
if (config.state) {
delete config.state;
}
let currentIpMode = iface.info.ipMode;
// Update config.
this.ethernetInterfaces[iface.info.name].updateConfig(config);
// Do not automatically re-connect if the interface is not in connected
// state.
if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
if (callback) {
callback.notify(true, "ok");
}
return;
}
let newIpMode = this.ethernetInterfaces[iface.info.name].info.ipMode;
if (newIpMode == IP_MODE_STATIC) {
this._setStaticIP(iface.info.name, callback);
return;
}
if ((currentIpMode == IP_MODE_STATIC) && (newIpMode == IP_MODE_DHCP)) {
gNetworkService.stopDhcp(iface.info.name, function(success) {
if (success) {
debug("DHCP for " + iface.info.name + " stopped.");
}
});
// Clear the current network settings before do dhcp request, otherwise
// dhcp settings could fail.
this.disconnect(iface.info.name, { notify: function(success, message) {
if (!success) {
if (callback) {
callback.notify("Disconnect failed.");
}
return;
}
this._runDhcp(iface.info.name, callback);
}.bind(this) });
return;
}
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
enable: function(ifname, callback) {
debug("Enable interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
// Interface can be only enabled in the state of disabled.
if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_DISABLED) {
if (callback) {
callback.notify(true, "Interface already enabled.");
}
return;
}
let ips = {};
let prefixLengths = {};
iface.info.getAddresses(ips, prefixLengths);
let config = { ifname: iface.info.name,
ip: ips.value[0],
prefix: prefixLengths.value[0],
link: NETWORK_INTERFACE_UP };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd Error.");
}
return;
}
this.ethernetInterfaces[iface.info.name].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_ENABLED
});
debug("Enable interface " + iface.info.name + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
}.bind(this));
},
disable: function(ifname, callback) {
debug("Disable interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_DISABLED) {
if (callback) {
callback.notify(true, "Interface already disabled.");
}
return;
}
if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
gNetworkService.stopDhcp(iface.info.name, function(success) {
if (success) {
debug("DHCP for " + iface.info.name + " stopped.");
}
});
}
let ips = {};
let prefixLengths = {};
iface.info.getAddresses(ips, prefixLengths);
let config = { ifname: iface.info.name,
ip: ips.value[0],
prefix: prefixLengths.value[0],
link: NETWORK_INTERFACE_DOWN };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd Error.");
}
return;
}
this.ethernetInterfaces[iface.info.name].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_DISABLED
});
debug("Disable interface " + iface.info.name + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
}.bind(this));
},
connect: function(ifname, callback) {
debug("Connect interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
// Interface can only be connected in the state of enabled or
// disconnected.
if (iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_DISABLED ||
iface.info.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
if (callback) {
callback.notify(true, "Interface " + ifname + " is not available or "
+ " already connected.");
}
return;
}
if (iface.info.ipMode == IP_MODE_DHCP) {
this._runDhcp(iface.info.name, callback);
return;
}
if (iface.info.ipMode == IP_MODE_STATIC) {
if (this._checkConfigNull(iface) && this.lastStaticConfig[iface.info.name]) {
debug("Connect with lastStaticConfig " +
JSON.stringify(this.lastStaticConfig[iface.info.name]));
this.ethernetInterfaces[iface.info.name].updateConfig(
this.lastStaticConfig[iface.info.name]);
}
this._setStaticIP(iface.info.name, callback);
return;
}
if (callback) {
callback.notify(false, "IP mode is wrong or not set.");
}
}.bind(this));
},
disconnect: function(ifname, callback) {
debug("Disconnect interface " + ifname);
this._ensureIfname(ifname, callback, function(iface) {
// Interface can be only disconnected in the state of connected.
if (iface.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) {
if (callback) {
callback.notify(true, "Interface is already disconnected");
}
return;
}
let config = { ifname: iface.info.name,
ip: INTERFACE_IPADDR_NULL,
prefix: INTERFACE_PREFIX_NULL,
link: NETWORK_INTERFACE_UP };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd error.");
}
return;
}
// Stop dhcp daemon.
gNetworkService.stopDhcp(iface.info.name, function(success) {
if (success) {
debug("DHCP for " + iface.info.name + " stopped.");
}
});
this.ethernetInterfaces[iface.info.name].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED,
ip: INTERFACE_IPADDR_NULL,
prefixLength: INTERFACE_PREFIX_NULL,
gateway: INTERFACE_GATEWAY_NULL
});
gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Disconnect interface " + iface.info.name + " succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
}.bind(this));
},
_checkConfigNull: function(iface) {
let ips = {};
let prefixLengths = {};
let gateways = iface.info.getGateways();
iface.info.getAddresses(ips, prefixLengths);
if (ips.value[0] == INTERFACE_IPADDR_NULL &&
prefixLengths.value[0] == INTERFACE_PREFIX_NULL &&
gateways[0] == INTERFACE_GATEWAY_NULL) {
return true;
}
return false;
},
_ensureIfname: function(ifname, callback, func) {
// If no given ifname, use the default one.
if (!ifname) {
ifname = DEFAULT_ETHERNET_NETWORK_IFACE;
}
let iface = this.ethernetInterfaces[ifname];
if (!iface) {
if (callback) {
callback.notify(true, "Interface " + ifname + " is not available.");
}
return;
}
func.call(this, iface);
},
_runDhcp: function(ifname, callback) {
debug("runDhcp with " + ifname);
if (!this.ethernetInterfaces[ifname]) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
gNetworkService.dhcpRequest(ifname, function(success, result) {
if (!success) {
if (callback) {
callback.notify(false, "DHCP failed.");
}
return;
}
debug("DHCP succeeded with " + JSON.stringify(result));
// Clear last static network information when connecting with dhcp mode.
if (this.lastStaticConfig[ifname]) {
this.lastStaticConfig[ifname] = null;
}
this.ethernetInterfaces[ifname].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED,
ip: result.ipaddr_str,
gateway: result.gateway_str,
prefixLength: result.prefixLength,
dnses: [result.dns1_str, result.dns2_str]
});
gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Connect interface " + ifname + " with DHCP succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
_setStaticIP: function(ifname, callback) {
let iface = this.ethernetInterfaces[ifname];
if (!iface) {
if (callback) {
callback.notify(false, "Invalid interface.");
}
return;
}
let ips = {};
let prefixLengths = {};
iface.info.getAddresses(ips, prefixLengths);
let config = { ifname: iface.info.name,
ip: ips.value[0],
prefix: prefixLengths.value[0],
link: NETWORK_INTERFACE_UP };
gNetworkService.setInterfaceConfig(config, function(success) {
if (!success) {
if (callback) {
callback.notify(false, "Netd Error.");
}
return;
}
// Keep the lastest static network information.
let ips = {};
let prefixLengths = {};
let gateways = iface.info.getGateways();
iface.info.getAddresses(ips, prefixLengths);
this.lastStaticConfig[iface.info.name] = {
ip: ips.value[0],
prefixLength: prefixLengths.value[0],
gateway: gateways[0]
};
this.ethernetInterfaces[ifname].updateConfig({
state: Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED,
});
gNetworkManager.updateNetworkInterface(this.ethernetInterfaces[ifname]);
debug("Connect interface " + ifname + " with static ip succeeded.");
if (callback) {
callback.notify(true, "ok");
}
}.bind(this));
},
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EthernetManager]);

View File

@ -0,0 +1,2 @@
component {a96441dd-36b3-4f7f-963b-2c032e28a039} EthernetManager.js
contract @mozilla.org/ethernetManager;1 {a96441dd-36b3-4f7f-963b-2c032e28a039}

View File

@ -12,6 +12,7 @@ XPIDL_SOURCES += [
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
XPIDL_SOURCES += [
'nsIEthernetManager.idl',
'nsINetworkStatsServiceProxy.idl',
]

View File

@ -0,0 +1,137 @@
/* 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/. */
#include "nsISupports.idl"
[scriptable, function, uuid(2a3ad56c-edc0-439f-8aae-900b331ddf49)]
interface nsIEthernetManagerCallback : nsISupports
{
/**
* Callback function used to report the success of different operations.
*
* @param success
* Boolean value indicates the success of an operation.
* @prarm message
* Message reported in the end of operation.
*/
void notify(in boolean success, in DOMString message);
};
[scriptable, function, uuid(1746e7dd-92d4-43fa-8ef4-bc13d0b60353)]
interface nsIEthernetManagerScanCallback : nsISupports
{
/**
* Callback function used to report the result of scan function.
*
* @param list
* List of available ethernet interfaces.
*/
void notify(in jsval list);
};
/**
* An internal idl provides control to ethernet interfaces.
*/
[scriptable, uuid(81750c87-bb3b-4724-b955-834eafa53fd1)]
interface nsIEthernetManager : nsISupports
{
/**
* List of exisiting interface name.
*/
readonly attribute jsval interfaceList;
/**
* Scan available ethernet interfaces on device.
*
* @param callback
* Callback function.
*/
void scan(in nsIEthernetManagerScanCallback callback);
/**
* Add a new interface to the interface list.
*
* @param ifname
* Interface name. Should be the form of "eth*".
* @param callback
* Callback function.
*/
void addInterface(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Remove an existing interface from the interface list.
*
* @param ifname
* Interface name.
* @param Callback
* Callback function.
*/
void removeInterface(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Update a conifg of an existing interface in the interface list.
*
* @param ifname
* Interface name.
* @param config
* .ip: IP address.
* .prefixLength: Mask length.
* .gateway: Gateway.
* .dnses: DNS addresses.
* .httpProxyHost: HTTP proxy host.
* .httpProxyPort: HTTP proxy port.
* .ipMode: IP mode, can be 'dhcp' or 'static'.
* @param callback
* Callback function.
*/
void updateInterfaceConfig(in DOMString ifname,
in jsval config,
in nsIEthernetManagerCallback callback);
/**
* Enable networking of an existing interface in the interface list.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void enable(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Disable networking of an existing interface in the interface list.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void disable(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Make an existing interface connect to network.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void connect(in DOMString ifname,
in nsIEthernetManagerCallback callback);
/**
* Disconnect a connected interface in the interface list.
*
* @param ifname
* Interface name.
* @param callback
* Callback function.
*/
void disconnect(in DOMString ifname,
in nsIEthernetManagerCallback callback);
};

View File

@ -51,6 +51,8 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
EXTRA_COMPONENTS += [
'EthernetManager.js',
'EthernetManager.manifest',
'NetworkStatsManager.js',
'NetworkStatsManager.manifest',
'NetworkStatsServiceProxy.js',

View File

@ -14,9 +14,9 @@ Cu.import("resource://gre/modules/Promise.jsm");
const NETWORKMANAGER_CONTRACTID = "@mozilla.org/network/manager;1";
const NETWORKMANAGER_CID =
Components.ID("{33901e46-33b8-11e1-9869-f46d04d25bcc}");
Components.ID("{1ba9346b-53b5-4660-9dc6-58f0b258d0a6}");
const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInfo.NETWORK_TYPE_WIFI;
const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET;
XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
return Cc["@mozilla.org/parentprocessmessagemanager;1"]
@ -426,7 +426,8 @@ NetworkManager.prototype = {
return this.removeSecondaryDefaultRoute(extNetworkInfo);
})
.then(() => {
if (extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) {
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);
}
@ -499,6 +500,43 @@ NetworkManager.prototype = {
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 = {};
@ -516,8 +554,9 @@ NetworkManager.prototype = {
return this._preferredNetworkType;
},
set preferredNetworkType(val) {
if ([Ci.nsINetworkInfo.NETWORK_TYPE_WIFI,
Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE].indexOf(val) == -1) {
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;
@ -532,9 +571,9 @@ NetworkManager.prototype = {
_overriddenActive: null,
overrideActive: function(network) {
let type = network.info.type;
if ([Ci.nsINetworkInfo.NETWORK_TYPE_WIFI,
Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE].indexOf(type) == -1) {
if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI,
Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) {
throw "Invalid network type";
}
@ -835,15 +874,28 @@ NetworkManager.prototype = {
// 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_MOBILE &&
network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET) {
continue;
}
this._activeNetwork = network;
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()
@ -927,8 +979,9 @@ NetworkManager.prototype = {
// 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.nsINetworkInfo.NETWORK_TYPE_WIFI &&
aNetworkInfo.type != Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE) {
if (aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI &&
aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE &&
aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET) {
return null;
}
@ -941,6 +994,8 @@ NetworkManager.prototype = {
return CONNECTION_TYPE_WIFI;
case Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE:
return CONNECTION_TYPE_CELLULAR;
case Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET:
return CONNECTION_TYPE_ETHERNET;
}
},

View File

@ -1,3 +1,3 @@
# NetworkManager.js
component {33901e46-33b8-11e1-9869-f46d04d25bcc} NetworkManager.js
contract @mozilla.org/network/manager;1 {33901e46-33b8-11e1-9869-f46d04d25bcc}
component {1ba9346b-53b5-4660-9dc6-58f0b258d0a6} NetworkManager.js
contract @mozilla.org/network/manager;1 {1ba9346b-53b5-4660-9dc6-58f0b258d0a6}

View File

@ -4,7 +4,7 @@
#include "nsISupports.idl"
[scriptable, uuid(f439ab5d-64bd-4a6c-8863-30235fa784d2)]
[scriptable, uuid(4816a559-5620-4cb5-8433-ff0b25e6622f)]
interface nsINetworkInfo : nsISupports
{
const long NETWORK_STATE_UNKNOWN = -1;
@ -12,6 +12,8 @@ interface nsINetworkInfo : nsISupports
const long NETWORK_STATE_CONNECTED = 1;
const long NETWORK_STATE_DISCONNECTING = 2;
const long NETWORK_STATE_DISCONNECTED = 3;
const long NETWORK_STATE_ENABLED = 4;
const long NETWORK_STATE_DISABLED = 5;
/**
* Current network state, one of the NETWORK_STATE_* constants.
@ -30,6 +32,7 @@ interface nsINetworkInfo : nsISupports
const long NETWORK_TYPE_MOBILE_IMS = 5;
const long NETWORK_TYPE_MOBILE_DUN = 6;
const long NETWORK_TYPE_MOBILE_FOTA = 7;
const long NETWORK_TYPE_ETHERNET = 8;
/**
* Network type. One of the NETWORK_TYPE_* constants.

View File

@ -10,7 +10,7 @@ interface nsINetworkInterface;
/**
* Manage network interfaces.
*/
[scriptable, uuid(e5ffe335-078e-4b25-87f1-02429bd2e458)]
[scriptable, uuid(1ba9346b-53b5-4660-9dc6-58f0b258d0a6)]
interface nsINetworkManager : nsISupports
{
/**
@ -62,6 +62,15 @@ interface nsINetworkManager : nsISupports
*/
readonly attribute jsval allNetworkInfo;
/**
* Priority list of network types. An array of
* nsINetworkInterface::NETWORK_TYPE_* constants.
*
* The piror position of the type indicates the higher priority. The priority
* is used to determine route when there are multiple connected networks.
*/
attribute jsval networkTypePriorityList;
/**
* The preferred network type. One of the
* nsINetworkInterface::NETWORK_TYPE_* constants.