diff options
Diffstat (limited to 'netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp')
-rw-r--r-- | netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp | 285 |
1 files changed, 285 insertions, 0 deletions
diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp new file mode 100644 index 000000000..8ffa74b71 --- /dev/null +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.cpp @@ -0,0 +1,285 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "MDNSResponderOperator.h" +#include "nsICancelable.h" +#include "nsXULAppAPI.h" +#include "private/pprio.h" + +#ifdef MOZ_WIDGET_GONK +#include <cutils/properties.h> +#endif // MOZ_WIDGET_GONK + +namespace mozilla { +namespace net { + +namespace { + +inline void +StartService() +{ +#ifdef MOZ_WIDGET_GONK + char value[PROPERTY_VALUE_MAX] = { '\0' }; + property_get("init.svc.mdnsd", value, ""); + + if (strcmp(value, "running") == 0) { + return; + } + property_set("ctl.start", "mdnsd"); +#endif // MOZ_WIDGET_GONK +} + +inline void +StopService() +{ +#ifdef MOZ_WIDGET_GONK + char value[PROPERTY_VALUE_MAX] = { '\0' }; + property_get("init.svc.mdnsd", value, ""); + + if (strcmp(value, "stopped") == 0) { + return; + } + property_set("ctl.stop", "mdnsd"); +#endif // MOZ_WIDGET_GONK +} + +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); + +private: + virtual ~DiscoveryRequest() { Cancel(NS_OK); } + + RefPtr<nsDNSServiceDiscovery> mService; + nsIDNSServiceDiscoveryListener* mListener; +}; + +NS_IMPL_ISUPPORTS(DiscoveryRequest, nsICancelable) + +DiscoveryRequest::DiscoveryRequest(nsDNSServiceDiscovery* aService, + nsIDNSServiceDiscoveryListener* aListener) + : mService(aService) + , mListener(aListener) +{ +} + +NS_IMETHODIMP +DiscoveryRequest::Cancel(nsresult aReason) +{ + if (mService) { + 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); + +private: + virtual ~RegisterRequest() { Cancel(NS_OK); } + + RefPtr<nsDNSServiceDiscovery> mService; + nsIDNSRegistrationListener* mListener; +}; + +NS_IMPL_ISUPPORTS(RegisterRequest, nsICancelable) + +RegisterRequest::RegisterRequest(nsDNSServiceDiscovery* aService, + nsIDNSRegistrationListener* aListener) + : mService(aService) + , mListener(aListener) +{ +} + +NS_IMETHODIMP +RegisterRequest::Cancel(nsresult aReason) +{ + if (mService) { + mService->UnregisterService(mListener); + } + + mService = nullptr; + return NS_OK; +} + +} // namespace anonymous + +NS_IMPL_ISUPPORTS(nsDNSServiceDiscovery, nsIDNSServiceDiscovery) + +nsDNSServiceDiscovery::~nsDNSServiceDiscovery() +{ +#ifdef MOZ_WIDGET_GONK + StopService(); +#endif +} + +nsresult +nsDNSServiceDiscovery::Init() +{ + 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); + RefPtr<BrowseOperator> browserOp = new BrowseOperator(aServiceType, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = browserOp->Start()))) { + return rv; + } + + mDiscoveryMap.Put(aListener, browserOp); + + req.forget(aRetVal); + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::StopDiscovery(nsIDNSServiceDiscoveryListener* aListener) +{ + nsresult rv; + + RefPtr<BrowseOperator> browserOp; + if (!mDiscoveryMap.Get(aListener, getter_AddRefs(browserOp))) { + return NS_OK; + } + + browserOp->Cancel(); // cancel non-started operation + if (NS_WARN_IF(NS_FAILED(rv = browserOp->Stop()))) { + return rv; + } + + mDiscoveryMap.Remove(aListener); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::RegisterService(nsIDNSServiceInfo* aServiceInfo, + nsIDNSRegistrationListener* aListener, + nsICancelable** aRetVal) +{ + MOZ_ASSERT(aRetVal); + + nsresult rv; + if (NS_WARN_IF(NS_FAILED(rv = UnregisterService(aListener)))) { + return rv; + } + + nsCOMPtr<nsICancelable> req = new RegisterRequest(this, aListener); + RefPtr<RegisterOperator> registerOp = new RegisterOperator(aServiceInfo, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = registerOp->Start()))) { + return rv; + } + + mRegisterMap.Put(aListener, registerOp); + + req.forget(aRetVal); + + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::UnregisterService(nsIDNSRegistrationListener* aListener) +{ + nsresult rv; + + RefPtr<RegisterOperator> registerOp; + if (!mRegisterMap.Get(aListener, getter_AddRefs(registerOp))) { + return NS_OK; + } + + registerOp->Cancel(); // cancel non-started operation + if (NS_WARN_IF(NS_FAILED(rv = registerOp->Stop()))) { + return rv; + } + + mRegisterMap.Remove(aListener); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSServiceDiscovery::ResolveService(nsIDNSServiceInfo* aServiceInfo, + nsIDNSServiceResolveListener* aListener) +{ + if (!ServiceCounter::IsServiceRunning()) { + return NS_ERROR_FAILURE; + } + + nsresult rv; + + RefPtr<ResolveOperator> resolveOp = new ResolveOperator(aServiceInfo, + aListener); + if (NS_WARN_IF(NS_FAILED(rv = resolveOp->Start()))) { + return rv; + } + + return NS_OK; +} + +} // namespace net +} // namespace mozilla |