dom/system/gonk/NetworkService.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/system/gonk/NetworkService.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,562 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +"use strict";
     1.9 +
    1.10 +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
    1.11 +
    1.12 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.13 +Cu.import("resource://gre/modules/Services.jsm");
    1.14 +Cu.import("resource://gre/modules/NetUtil.jsm");
    1.15 +Cu.import("resource://gre/modules/FileUtils.jsm");
    1.16 +
    1.17 +const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1";
    1.18 +const NETWORKSERVICE_CID = Components.ID("{baec696c-c78d-42db-8b44-603f8fbfafb4}");
    1.19 +
    1.20 +XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker",
    1.21 +                                   "@mozilla.org/network/worker;1",
    1.22 +                                   "nsINetworkWorker");
    1.23 +
    1.24 +// 1xx - Requested action is proceeding
    1.25 +const NETD_COMMAND_PROCEEDING   = 100;
    1.26 +// 2xx - Requested action has been successfully completed
    1.27 +const NETD_COMMAND_OKAY         = 200;
    1.28 +// 4xx - The command is accepted but the requested action didn't
    1.29 +// take place.
    1.30 +const NETD_COMMAND_FAIL         = 400;
    1.31 +// 5xx - The command syntax or parameters error
    1.32 +const NETD_COMMAND_ERROR        = 500;
    1.33 +// 6xx - Unsolicited broadcasts
    1.34 +const NETD_COMMAND_UNSOLICITED  = 600;
    1.35 +
    1.36 +const WIFI_CTRL_INTERFACE = "wl0.1";
    1.37 +
    1.38 +const MANUAL_PROXY_CONFIGURATION = 1;
    1.39 +
    1.40 +let DEBUG = false;
    1.41 +
    1.42 +// Read debug setting from pref.
    1.43 +try {
    1.44 +  let debugPref = Services.prefs.getBoolPref("network.debugging.enabled");
    1.45 +  DEBUG = DEBUG || debugPref;
    1.46 +} catch (e) {}
    1.47 +
    1.48 +function netdResponseType(code) {
    1.49 +  return Math.floor(code / 100) * 100;
    1.50 +}
    1.51 +
    1.52 +function isError(code) {
    1.53 +  let type = netdResponseType(code);
    1.54 +  return (type !== NETD_COMMAND_PROCEEDING && type !== NETD_COMMAND_OKAY);
    1.55 +}
    1.56 +
    1.57 +function debug(msg) {
    1.58 +  dump("-*- NetworkService: " + msg + "\n");
    1.59 +}
    1.60 +
    1.61 +/**
    1.62 + * This component watches for network interfaces changing state and then
    1.63 + * adjusts routes etc. accordingly.
    1.64 + */
    1.65 +function NetworkService() {
    1.66 +  if(DEBUG) debug("Starting net_worker.");
    1.67 +
    1.68 +  let self = this;
    1.69 +
    1.70 +  if (gNetworkWorker) {
    1.71 +    let networkListener = {
    1.72 +      onEvent: function(event) {
    1.73 +        self.handleWorkerMessage(event);
    1.74 +      }
    1.75 +    };
    1.76 +    gNetworkWorker.start(networkListener);
    1.77 +  }
    1.78 +  // Callbacks to invoke when a reply arrives from the net_worker.
    1.79 +  this.controlCallbacks = Object.create(null);
    1.80 +
    1.81 +  this.shutdown = false;
    1.82 +  Services.obs.addObserver(this, "xpcom-shutdown", false);
    1.83 +}
    1.84 +
    1.85 +NetworkService.prototype = {
    1.86 +  classID:   NETWORKSERVICE_CID,
    1.87 +  classInfo: XPCOMUtils.generateCI({classID: NETWORKSERVICE_CID,
    1.88 +                                    contractID: NETWORKSERVICE_CONTRACTID,
    1.89 +                                    classDescription: "Network Service",
    1.90 +                                    interfaces: [Ci.nsINetworkService]}),
    1.91 +  QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkService]),
    1.92 +
    1.93 +  // Helpers
    1.94 +
    1.95 +  idgen: 0,
    1.96 +  controlMessage: function(params, callback) {
    1.97 +    if (this.shutdown) {
    1.98 +      return;
    1.99 +    }
   1.100 +
   1.101 +    if (callback) {
   1.102 +      let id = this.idgen++;
   1.103 +      params.id = id;
   1.104 +      this.controlCallbacks[id] = callback;
   1.105 +    }
   1.106 +    if (gNetworkWorker) {
   1.107 +      gNetworkWorker.postMessage(params);
   1.108 +    }
   1.109 +  },
   1.110 +
   1.111 +  handleWorkerMessage: function(response) {
   1.112 +    if(DEBUG) debug("NetworkManager received message from worker: " + JSON.stringify(response));
   1.113 +    let id = response.id;
   1.114 +    if (response.broadcast === true) {
   1.115 +      Services.obs.notifyObservers(null, response.topic, response.reason);
   1.116 +      return;
   1.117 +    }
   1.118 +    let callback = this.controlCallbacks[id];
   1.119 +    if (callback) {
   1.120 +      callback.call(this, response);
   1.121 +      delete this.controlCallbacks[id];
   1.122 +    }
   1.123 +  },
   1.124 +
   1.125 +  // nsINetworkService
   1.126 +
   1.127 +  getNetworkInterfaceStats: function(networkName, callback) {
   1.128 +    if(DEBUG) debug("getNetworkInterfaceStats for " + networkName);
   1.129 +
   1.130 +    if (this.shutdown) {
   1.131 +      return;
   1.132 +    }
   1.133 +
   1.134 +    let file = new FileUtils.File("/proc/net/dev");
   1.135 +    if (!file) {
   1.136 +      callback.networkStatsAvailable(false, -1, -1, new Date());
   1.137 +      return;
   1.138 +    }
   1.139 +
   1.140 +    NetUtil.asyncFetch(file, function(inputStream, status) {
   1.141 +      let result = {
   1.142 +        success: true,  // netd always return success even interface doesn't exist.
   1.143 +        rxBytes: 0,
   1.144 +        txBytes: 0
   1.145 +      };
   1.146 +      result.date = new Date();
   1.147 +
   1.148 +      if (Components.isSuccessCode(status)) {
   1.149 +        // Find record for corresponding interface.
   1.150 +        let statExpr = /(\S+): +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+/;
   1.151 +        let data = NetUtil.readInputStreamToString(inputStream,
   1.152 +                    inputStream.available()).split("\n");
   1.153 +        for (let i = 2; i < data.length; i++) {
   1.154 +          let parseResult = statExpr.exec(data[i]);
   1.155 +          if (parseResult && parseResult[1] === networkName) {
   1.156 +            result.rxBytes = parseInt(parseResult[2], 10);
   1.157 +            result.txBytes = parseInt(parseResult[3], 10);
   1.158 +            break;
   1.159 +          }
   1.160 +        }
   1.161 +      }
   1.162 +
   1.163 +      callback.networkStatsAvailable(result.success, result.rxBytes,
   1.164 +                                     result.txBytes, result.date);
   1.165 +    });
   1.166 +  },
   1.167 +
   1.168 +  setNetworkInterfaceAlarm: function(networkName, threshold, callback) {
   1.169 +    if (!networkName) {
   1.170 +      callback.networkUsageAlarmResult(-1);
   1.171 +      return;
   1.172 +    }
   1.173 +
   1.174 +    let self = this;
   1.175 +    this._disableNetworkInterfaceAlarm(networkName, function(result) {
   1.176 +      if (threshold < 0) {
   1.177 +        if (!isError(result.resultCode)) {
   1.178 +          callback.networkUsageAlarmResult(null);
   1.179 +          return;
   1.180 +        }
   1.181 +        callback.networkUsageAlarmResult(result.reason);
   1.182 +        return
   1.183 +      }
   1.184 +
   1.185 +      self._setNetworkInterfaceAlarm(networkName, threshold, callback);
   1.186 +    });
   1.187 +  },
   1.188 +
   1.189 +  _setNetworkInterfaceAlarm: function(networkName, threshold, callback) {
   1.190 +    if(DEBUG) debug("setNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
   1.191 +
   1.192 +    let params = {
   1.193 +      cmd: "setNetworkInterfaceAlarm",
   1.194 +      ifname: networkName,
   1.195 +      threshold: threshold
   1.196 +    };
   1.197 +
   1.198 +    params.report = true;
   1.199 +    params.isAsync = true;
   1.200 +
   1.201 +    this.controlMessage(params, function(result) {
   1.202 +      if (!isError(result.resultCode)) {
   1.203 +        callback.networkUsageAlarmResult(null);
   1.204 +        return;
   1.205 +      }
   1.206 +
   1.207 +      this._enableNetworkInterfaceAlarm(networkName, threshold, callback);
   1.208 +    });
   1.209 +  },
   1.210 +
   1.211 +  _enableNetworkInterfaceAlarm: function(networkName, threshold, callback) {
   1.212 +    if(DEBUG) debug("enableNetworkInterfaceAlarm for " + networkName + " at " + threshold + "bytes");
   1.213 +
   1.214 +    let params = {
   1.215 +      cmd: "enableNetworkInterfaceAlarm",
   1.216 +      ifname: networkName,
   1.217 +      threshold: threshold
   1.218 +    };
   1.219 +
   1.220 +    params.report = true;
   1.221 +    params.isAsync = true;
   1.222 +
   1.223 +    this.controlMessage(params, function(result) {
   1.224 +      if (!isError(result.resultCode)) {
   1.225 +        callback.networkUsageAlarmResult(null);
   1.226 +        return;
   1.227 +      }
   1.228 +      callback.networkUsageAlarmResult(result.reason);
   1.229 +    });
   1.230 +  },
   1.231 +
   1.232 +  _disableNetworkInterfaceAlarm: function(networkName, callback) {
   1.233 +    if(DEBUG) debug("disableNetworkInterfaceAlarm for " + networkName);
   1.234 +
   1.235 +    let params = {
   1.236 +      cmd: "disableNetworkInterfaceAlarm",
   1.237 +      ifname: networkName,
   1.238 +    };
   1.239 +
   1.240 +    params.report = true;
   1.241 +    params.isAsync = true;
   1.242 +
   1.243 +    this.controlMessage(params, function(result) {
   1.244 +      callback(result);
   1.245 +    });
   1.246 +  },
   1.247 +
   1.248 +  setWifiOperationMode: function(interfaceName, mode, callback) {
   1.249 +    if(DEBUG) debug("setWifiOperationMode on " + interfaceName + " to " + mode);
   1.250 +
   1.251 +    let params = {
   1.252 +      cmd: "setWifiOperationMode",
   1.253 +      ifname: interfaceName,
   1.254 +      mode: mode
   1.255 +    };
   1.256 +
   1.257 +    params.report = true;
   1.258 +    params.isAsync = true;
   1.259 +
   1.260 +    this.controlMessage(params, function(result) {
   1.261 +      if (isError(result.resultCode)) {
   1.262 +        callback.wifiOperationModeResult("netd command error");
   1.263 +      } else {
   1.264 +        callback.wifiOperationModeResult(null);
   1.265 +      }
   1.266 +    });
   1.267 +  },
   1.268 +
   1.269 +  resetRoutingTable: function(network) {
   1.270 +    let ips = {};
   1.271 +    let prefixLengths = {};
   1.272 +    let length = network.getAddresses(ips, prefixLengths);
   1.273 +
   1.274 +    for (let i = 0; i < length; i++) {
   1.275 +      let ip = ips.value[i];
   1.276 +      let prefixLength = prefixLengths.value[i];
   1.277 +
   1.278 +      let options = {
   1.279 +        cmd: "removeNetworkRoute",
   1.280 +        ifname: network.name,
   1.281 +        ip: ip,
   1.282 +        prefixLength: prefixLength
   1.283 +      };
   1.284 +      this.controlMessage(options);
   1.285 +    }
   1.286 +  },
   1.287 +
   1.288 +  setDNS: function(networkInterface) {
   1.289 +    if(DEBUG) debug("Going DNS to " + networkInterface.name);
   1.290 +    let dnses = networkInterface.getDnses();
   1.291 +    let options = {
   1.292 +      cmd: "setDNS",
   1.293 +      ifname: networkInterface.name,
   1.294 +      domain: "mozilla." + networkInterface.name + ".doman",
   1.295 +      dnses: dnses
   1.296 +    };
   1.297 +    this.controlMessage(options);
   1.298 +  },
   1.299 +
   1.300 +  setDefaultRouteAndDNS: function(network, oldInterface) {
   1.301 +    if(DEBUG) debug("Going to change route and DNS to " + network.name);
   1.302 +    let gateways = network.getGateways();
   1.303 +    let dnses = network.getDnses();
   1.304 +    let options = {
   1.305 +      cmd: "setDefaultRouteAndDNS",
   1.306 +      ifname: network.name,
   1.307 +      oldIfname: (oldInterface && oldInterface !== network) ? oldInterface.name : null,
   1.308 +      gateways: gateways,
   1.309 +      domain: "mozilla." + network.name + ".doman",
   1.310 +      dnses: dnses
   1.311 +    };
   1.312 +    this.controlMessage(options);
   1.313 +    this.setNetworkProxy(network);
   1.314 +  },
   1.315 +
   1.316 +  removeDefaultRoute: function(network) {
   1.317 +    if(DEBUG) debug("Remove default route for " + network.name);
   1.318 +    let gateways = network.getGateways();
   1.319 +    let options = {
   1.320 +      cmd: "removeDefaultRoute",
   1.321 +      ifname: network.name,
   1.322 +      gateways: gateways
   1.323 +    };
   1.324 +    this.controlMessage(options);
   1.325 +  },
   1.326 +
   1.327 +  addHostRoute: function(network) {
   1.328 +    if(DEBUG) debug("Going to add host route on " + network.name);
   1.329 +    let gateways = network.getGateways();
   1.330 +    let dnses = network.getDnses();
   1.331 +    let options = {
   1.332 +      cmd: "addHostRoute",
   1.333 +      ifname: network.name,
   1.334 +      gateways: gateways,
   1.335 +      hostnames: dnses.concat(network.httpProxyHost)
   1.336 +    };
   1.337 +    this.controlMessage(options);
   1.338 +  },
   1.339 +
   1.340 +  removeHostRoute: function(network) {
   1.341 +    if(DEBUG) debug("Going to remove host route on " + network.name);
   1.342 +    let gateways = network.getGateways();
   1.343 +    let dnses = network.getDnses();
   1.344 +    let options = {
   1.345 +      cmd: "removeHostRoute",
   1.346 +      ifname: network.name,
   1.347 +      gateways: gateways,
   1.348 +      hostnames: dnses.concat(network.httpProxyHost)
   1.349 +    };
   1.350 +    this.controlMessage(options);
   1.351 +  },
   1.352 +
   1.353 +  removeHostRoutes: function(ifname) {
   1.354 +    if(DEBUG) debug("Going to remove all host routes on " + ifname);
   1.355 +    let options = {
   1.356 +      cmd: "removeHostRoutes",
   1.357 +      ifname: ifname,
   1.358 +    };
   1.359 +    this.controlMessage(options);
   1.360 +  },
   1.361 +
   1.362 +  addHostRouteWithResolve: function(network, hosts) {
   1.363 +    if(DEBUG) debug("Going to add host route after dns resolution on " + network.name);
   1.364 +    let gateways = network.getGateways();
   1.365 +    let options = {
   1.366 +      cmd: "addHostRoute",
   1.367 +      ifname: network.name,
   1.368 +      gateways: gateways,
   1.369 +      hostnames: hosts
   1.370 +    };
   1.371 +    this.controlMessage(options);
   1.372 +  },
   1.373 +
   1.374 +  removeHostRouteWithResolve: function(network, hosts) {
   1.375 +    if(DEBUG) debug("Going to remove host route after dns resolution on " + network.name);
   1.376 +    let gateways = network.getGateways();
   1.377 +    let options = {
   1.378 +      cmd: "removeHostRoute",
   1.379 +      ifname: network.name,
   1.380 +      gateways: gateways,
   1.381 +      hostnames: hosts
   1.382 +    };
   1.383 +    this.controlMessage(options);
   1.384 +  },
   1.385 +
   1.386 +  addSecondaryRoute: function(ifname, route) {
   1.387 +    if(DEBUG) debug("Going to add route to secondary table on " + ifname);
   1.388 +    let options = {
   1.389 +      cmd: "addSecondaryRoute",
   1.390 +      ifname: ifname,
   1.391 +      ip: route.ip,
   1.392 +      prefix: route.prefix,
   1.393 +      gateway: route.gateway
   1.394 +    };
   1.395 +    this.controlMessage(options);
   1.396 +  },
   1.397 +
   1.398 +  removeSecondaryRoute: function(ifname, route) {
   1.399 +    if(DEBUG) debug("Going to remove route from secondary table on " + ifname);
   1.400 +    let options = {
   1.401 +      cmd: "removeSecondaryRoute",
   1.402 +      ifname: ifname,
   1.403 +      ip: route.ip,
   1.404 +      prefix: route.prefix,
   1.405 +      gateway: route.gateway
   1.406 +    };
   1.407 +    this.controlMessage(options);
   1.408 +  },
   1.409 +
   1.410 +  setNetworkProxy: function(network) {
   1.411 +    try {
   1.412 +      if (!network.httpProxyHost || network.httpProxyHost === "") {
   1.413 +        // Sets direct connection to internet.
   1.414 +        Services.prefs.clearUserPref("network.proxy.type");
   1.415 +        Services.prefs.clearUserPref("network.proxy.share_proxy_settings");
   1.416 +        Services.prefs.clearUserPref("network.proxy.http");
   1.417 +        Services.prefs.clearUserPref("network.proxy.http_port");
   1.418 +        Services.prefs.clearUserPref("network.proxy.ssl");
   1.419 +        Services.prefs.clearUserPref("network.proxy.ssl_port");
   1.420 +        if(DEBUG) debug("No proxy support for " + network.name + " network interface.");
   1.421 +        return;
   1.422 +      }
   1.423 +
   1.424 +      if(DEBUG) debug("Going to set proxy settings for " + network.name + " network interface.");
   1.425 +      // Sets manual proxy configuration.
   1.426 +      Services.prefs.setIntPref("network.proxy.type", MANUAL_PROXY_CONFIGURATION);
   1.427 +      // Do not use this proxy server for all protocols.
   1.428 +      Services.prefs.setBoolPref("network.proxy.share_proxy_settings", false);
   1.429 +      Services.prefs.setCharPref("network.proxy.http", network.httpProxyHost);
   1.430 +      Services.prefs.setCharPref("network.proxy.ssl", network.httpProxyHost);
   1.431 +      let port = network.httpProxyPort === 0 ? 8080 : network.httpProxyPort;
   1.432 +      Services.prefs.setIntPref("network.proxy.http_port", port);
   1.433 +      Services.prefs.setIntPref("network.proxy.ssl_port", port);
   1.434 +    } catch(ex) {
   1.435 +        if(DEBUG) debug("Exception " + ex + ". Unable to set proxy setting for " +
   1.436 +                         network.name + " network interface.");
   1.437 +    }
   1.438 +  },
   1.439 +
   1.440 +  // Enable/Disable DHCP server.
   1.441 +  setDhcpServer: function(enabled, config, callback) {
   1.442 +    if (null === config) {
   1.443 +      config = {};
   1.444 +    }
   1.445 +
   1.446 +    config.cmd = "setDhcpServer";
   1.447 +    config.isAsync = true;
   1.448 +    config.enabled = enabled;
   1.449 +
   1.450 +    this.controlMessage(config, function setDhcpServerResult(response) {
   1.451 +      if (!response.success) {
   1.452 +        callback.dhcpServerResult('Set DHCP server error');
   1.453 +        return;
   1.454 +      }
   1.455 +      callback.dhcpServerResult(null);
   1.456 +    });
   1.457 +  },
   1.458 +
   1.459 +  // Enable/disable WiFi tethering by sending commands to netd.
   1.460 +  setWifiTethering: function(enable, config, callback) {
   1.461 +    // config should've already contained:
   1.462 +    //   .ifname
   1.463 +    //   .internalIfname
   1.464 +    //   .externalIfname
   1.465 +    config.wifictrlinterfacename = WIFI_CTRL_INTERFACE;
   1.466 +    config.cmd = "setWifiTethering";
   1.467 +
   1.468 +    // The callback function in controlMessage may not be fired immediately.
   1.469 +    config.isAsync = true;
   1.470 +    this.controlMessage(config, function setWifiTetheringResult(data) {
   1.471 +      let code = data.resultCode;
   1.472 +      let reason = data.resultReason;
   1.473 +      let enable = data.enable;
   1.474 +      let enableString = enable ? "Enable" : "Disable";
   1.475 +
   1.476 +      if(DEBUG) debug(enableString + " Wifi tethering result: Code " + code + " reason " + reason);
   1.477 +
   1.478 +      if (isError(code)) {
   1.479 +        callback.wifiTetheringEnabledChange("netd command error");
   1.480 +      } else {
   1.481 +        callback.wifiTetheringEnabledChange(null);
   1.482 +      }
   1.483 +    });
   1.484 +  },
   1.485 +
   1.486 +  // Enable/disable USB tethering by sending commands to netd.
   1.487 +  setUSBTethering: function(enable, config, callback) {
   1.488 +    config.cmd = "setUSBTethering";
   1.489 +    // The callback function in controlMessage may not be fired immediately.
   1.490 +    config.isAsync = true;
   1.491 +    this.controlMessage(config, function setUsbTetheringResult(data) {
   1.492 +      let code = data.resultCode;
   1.493 +      let reason = data.resultReason;
   1.494 +      let enable = data.enable;
   1.495 +      let enableString = enable ? "Enable" : "Disable";
   1.496 +
   1.497 +      if(DEBUG) debug(enableString + " USB tethering result: Code " + code + " reason " + reason);
   1.498 +
   1.499 +      if (isError(code)) {
   1.500 +        callback.usbTetheringEnabledChange("netd command error");
   1.501 +      } else {
   1.502 +        callback.usbTetheringEnabledChange(null);
   1.503 +      }
   1.504 +    });
   1.505 +  },
   1.506 +
   1.507 +  // Switch usb function by modifying property of persist.sys.usb.config.
   1.508 +  enableUsbRndis: function(enable, callback) {
   1.509 +    if(DEBUG) debug("enableUsbRndis: " + enable);
   1.510 +
   1.511 +    let params = {
   1.512 +      cmd: "enableUsbRndis",
   1.513 +      enable: enable
   1.514 +    };
   1.515 +    // Ask net work to report the result when this value is set to true.
   1.516 +    if (callback) {
   1.517 +      params.report = true;
   1.518 +    } else {
   1.519 +      params.report = false;
   1.520 +    }
   1.521 +
   1.522 +    // The callback function in controlMessage may not be fired immediately.
   1.523 +    params.isAsync = true;
   1.524 +    //this._usbTetheringAction = TETHERING_STATE_ONGOING;
   1.525 +    this.controlMessage(params, function(data) {
   1.526 +      callback.enableUsbRndisResult(data.result, data.enable);
   1.527 +    });
   1.528 +  },
   1.529 +
   1.530 +  updateUpStream: function(previous, current, callback) {
   1.531 +    let params = {
   1.532 +      cmd: "updateUpStream",
   1.533 +      isAsync: true,
   1.534 +      preInternalIfname: previous.internalIfname,
   1.535 +      preExternalIfname: previous.externalIfname,
   1.536 +      curInternalIfname: current.internalIfname,
   1.537 +      curExternalIfname: current.externalIfname
   1.538 +    };
   1.539 +
   1.540 +    this.controlMessage(params, function(data) {
   1.541 +      let code = data.resultCode;
   1.542 +      let reason = data.resultReason;
   1.543 +      if(DEBUG) debug("updateUpStream result: Code " + code + " reason " + reason);
   1.544 +      callback.updateUpStreamResult(!isError(code), data.curExternalIfname);
   1.545 +    });
   1.546 +  },
   1.547 +
   1.548 +  shutdown: false,
   1.549 +
   1.550 +  observe: function observe(aSubject, aTopic, aData) {
   1.551 +    switch (aTopic) {
   1.552 +      case "xpcom-shutdown":
   1.553 +        debug("NetworkService shutdown");
   1.554 +        this.shutdown = true;
   1.555 +        Services.obs.removeObserver(this, "xpcom-shutdown");
   1.556 +        if (gNetworkWorker) {
   1.557 +          gNetworkWorker.shutdown();
   1.558 +          gNetworkWorker = null;
   1.559 +        }
   1.560 +        break;
   1.561 +    }
   1.562 +  },
   1.563 +};
   1.564 +
   1.565 +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkService]);

mercurial