Bug 992772 - Use mms specific network interface to do DNS lookup. r=echen, r=btseng, r=mrbkap

--HG--
extra : histedit_source : 670d2124210bc3769a460022214baaee6b305639
This commit is contained in:
Henry Chang 2015-04-09 19:09:37 +08:00
Родитель c723673526
Коммит f9c56cb2da
7 изменённых файлов: 176 добавлений и 89 удалений

Просмотреть файл

@ -167,6 +167,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIMobileConnectionService");
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
"@mozilla.org/network/service;1",
"nsINetworkService");
XPCOMUtils.defineLazyGetter(this, "MMS", function() {
let MMS = {};
Cu.import("resource://gre/modules/MmsPduHelper.jsm", MMS);
@ -706,33 +710,38 @@ XPCOMUtils.defineLazyGetter(this, "gMmsTransactionHelper", function() {
url = mmsConnection.mmsc;
}
let startTransaction = () => {
let startTransaction = netId => {
if (DEBUG) debug("sendRequest: register proxy filter to " + url);
let proxyFilter = new MmsProxyFilter(mmsConnection, url);
gpps.registerFilter(proxyFilter, 0);
cancellable.xhr =
this.sendHttpRequest(mmsConnection, method,
url, istream, proxyFilter,
url, istream, proxyFilter, netId,
(aHttpStatus, aData) =>
cancellable.done(aHttpStatus, aData));
};
mmsConnection.ensureRouting(url)
.then(() => startTransaction(),
(aError) => {
debug("Failed to ensureRouting: " + aError);
let onRejected = aReason => {
debug(aReason);
mmsConnection.release();
cancellable.done(_HTTP_STATUS_FAILED_TO_ROUTE, null);
};
mmsConnection.release();
cancellable.done(_HTTP_STATUS_FAILED_TO_ROUTE, null);
});
// TODO: |getNetId| will be implemented as a sync call in nsINetworkManager
// once Bug 1141903 is landed.
mmsConnection.ensureRouting(url)
.then(() => gNetworkService.getNetId(mmsConnection.networkInterface.name),
(aReason) => onRejected('Failed to ensureRouting: ' + aReason))
.then((netId) => startTransaction(netId),
(aReason) => onRejected('Failed to getNetId: ' + aReason));
});
return cancellable;
},
sendHttpRequest: function(mmsConnection, method, url, istream, proxyFilter,
callback) {
netId, callback) {
let releaseMmsConnectionAndCallback = (httpStatus, data) => {
gpps.unregisterFilter(proxyFilter);
// Always release the MMS network connection before callback.
@ -745,6 +754,7 @@ XPCOMUtils.defineLazyGetter(this, "gMmsTransactionHelper", function() {
.createInstance(Ci.nsIXMLHttpRequest);
// Basic setups
xhr.networkInterfaceId = netId;
xhr.open(method, url, true);
xhr.responseType = "arraybuffer";
if (istream) {

Просмотреть файл

@ -277,48 +277,53 @@ NetworkManager.prototype = {
switch (network.state) {
case Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED:
gNetworkService.createNetwork(network.name, () => {
// Add host route for data calls
if (this.isNetworkTypeMobile(network.type)) {
let currentInterfaceLinks = this.networkInterfaceLinks[networkId];
let newLinkRoutes = network.getDnses().concat(network.httpProxyHost);
// If gateways have changed, remove all old routes first.
this._handleGateways(networkId, network.getGateways())
.then(() => this._updateRoutes(currentInterfaceLinks.linkRoutes,
newLinkRoutes,
network.getGateways(), network.name))
.then(() => currentInterfaceLinks.setLinks(newLinkRoutes,
network.getGateways(),
network.name));
}
// Remove pre-created default route and let setAndConfigureActive()
// to set default route only on preferred network
gNetworkService.removeDefaultRoute(network);
// Dun type is a special case where we add the default route to a
// secondary table.
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
this.setSecondaryDefaultRoute(network);
}
this._addSubnetRoutes(network);
this.setAndConfigureActive();
// Update data connection when Wifi connected/disconnected
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI && this.mRil) {
for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
this.mRil.getRadioInterface(i).updateRILNetworkInterface();
// Set DNS server as early as possible to prevent from
// premature domain name lookup.
gNetworkService.setDNS(network, () => {
// Add host route for data calls
if (this.isNetworkTypeMobile(network.type)) {
let currentInterfaceLinks = this.networkInterfaceLinks[networkId];
let newLinkRoutes = network.getDnses().concat(network.httpProxyHost);
// If gateways have changed, remove all old routes first.
this._handleGateways(networkId, network.getGateways())
.then(() => this._updateRoutes(currentInterfaceLinks.linkRoutes,
newLinkRoutes,
network.getGateways(), network.name))
.then(() => currentInterfaceLinks.setLinks(newLinkRoutes,
network.getGateways(),
network.name));
}
}
// Probing the public network accessibility after routing table is ready
CaptivePortalDetectionHelper
.notify(CaptivePortalDetectionHelper.EVENT_CONNECT, this.active);
// Dun type is a special case where we add the default route to a
// secondary table.
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
this.setSecondaryDefaultRoute(network);
}
// Notify outer modules like MmsService to start the transaction after
// the configuration of the network interface is done.
Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
this.convertConnectionType(network));
this._addSubnetRoutes(network);
this.setAndConfigureActive();
// Update data connection when Wifi connected/disconnected
if (network.type == Ci.nsINetworkInterface.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.active);
// Notify outer modules like MmsService to start the transaction after
// the configuration of the network interface is done.
Services.obs.notifyObservers(network, TOPIC_CONNECTION_STATE_CHANGED,
this.convertConnectionType(network));
});
});
break;
@ -641,7 +646,7 @@ NetworkManager.prototype = {
// The override was just set, so reconfigure the network.
if (this.active != this._overriddenActive) {
this.active = this._overriddenActive;
this._setDefaultRouteAndDNS(this.active, oldActive);
this._setDefaultRouteAndProxy(this.active, oldActive);
Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
}
return;
@ -652,7 +657,7 @@ NetworkManager.prototype = {
this.active.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED &&
this.active.type == this._preferredNetworkType) {
debug("Active network is already our preferred type.");
this._setDefaultRouteAndDNS(this.active, oldActive);
this._setDefaultRouteAndProxy(this.active, oldActive);
return;
}
@ -686,10 +691,8 @@ NetworkManager.prototype = {
this.active = defaultDataNetwork;
}
// Don't set default route on secondary APN
if (this.isNetworkTypeSecondaryMobile(this.active.type)) {
gNetworkService.setDNS(this.active, function() {});
} else {
this._setDefaultRouteAndDNS(this.active, oldActive);
if (!this.isNetworkTypeSecondaryMobile(this.active.type)) {
this._setDefaultRouteAndProxy(this.active, oldActive);
}
}
@ -713,44 +716,48 @@ NetworkManager.prototype = {
return Promise.resolve([hostname]);
}
let deferred = Promise.defer();
let onLookupComplete = (aRequest, aRecord, aStatus) => {
if (!Components.isSuccessCode(aStatus)) {
deferred.reject(new Error(
"Failed to resolve '" + hostname + "', with status: " + aStatus));
return;
}
// 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 '" + hostname +
"', with status: " + aStatus));
return;
}
let retval = [];
while (aRecord.hasMore()) {
retval.push(aRecord.getNextAddrAsString());
}
let retval = [];
while (aRecord.hasMore()) {
retval.push(aRecord.getNextAddrAsString());
}
if (!retval.length) {
deferred.reject(new Error("No valid address after DNS lookup!"));
return;
}
if (!retval.length) {
aReject(new Error("No valid address after DNS lookup!"));
return;
}
debug("hostname is resolved: " + hostname);
debug("Addresses: " + JSON.stringify(retval));
debug("hostname is resolved: " + hostname);
debug("Addresses: " + JSON.stringify(retval));
deferred.resolve(retval);
aResolve(retval);
};
debug('Calling gDNSService.asyncResolveExtended: ' + aNetId + ', ' + hostname);
gDNSService.asyncResolveExtended(hostname,
0,
aNetId,
onLookupComplete,
Services.tm.mainThread);
});
};
// Bug 1058282 - Explicitly request ipv4 to get around 8.8.8.8 probe at
// http://androidxref.com/4.3_r2.1/xref/bionic/libc/netbsd/net/getaddrinfo.c#1923
//
// Whenever MMS connection is the only network interface, there is no
// default route so that any ip probe will fail.
let flags = 0;
if (network.type === Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
flags |= Ci.nsIDNSService.RESOLVE_DISABLE_IPV6;
}
// TODO: Bug 992772 - Resolve the hostname with specified networkInterface.
gDNSService.asyncResolve(hostname, flags, onLookupComplete, Services.tm.mainThread);
return deferred.promise;
// TODO: |getNetId| will be implemented as a sync call in nsINetworkManager
// once Bug 1141903 is landed.
return gNetworkService.getNetId(network.name)
.then(aNetId => hostResolveWrapper(aNetId));
},
convertConnectionType: function(network) {
@ -774,15 +781,13 @@ NetworkManager.prototype = {
}
},
_setDefaultRouteAndDNS: function(network, oldInterface) {
_setDefaultRouteAndProxy: function(network, oldInterface) {
gNetworkService.setDefaultRoute(network, oldInterface, function(success) {
if (!success) {
gNetworkService.destroyNetwork(network, function() {});
return;
}
gNetworkService.setDNS(network, function(result) {
gNetworkService.setNetworkProxy(network);
});
gNetworkService.setNetworkProxy(network);
});
},
};

Просмотреть файл

@ -391,7 +391,8 @@ NetworkService.prototype = {
cmd: "setDNS",
ifname: networkInterface.name,
domain: "mozilla." + networkInterface.name + ".doman",
dnses: dnses
dnses: dnses,
gateways: networkInterface.getGateways()
};
this.controlMessage(options, function(result) {
callback.setDnsResult(result.success ? null : result.reason);
@ -762,6 +763,23 @@ NetworkService.prototype = {
callback.nativeCommandResult(!result.error);
});
},
getNetId: function(interfaceName) {
let params = {
cmd: "getNetId",
ifname: interfaceName
};
return new Promise((aResolve, aReject) => {
this.controlMessage(params, result => {
if (result.error) {
aReject(result.reason);
return;
}
aResolve(result.netId);
});
});
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkService]);

Просмотреть файл

@ -440,7 +440,6 @@ CommandResult::CommandResult(int32_t aResultCode)
strerror_r(abs(aResultCode), strerrorBuf, STRERROR_R_BUF_SIZE);
mResult.mReason = NS_ConvertUTF8toUTF16(strerrorBuf);
}
mResult.mRet = true;
}
CommandResult::CommandResult(const mozilla::dom::NetworkResultOptions& aResult)
@ -1535,6 +1534,7 @@ void NetworkUtils::ExecuteCommand(NetworkParams aOptions)
BUILD_ENTRY(resetConnections),
BUILD_ENTRY(createNetwork),
BUILD_ENTRY(destroyNetwork),
BUILD_ENTRY(getNetId),
#undef BUILD_ENTRY
};
@ -1704,6 +1704,7 @@ CommandResult NetworkUtils::setDNS(NetworkParams& aOptions)
// Lollipop.
static CommandFunc COMMAND_CHAIN[] = {
setInterfaceDns,
addDefaultRouteToNetwork,
defaultAsyncSuccessHandler
};
NetIdManager::NetIdInfo netIdInfo;
@ -1717,7 +1718,12 @@ CommandResult NetworkUtils::setDNS(NetworkParams& aOptions)
if (SDK_VERSION >= 18) {
// JB, KK.
static CommandFunc COMMAND_CHAIN[] = {
#if ANDROID_VERSION == 18
// Since we don't use per-interface DNS lookup feature on JB,
// we need to set the default DNS interface whenever setting the
// DNS name server.
setDefaultInterface,
#endif
setInterfaceDns,
defaultAsyncSuccessHandler
};
@ -1898,6 +1904,17 @@ CommandResult NetworkUtils::setDefaultRouteLegacy(NetworkParams& aOptions)
}
}
// Set the default DNS interface.
if (SDK_VERSION >= 18) {
// For JB, KK only.
static CommandFunc COMMAND_CHAIN[] = {
setDefaultInterface,
defaultAsyncSuccessHandler
};
runChain(aOptions, COMMAND_CHAIN, setDnsFail);
return CommandResult::Pending();
}
return SUCCESS;
}
@ -2516,6 +2533,27 @@ CommandResult NetworkUtils::destroyNetwork(NetworkParams& aOptions)
return CommandResult::Pending();
}
/**
* Query the netId associated with the given network interface name.
*/
CommandResult NetworkUtils::getNetId(NetworkParams& aOptions)
{
NetworkResultOptions result;
if (SDK_VERSION < 20) {
// For pre-Lollipop, use the interface name as the fallback.
result.mNetId = GET_FIELD(mIfname);
return result;
}
NetIdManager::NetIdInfo netIdInfo;
if (-1 == mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) {
return ESRCH;
}
result.mNetId.AppendInt(netIdInfo.mNetId, 10);
return result;
}
void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
{
NetworkResultOptions result;

Просмотреть файл

@ -309,6 +309,7 @@ private:
CommandResult updateUpStream(NetworkParams& aOptions);
CommandResult createNetwork(NetworkParams& aOptions);
CommandResult destroyNetwork(NetworkParams& aOptions);
CommandResult getNetId(NetworkParams& aOptions);
CommandResult addHostRouteLegacy(NetworkParams& aOptions);
CommandResult removeHostRouteLegacy(NetworkParams& aOptions);

Просмотреть файл

@ -159,7 +159,7 @@ interface nsIDhcpRequestCallback : nsISupports
/**
* Provide network services.
*/
[scriptable, uuid(e40dd966-cb04-4dc7-ac4b-6382769c00b9)]
[scriptable, uuid(a0f29630-c25c-11e4-8830-0800200c9a66)]
interface nsINetworkService : nsISupports
{
const long MODIFY_ROUTE_ADD = 0;
@ -486,4 +486,17 @@ interface nsINetworkService : nsISupports
*/
void destroyNetwork(in DOMString interfaceName,
in nsINativeCommandCallback callback);
/**
* Query the netId associated with given network interface name.
*
* @param interfaceName
* The network interface name which we want to query.
*
* @return A deferred promise that resolves with a string to indicate.
* the queried netId on success and rejects if the interface name
* is invalid.
*
*/
jsval getNetId(in DOMString interfaceName);
};

Просмотреть файл

@ -96,4 +96,6 @@ dictionary NetworkResultOptions
long dns1 = 0;
long dns2 = 0;
long server = 0;
DOMString netId = ""; // for "getNetId".
};