Bug 875390 - Add MMSC and/or MMS Proxy specific host routes via MMS APN. r=vyang
authorAlexandre Lissy <lissyx@lissyx.dyndns.org>
Fri, 31 May 2013 10:14:45 +0200
changeset 133778 df933307c25d929ad8b68d3c59e21deb338a4f92
parent 133777 603891a7c4b131cab3c12086e81b2c0a4c4c3eb3
child 133779 734e6d9d72f8f0a5dd40d90f4bc90a46dda353b7
push id28905
push userryanvm@gmail.com
push dateMon, 03 Jun 2013 15:58:12 +0000
treeherdermozilla-inbound@d2eabe8e27b5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvyang
bugs875390
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 875390 - Add MMSC and/or MMS Proxy specific host routes via MMS APN. r=vyang MMS sending has been failing because often the default network route was not going through the MMS APN. This commit adds specific host route via the correct network interface for either MMSC or MMS proxy depending on the carrier information. We also perform DNS resolution to cope with MMSC/proxy that are using FQDN.
dom/system/gonk/NetworkManager.js
dom/system/gonk/net_worker.js
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -18,16 +18,20 @@ const NETWORKINTERFACE_CID =
   Components.ID("{266c3edd-78f0-4512-8178-2d6fee2d35ee}");
 
 const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
                                    "@mozilla.org/settingsService;1",
                                    "nsISettingsService");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
+                                   "@mozilla.org/network/dns-service;1",
+                                   "nsIDNSService");
+
 const TOPIC_INTERFACE_STATE_CHANGED  = "network-interface-state-changed";
 const TOPIC_INTERFACE_REGISTERED     = "network-interface-registered";
 const TOPIC_INTERFACE_UNREGISTERED   = "network-interface-unregistered";
 const TOPIC_ACTIVE_CHANGED           = "network-active-changed";
 const TOPIC_MOZSETTINGS_CHANGED      = "mozsettings-changed";
 const TOPIC_PREF_CHANGED             = "nsPref:changed";
 const TOPIC_XPCOM_SHUTDOWN           = "xpcom-shutdown";
 const PREF_MANAGE_OFFLINE_STATUS     = "network.gonk.manage-offline-status";
@@ -124,16 +128,18 @@ function isComplete(code) {
 
 /**
  * This component watches for network interfaces changing state and then
  * adjusts routes etc. accordingly.
  */
 function NetworkManager() {
   this.networkInterfaces = {};
   Services.obs.addObserver(this, TOPIC_INTERFACE_STATE_CHANGED, true);
+  Services.obs.addObserver(this, TOPIC_INTERFACE_REGISTERED, true);
+  Services.obs.addObserver(this, TOPIC_INTERFACE_UNREGISTERED, true);
   Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false);
   Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false);
 
   debug("Starting worker.");
   this.worker = new ChromeWorker("resource://gre/modules/net_worker.js");
   this.worker.onmessage = this.handleWorkerMessage.bind(this);
   this.worker.onerror = function onerror(event) {
     debug("Received error from worker: " + event.filename +
@@ -268,28 +274,52 @@ NetworkManager.prototype = {
             this.setAndConfigureActive();
             // Update data connection when Wifi connected/disconnected
             if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
               this.mRIL.updateRILNetworkInterface();
             }
             break;
         }
         break;
+      case TOPIC_INTERFACE_REGISTERED:
+        let regNetwork = subject.QueryInterface(Ci.nsINetworkInterface);
+        debug("Network '" + regNetwork.name + "' registered, adding mmsproxy and/or mmsc route");
+        if (regNetwork.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
+	  let mmsHosts = this.resolveHostname(
+	      [ Services.prefs.getCharPref("ril.mms.mmsproxy"),
+                Services.prefs.getCharPref("ril.mms.mmsc") ]
+	    );
+          this.addHostRouteWithResolve(regNetwork, mmsHosts);
+        }
+        break;
+      case TOPIC_INTERFACE_UNREGISTERED:
+        let unregNetwork = subject.QueryInterface(Ci.nsINetworkInterface);
+        debug("Network '" + regNetwork.name + "' unregistered, removing mmsproxy and/or mmsc route");
+        if (unregNetwork.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
+	  let mmsHosts = this.resolveHostname(
+	      [ Services.prefs.getCharPref("ril.mms.mmsproxy"),
+                Services.prefs.getCharPref("ril.mms.mmsc") ]
+	    );
+          this.removeHostRouteWithResolve(unregNetwork, mmsHosts);
+        }
+        break;
       case TOPIC_MOZSETTINGS_CHANGED:
         let setting = JSON.parse(data);
         this.handle(setting.key, setting.value);
         break;
       case TOPIC_PREF_CHANGED:
         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.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED);
+        Services.obs.removeObserver(this, TOPIC_INTERFACE_REGISTERED);
+        Services.obs.removeObserver(this, TOPIC_INTERFACE_UNREGISTERED);
         Services.obs.removeObserver(this, TOPIC_INTERFACE_STATE_CHANGED);
         break;
     }
   },
 
   // nsINetworkManager
 
   registerNetworkInterface: function registerNetworkInterface(network) {
@@ -518,35 +548,70 @@ NetworkManager.prototype = {
     this.worker.postMessage(options);
   },
 
   addHostRoute: function addHostRoute(network) {
     debug("Going to add host route on " + network.name);
     let options = {
       cmd: "addHostRoute",
       ifname: network.name,
-      dns1: network.dns1,
-      dns2: network.dns2,
       gateway: network.gateway,
-      httpproxy: network.httpProxyHost,
-      mmsproxy: Services.prefs.getCharPref("ril.mms.mmsproxy")
+      hostnames: [network.dns1, network.dns2, network.httpProxyHost]
     };
     this.worker.postMessage(options);
   },
 
   removeHostRoute: function removeHostRoute(network) {
     debug("Going to remove host route on " + network.name);
     let options = {
       cmd: "removeHostRoute",
       ifname: network.name,
-      dns1: network.dns1,
-      dns2: network.dns2,
       gateway: network.gateway,
-      httpproxy: network.httpProxyHost,
-      mmsproxy: Services.prefs.getCharPref("ril.mms.mmsproxy")
+      hostnames: [network.dns1, network.dns2, network.httpProxyHost]
+    };
+    this.worker.postMessage(options);
+  },
+
+  resolveHostname: function resolveHostname(hosts) {
+    let retval = [];
+
+    for(var i = 0; i < hosts.length; i++) {
+      let hostname = hosts[i].split('/')[2];
+      if (!hostname) {
+        continue;
+      }
+
+      let hostnameIps = gDNSService.resolve(hostname, 0);
+      while (hostnameIps.hasMore()) {
+        retval.push(hostnameIps.getNextAddrAsString());
+        debug("Found IP at: " + JSON.stringify(retval));
+      }
+    }
+
+    return retval;
+  },
+
+  addHostRouteWithResolve: function addHostRouteWithResolve(network, hosts) {
+    debug("Going to add host route after dns resolution on " + network.name);
+    let options = {
+      cmd: "addHostRoute",
+      ifname: network.name,
+      gateway: network.gateway,
+      hostnames: hosts
+    };
+    this.worker.postMessage(options);
+  },
+
+  removeHostRouteWithResolve: function removeHostRouteWithResolve(network, hosts) {
+    debug("Going to remove host route after dns resolution on " + network.name);
+    let options = {
+      cmd: "removeHostRoute",
+      ifname: network.name,
+      gateway: network.gateway,
+      hostnames: hosts
     };
     this.worker.postMessage(options);
   },
 
   setNetworkProxy: function setNetworkProxy() {
     try {
       if (!this.active.httpProxyHost || this.active.httpProxyHost == "") {
         // Sets direct connection to internet.
--- a/dom/system/gonk/net_worker.js
+++ b/dom/system/gonk/net_worker.js
@@ -224,30 +224,28 @@ function runDHCPAndSetDefaultRouteAndDNS
 function removeDefaultRoute(options) {
   libnetutils.ifc_remove_default_route(options.ifname);
 }
 
 /**
  * Add host route for given network interface.
  */
 function addHostRoute(options) {
-  libnetutils.ifc_add_route(options.ifname, options.dns1, 32, options.gateway);
-  libnetutils.ifc_add_route(options.ifname, options.dns2, 32, options.gateway);
-  libnetutils.ifc_add_route(options.ifname, options.httpproxy, 32, options.gateway);
-  libnetutils.ifc_add_route(options.ifname, options.mmsproxy, 32, options.gateway);
+  for (let i = 0; i < options.hostnames.length; i++) {
+    libnetutils.ifc_add_route(options.ifname, options.hostnames[i], 32, options.gateway);
+  }
 }
 
 /**
  * Remove host route for given network interface.
  */
 function removeHostRoute(options) {
-  libnetutils.ifc_remove_route(options.ifname, options.dns1, 32, options.gateway);
-  libnetutils.ifc_remove_route(options.ifname, options.dns2, 32, options.gateway);
-  libnetutils.ifc_remove_route(options.ifname, options.httpproxy, 32, options.gateway);
-  libnetutils.ifc_remove_route(options.ifname, options.mmsproxy, 32, options.gateway);
+  for (let i = 0; i < options.hostnames.length; i++) {
+    libnetutils.ifc_remove_route(options.ifname, options.hostnames[i], 32, options.gateway);
+  }
 }
 
 function removeNetworkRoute(options) {
   let ipvalue = netHelpers.stringToIP(options.ip);
   let netmaskvalue = netHelpers.stringToIP(options.netmask);
   let subnet = netmaskvalue & ipvalue;
   let dst = netHelpers.ipToString(subnet);
   let prefixLength = netHelpers.getMaskLength(netmaskvalue);