Bug 1199564 - start/stop mDNS on demand - v3. r=mcmanus
authorKershaw Chang <kechang@mozilla.com>
Thu, 10 Sep 2015 20:03:00 +0200
changeset 294540 8d707bceab14479a09bc10dc13d7afd3969b343c
parent 294539 780bdbf0c0a9ac2ab5d18965f480760f6d5defa8
child 294541 b0c1649e39d2a3cf468f2c9098288aaf177f44ec
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs1199564
milestone43.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 1199564 - start/stop mDNS on demand - v3. r=mcmanus
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp
netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h
--- a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp
+++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp
@@ -2,24 +2,25 @@
 /* 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 "nsDNSServiceDiscovery.h"
 #include <cutils/properties.h>
 #include "MDNSResponderOperator.h"
 #include "nsICancelable.h"
+#include "nsXULAppAPI.h"
 #include "private/pprio.h"
 
 namespace mozilla {
 namespace net {
 
 namespace {
 
-void
+inline void
 StartService()
 {
   char value[PROPERTY_VALUE_MAX] = { '\0' };
   property_get("init.svc.mdnsd", value, "");
 
   if (strcmp(value, "running") == 0) {
     return;
   }
@@ -33,17 +34,49 @@ StopService()
   property_get("init.svc.mdnsd", value, "");
 
   if (strcmp(value, "stopped") == 0) {
     return;
   }
   property_set("ctl.stop", "mdnsd");
 }
 
+class ServiceCounter
+{
+public:
+  static bool IsServiceRunning()
+  {
+    return !!sUseCount;
+  }
+
+private:
+  static uint32_t sUseCount;
+
+protected:
+  ServiceCounter()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    if (!sUseCount++) {
+      StartService();
+    }
+  }
+
+  virtual ~ServiceCounter()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    if (!--sUseCount) {
+      StopService();
+    }
+  }
+};
+
+uint32_t ServiceCounter::sUseCount = 0;
+
 class DiscoveryRequest final : public nsICancelable
+                             , private ServiceCounter
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICANCELABLE
 
   explicit DiscoveryRequest(nsDNSServiceDiscovery* aService,
                             nsIDNSServiceDiscoveryListener* aListener);
 
@@ -70,16 +103,17 @@ DiscoveryRequest::Cancel(nsresult aReaso
     mService->StopDiscovery(mListener);
   }
 
   mService = nullptr;
   return NS_OK;
 }
 
 class RegisterRequest final : public nsICancelable
+                            , private ServiceCounter
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICANCELABLE
 
   explicit RegisterRequest(nsDNSServiceDiscovery* aService,
                            nsIDNSRegistrationListener* aListener);
 
@@ -119,41 +153,44 @@ nsDNSServiceDiscovery::~nsDNSServiceDisc
 #ifdef MOZ_WIDGET_GONK
   StopService();
 #endif
 }
 
 nsresult
 nsDNSServiceDiscovery::Init()
 {
-  StartService();
+  if (!XRE_IsParentProcess()) {
+    MOZ_ASSERT(false, "nsDNSServiceDiscovery can only be used in parent process");
+    return NS_ERROR_FAILURE;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDNSServiceDiscovery::StartDiscovery(const nsACString& aServiceType,
                                       nsIDNSServiceDiscoveryListener* aListener,
                                       nsICancelable** aRetVal)
 {
   MOZ_ASSERT(aRetVal);
 
   nsresult rv;
   if (NS_WARN_IF(NS_FAILED(rv = StopDiscovery(aListener)))) {
     return rv;
   }
 
+  nsCOMPtr<nsICancelable> req = new DiscoveryRequest(this, aListener);
   nsRefPtr<BrowseOperator> browserOp = new BrowseOperator(aServiceType,
                                                           aListener);
   if (NS_WARN_IF(NS_FAILED(rv = browserOp->Start()))) {
     return rv;
   }
 
   mDiscoveryMap.Put(aListener, browserOp);
 
-  nsCOMPtr<nsICancelable> req = new DiscoveryRequest(this, aListener);
   req.forget(aRetVal);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDNSServiceDiscovery::StopDiscovery(nsIDNSServiceDiscoveryListener* aListener)
 {
@@ -180,25 +217,25 @@ nsDNSServiceDiscovery::RegisterService(n
 {
   MOZ_ASSERT(aRetVal);
 
   nsresult rv;
   if (NS_WARN_IF(NS_FAILED(rv = UnregisterService(aListener)))) {
     return rv;
   }
 
+  nsCOMPtr<nsICancelable> req = new RegisterRequest(this, aListener);
   nsRefPtr<RegisterOperator> registerOp = new RegisterOperator(aServiceInfo,
                                                                aListener);
   if (NS_WARN_IF(NS_FAILED(rv = registerOp->Start()))) {
     return rv;
   }
 
   mRegisterMap.Put(aListener, registerOp);
 
-  nsCOMPtr<nsICancelable> req = new RegisterRequest(this, aListener);
   req.forget(aRetVal);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDNSServiceDiscovery::UnregisterService(nsIDNSRegistrationListener* aListener)
 {
@@ -217,16 +254,20 @@ nsDNSServiceDiscovery::UnregisterService
   mRegisterMap.Remove(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDNSServiceDiscovery::ResolveService(nsIDNSServiceInfo* aServiceInfo,
                                       nsIDNSServiceResolveListener* aListener)
 {
+  if (!ServiceCounter::IsServiceRunning()) {
+    return NS_ERROR_FAILURE;
+  }
+
   nsresult rv;
 
   nsRefPtr<ResolveOperator> resolveOp = new ResolveOperator(aServiceInfo,
                                                             aListener);
   if (NS_WARN_IF(NS_FAILED(rv = resolveOp->Start()))) {
     return rv;
   }
 
--- a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h
+++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h
@@ -21,18 +21,18 @@ class nsDNSServiceDiscovery final : publ
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIDNSSERVICEDISCOVERY
 
   explicit nsDNSServiceDiscovery() = default;
 
   /*
-  ** The mDNS service is started in this function. However, the function returns
-  ** without waiting. Therefore, all operations before service started will fail
+  ** The mDNS service is started on demand. If no one uses, mDNS service will not
+  ** start. Therefore, all operations before service started will fail
   ** and get error code |kDNSServiceErr_ServiceNotRunning| defined in dns_sd.h.
   **/
   nsresult Init();
 
   nsresult StopDiscovery(nsIDNSServiceDiscoveryListener* aListener);
   nsresult UnregisterService(nsIDNSRegistrationListener* aListener);
 
 private: