Bug 1018088 - PUSH wakeup compatible multiple mobile networks carriers. r=nsm

This commit is contained in:
Fernando Rodriguez Sela 2014-06-09 00:32:00 -04:00
parent 283734ec19
commit 53ed7beec6
2 changed files with 131 additions and 35 deletions

View File

@ -463,6 +463,17 @@ pref("services.push.pingInterval", 1800000); // 30 minutes
pref("services.push.requestTimeout", 10000);
// enable udp wakeup support
pref("services.push.udp.wakeupEnabled", true);
// This value should be the prefix to be added to the current PDP context[1]
// domain or a full-qualified domain name.
// If finished with a dot, it will be added as a prefix to the PDP context
// domain. If not, will be used as the DNS query.
// If the DNS query is unsuccessful, the push agent will send a null netid and
// is a server decision what to do with the device. If the MCC-MNC identifies a
// unique network the server will change to UDP mode. Otherwise, a websocket
// connection will be maintained.
// [1] Packet Data Protocol
// http://en.wikipedia.org/wiki/GPRS_core_network#PDP_context
pref("services.push.udp.well-known_netidAddress", "_wakeup_.");
// NetworkStats
#ifdef MOZ_WIDGET_GONK

View File

@ -25,9 +25,19 @@ Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.importGlobalProperties(["indexedDB"]);
XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
"@mozilla.org/network/dns-service;1",
"nsIDNSService");
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
"@mozilla.org/settingsService;1",
"nsISettingsService");
XPCOMUtils.defineLazyModuleGetter(this, "AlarmService",
"resource://gre/modules/AlarmService.jsm");
var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
this.EXPORTED_SYMBOLS = ["PushService"];
const prefs = new Preferences("services.push.");
@ -643,6 +653,9 @@ this.PushService = {
return;
}
// Read the APN data from the settings DB.
let lock = gSettingsService.createLock();
lock.get("ril.data.apnSettings", this);
debug("serverURL: " + uri.spec);
this._wsListener = new PushWebSocketListener(this);
@ -651,6 +664,25 @@ this.PushService = {
this._currentState = STATE_WAITING_FOR_WS_START;
},
/**
* nsISettingsServiceCallback
*/
handle: function(name, result) {
if (name !== "ril.data.apnSettings" || !result) {
return;
}
let apn = result[0].filter(function(e) {
return e.types[0] === "default";
});
if (apn.length === 0 || !apn[0].apn) {
this._apnDomain = null;
debug("No APN Domain found. No netid support");
return;
}
this._apnDomain = apn[0].apn;
debug("APN Domain: " + this._apnDomain);
},
_startListeningIfChannelsPresent: function() {
// Check to see if we need to do anything.
this._db.getAllChannelIDs(function(channelIDs) {
@ -1295,9 +1327,6 @@ this.PushService = {
// Since we've had a successful connection reset the retry fail count.
this._retryFailCount = 0;
// Openning an available UDP port.
this._listenForUDPWakeup();
let data = {
messageType: "hello",
}
@ -1305,20 +1334,6 @@ this.PushService = {
if (this._UAID)
data["uaid"] = this._UAID;
let networkState = this._getNetworkState();
if (networkState.ip) {
// Hostport is apparently a thing.
data["wakeup_hostport"] = {
ip: networkState.ip,
port: this._udpServer && this._udpServer.port
};
data["mobilenetwork"] = {
mcc: networkState.mcc,
mnc: networkState.mnc
};
}
function sendHelloMessage(ids) {
// On success, ids is an array, on error its not.
data["channelIDs"] = ids.map ?
@ -1327,8 +1342,27 @@ this.PushService = {
this._currentState = STATE_WAITING_FOR_HELLO;
}
this._db.getAllChannelIDs(sendHelloMessage.bind(this),
sendHelloMessage.bind(this));
this._getNetworkState((networkState) => {
if (networkState.ip) {
// Opening an available UDP port.
this._listenForUDPWakeup();
// Host-port is apparently a thing.
data["wakeup_hostport"] = {
ip: networkState.ip,
port: this._udpServer && this._udpServer.port
};
data["mobilenetwork"] = {
mcc: networkState.mcc,
mnc: networkState.mnc,
netid: networkState.netid
};
}
this._db.getAllChannelIDs(sendHelloMessage.bind(this),
sendHelloMessage.bind(this));
});
},
/**
@ -1421,6 +1455,9 @@ this.PushService = {
}
},
/**
* This method should be called only if the device is on a mobile network!
*/
_listenForUDPWakeup: function() {
debug("listenForUDPWakeup()");
@ -1429,11 +1466,6 @@ this.PushService = {
return;
}
if (!this._getNetworkState().ip) {
debug("No IP");
return;
}
if (!prefs.get("udp.wakeupEnabled")) {
debug("UDP support disabled");
return;
@ -1474,12 +1506,15 @@ this.PushService = {
* woken up by UDP (which currently just means having an mcc and mnc along
* with an IP).
*/
_getNetworkState: function() {
_getNetworkState: function(callback) {
if (typeof callback !== 'function') {
throw new Error("No callback method. Aborting push agent !");
}
debug("getNetworkState()");
try {
if (!prefs.get("udp.wakeupEnabled")) {
debug("UDP support disabled, we do not send any carrier info");
throw "UDP disabled";
throw new Error("UDP disabled");
}
let nm = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
@ -1494,25 +1529,33 @@ this.PushService = {
let iccInfo = icc.getIccInfo(clientId);
if (iccInfo) {
debug("Running on mobile data");
let ips = {};
let prefixLengths = {};
nm.active.getAddresses(ips, prefixLengths);
return {
mcc: iccInfo.mcc,
mnc: iccInfo.mnc,
ip: ips.value[0]
}
this._getMobileNetworkId(function(netid) {
debug("Recovered netID = " + netid);
callback({
mcc: iccInfo.mcc,
mnc: iccInfo.mnc,
ip: ips.value[0],
netid: netid
});
});
return;
}
}
} catch (e) {}
} catch (e) {
debug("Error recovering mobile network information: " + e);
}
debug("Running on wifi");
return {
callback({
mcc: 0,
mnc: 0,
ip: undefined
};
});
},
// utility function used to add/remove observers in init() and shutdown()
@ -1523,5 +1566,47 @@ this.PushService = {
} catch (e) {
return "network:offline-status-changed";
}
},
// Get the mobile network ID (netid)
_getMobileNetworkId: function(callback) {
if (typeof callback !== 'function') {
return;
}
function queryDNSForDomain(domain) {
debug("[_getMobileNetworkId:queryDNSForDomain] Querying DNS for " +
domain);
let netIDDNSListener = {
onLookupComplete: function(aRequest, aRecord, aStatus) {
if (aRecord) {
let netid = aRecord.getNextAddrAsString();
debug("[_getMobileNetworkId:queryDNSForDomain] NetID found: " +
netid);
callback(netid);
} else {
debug("[_getMobileNetworkId:queryDNSForDomain] NetID not found");
callback(null);
}
}
};
gDNSService.asyncResolve(domain, 0, netIDDNSListener,
threadManager.currentThread);
return [];
}
debug("[_getMobileNetworkId:queryDNSForDomain] Getting mobile network ID (I'm " +
gDNSService.myHostName + ")");
let netidAddress = prefs.get("udp.well-known_netidAddress");
if (netidAddress.endsWith(".")) {
if (this._apnDomain) {
queryDNSForDomain(netidAddress + this._apnDomain, callback);
} else {
callback(null); // No netid could be recovered
}
} else if(netidAddress) {
queryDNSForDomain(netidAddress, callback);
}
}
}