mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1115480 - Part 2: Implement mDNS device provider. r=schien
This commit is contained in:
parent
0f95d0e95a
commit
c3f3d7e3df
@ -22,7 +22,8 @@ NS_IMPL_ISUPPORTS(PresentationDeviceManager,
|
||||
nsIPresentationDeviceManager,
|
||||
nsIPresentationDeviceListener,
|
||||
nsIPresentationDeviceEventListener,
|
||||
nsIObserver)
|
||||
nsIObserver,
|
||||
nsISupportsWeakReference)
|
||||
|
||||
PresentationDeviceManager::PresentationDeviceManager()
|
||||
{
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsIPresentationDeviceManager.h"
|
||||
#include "nsIPresentationDeviceProvider.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -20,6 +21,7 @@ class PresentationDeviceManager final : public nsIPresentationDeviceManager
|
||||
, public nsIPresentationDeviceListener
|
||||
, public nsIPresentationDeviceEventListener
|
||||
, public nsIObserver
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
493
dom/presentation/provider/MulticastDNSDeviceProvider.cpp
Normal file
493
dom/presentation/provider/MulticastDNSDeviceProvider.cpp
Normal file
@ -0,0 +1,493 @@
|
||||
/* -*- 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 "MulticastDNSDeviceProvider.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIPresentationDevice.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
inline static PRLogModuleInfo*
|
||||
GetProviderLog()
|
||||
{
|
||||
static PRLogModuleInfo* log = PR_NewLogModule("MulticastDNSDeviceProvider");
|
||||
return log;
|
||||
}
|
||||
#undef LOG_I
|
||||
#define LOG_I(...) PR_LOG(GetProviderLog(), PR_LOG_NOTICE, (__VA_ARGS__))
|
||||
#undef LOG_E
|
||||
#define LOG_E(...) PR_LOG(GetProviderLog(), PR_LOG_ERROR, (__VA_ARGS__))
|
||||
|
||||
#define SERVICE_TYPE "_mozilla_papi._tcp."
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace presentation {
|
||||
|
||||
/**
|
||||
* This wrapper is used to break circular-reference problem.
|
||||
*/
|
||||
class DNSServiceWrappedListener final
|
||||
: public nsIDNSServiceDiscoveryListener
|
||||
, public nsIDNSRegistrationListener
|
||||
, public nsIDNSServiceResolveListener
|
||||
, public nsITCPPresentationServerListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_FORWARD_SAFE_NSIDNSSERVICEDISCOVERYLISTENER(mListener)
|
||||
NS_FORWARD_SAFE_NSIDNSREGISTRATIONLISTENER(mListener)
|
||||
NS_FORWARD_SAFE_NSIDNSSERVICERESOLVELISTENER(mListener)
|
||||
NS_FORWARD_SAFE_NSITCPPRESENTATIONSERVERLISTENER(mListener)
|
||||
|
||||
explicit DNSServiceWrappedListener() = default;
|
||||
|
||||
nsresult SetListener(MulticastDNSDeviceProvider* aListener)
|
||||
{
|
||||
mListener = aListener;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~DNSServiceWrappedListener() = default;
|
||||
|
||||
MulticastDNSDeviceProvider* mListener = nullptr;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(DNSServiceWrappedListener,
|
||||
nsIDNSServiceDiscoveryListener,
|
||||
nsIDNSRegistrationListener,
|
||||
nsIDNSServiceResolveListener,
|
||||
nsITCPPresentationServerListener)
|
||||
|
||||
NS_IMPL_ISUPPORTS(MulticastDNSDeviceProvider,
|
||||
nsIPresentationDeviceProvider,
|
||||
nsIDNSServiceDiscoveryListener,
|
||||
nsIDNSRegistrationListener,
|
||||
nsIDNSServiceResolveListener,
|
||||
nsITCPPresentationServerListener)
|
||||
|
||||
MulticastDNSDeviceProvider::~MulticastDNSDeviceProvider()
|
||||
{
|
||||
Uninit();
|
||||
}
|
||||
|
||||
nsresult
|
||||
MulticastDNSDeviceProvider::Init()
|
||||
{
|
||||
if (mInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
mMulticastDNS = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mWrappedListener = new DNSServiceWrappedListener();
|
||||
if (NS_WARN_IF(!mWrappedListener)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mWrappedListener->SetListener(this)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mPresentationServer = do_CreateInstance("@mozilla.org/presentation-device/tcp-presentation-server;1", &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(mPresentationServer->SetListener(mWrappedListener)))) {
|
||||
return rv;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->Init(EmptyCString(), 0)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint16_t port = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&port)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv = RegisterService(port)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mInitialized = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MulticastDNSDeviceProvider::Uninit()
|
||||
{
|
||||
if (!mInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mPresentationServer) {
|
||||
mPresentationServer->Close();
|
||||
mPresentationServer = nullptr;
|
||||
}
|
||||
|
||||
if (mDiscoveryRequest) {
|
||||
mDiscoveryRequest->Cancel(NS_OK);
|
||||
mDiscoveryRequest = nullptr;
|
||||
}
|
||||
if (mRegisterRequest) {
|
||||
mRegisterRequest->Cancel(NS_OK);
|
||||
mRegisterRequest = nullptr;
|
||||
}
|
||||
mMulticastDNS = nullptr;
|
||||
|
||||
if (mWrappedListener) {
|
||||
mWrappedListener->SetListener(nullptr);
|
||||
mWrappedListener = nullptr;
|
||||
}
|
||||
|
||||
mInitialized = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MulticastDNSDeviceProvider::RegisterService(uint32_t aPort)
|
||||
{
|
||||
LOG_I("RegisterService: %d", aPort);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIDNSServiceInfo> serviceInfo = do_CreateInstance(DNSSERVICEINFO_CONTRACT_ID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetServiceType(NS_LITERAL_CSTRING(SERVICE_TYPE))))) {
|
||||
return rv;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv = serviceInfo->SetPort(aPort)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mRegisterRequest) {
|
||||
mRegisterRequest->Cancel(NS_OK);
|
||||
mRegisterRequest = nullptr;
|
||||
}
|
||||
return mMulticastDNS->RegisterService(serviceInfo, mWrappedListener, getter_AddRefs(mRegisterRequest));
|
||||
}
|
||||
|
||||
// nsIPresentationDeviceProvider
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::GetListener(nsIPresentationDeviceListener** aListener)
|
||||
{
|
||||
if (NS_WARN_IF(!aListener)) {
|
||||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationDeviceListener> listener = do_QueryReferent(mDeviceListener);
|
||||
listener.forget(aListener);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::SetListener(nsIPresentationDeviceListener* aListener)
|
||||
{
|
||||
mDeviceListener = do_GetWeakReference(aListener);
|
||||
|
||||
nsresult rv;
|
||||
if (mDeviceListener) {
|
||||
if (NS_WARN_IF(NS_FAILED(rv = Init()))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
if (NS_WARN_IF(NS_FAILED(rv = Uninit()))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::ForceDiscovery()
|
||||
{
|
||||
LOG_I("ForceDiscovery");
|
||||
MOZ_ASSERT(mInitialized);
|
||||
MOZ_ASSERT(mMulticastDNS);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (mDiscoveryRequest) {
|
||||
mDiscoveryRequest->Cancel(NS_OK);
|
||||
mDiscoveryRequest = nullptr;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->StartDiscovery(
|
||||
NS_LITERAL_CSTRING(SERVICE_TYPE),
|
||||
mWrappedListener,
|
||||
getter_AddRefs(mDiscoveryRequest))))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIDNSServiceDiscoveryListener
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnDiscoveryStarted(const nsACString& aServiceType)
|
||||
{
|
||||
LOG_I("OnDiscoveryStarted");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnDiscoveryStopped(const nsACString& aServiceType)
|
||||
{
|
||||
LOG_I("OnDiscoveryStopped");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
|
||||
{
|
||||
if (NS_WARN_IF(!aServiceInfo)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult rv ;
|
||||
|
||||
nsAutoCString serviceName;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG_I("OnServiceFound: %s", serviceName.get());
|
||||
|
||||
if (mRegisteredName == serviceName) {
|
||||
LOG_I("ignore self");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationDevice> device;
|
||||
if (NS_SUCCEEDED(mPresentationServer->GetTCPDevice(serviceName,
|
||||
getter_AddRefs(device)))) {
|
||||
LOG_I("device exists");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mMulticastDNS) {
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mMulticastDNS->ResolveService(aServiceInfo, mWrappedListener)))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
|
||||
{
|
||||
if (NS_WARN_IF(!aServiceInfo)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString serviceName;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG_I("OnServiceLost: %s", serviceName.get());
|
||||
|
||||
nsCOMPtr<nsIPresentationDevice> device;
|
||||
if (NS_FAILED(mPresentationServer->GetTCPDevice(serviceName, getter_AddRefs(device)))) {
|
||||
return NS_OK; // ignore non-existing device;
|
||||
}
|
||||
|
||||
NS_WARN_IF(NS_FAILED(mPresentationServer->RemoveTCPDevice(serviceName)));
|
||||
|
||||
nsCOMPtr<nsIPresentationDeviceListener> listener;
|
||||
GetListener(getter_AddRefs(listener));
|
||||
if (listener) {
|
||||
listener->RemoveDevice(device);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
|
||||
{
|
||||
LOG_E("OnStartDiscoveryFailed: %d", aErrorCode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
|
||||
{
|
||||
LOG_E("OnStopDiscoveryFailed: %d", aErrorCode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIDNSRegistrationListener
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo)
|
||||
{
|
||||
if (NS_WARN_IF(!aServiceInfo)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString name;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(name)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG_I("OnServiceRegistered (%s)", name.get());
|
||||
mRegisteredName = name;
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->SetId(name)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo)
|
||||
{
|
||||
LOG_I("OnServiceUnregistered");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
|
||||
{
|
||||
LOG_E("OnRegistrationFailed: %d", aErrorCode);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (aErrorCode == nsIDNSRegistrationListener::ERROR_SERVICE_NOT_RUNNING) {
|
||||
uint16_t port = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&port)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv = RegisterService(port)))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
|
||||
{
|
||||
LOG_E("OnUnregistrationFailed: %d", aErrorCode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIDNSServiceResolveListener
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
|
||||
{
|
||||
if (NS_WARN_IF(!aServiceInfo)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString serviceName;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceName(serviceName)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
LOG_I("OnServiceResolved: %s", serviceName.get());
|
||||
|
||||
nsCOMPtr<nsIPresentationDevice> device;
|
||||
nsCOMPtr<nsIPresentationDeviceListener> listener;
|
||||
GetListener(getter_AddRefs(listener));
|
||||
|
||||
if (NS_SUCCEEDED(mPresentationServer->GetTCPDevice(serviceName,
|
||||
getter_AddRefs(device)))) {
|
||||
NS_WARN_IF(NS_FAILED(mPresentationServer->RemoveTCPDevice(serviceName)));
|
||||
if (listener) {
|
||||
NS_WARN_IF(NS_FAILED(listener->RemoveDevice(device)));
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString host;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetHost(host)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint16_t port;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetPort(&port)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString serviceType;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = aServiceInfo->GetServiceType(serviceType)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->CreateTCPDevice(serviceName,
|
||||
serviceName,
|
||||
serviceType,
|
||||
host,
|
||||
port,
|
||||
getter_AddRefs(device))))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (listener) {
|
||||
listener->AddDevice(device);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
|
||||
{
|
||||
LOG_E("OnResolveFailed: %d", aErrorCode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsITCPPresentationServerListener
|
||||
NS_IMETHODIMP
|
||||
MulticastDNSDeviceProvider::OnClose(nsresult aReason)
|
||||
{
|
||||
LOG_I("OnClose: %x", aReason);
|
||||
|
||||
if (mRegisterRequest) {
|
||||
mRegisterRequest->Cancel(aReason);
|
||||
mRegisterRequest = nullptr;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (NS_FAILED(aReason)) {
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->Init(EmptyCString(), 0)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint16_t port = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&port)))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv = RegisterService(port)))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace presentation
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
64
dom/presentation/provider/MulticastDNSDeviceProvider.h
Normal file
64
dom/presentation/provider/MulticastDNSDeviceProvider.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
|
||||
#define mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICancelable.h"
|
||||
#include "nsIDNSServiceDiscovery.h"
|
||||
#include "nsIPresentationDeviceProvider.h"
|
||||
#include "nsITCPPresentationServer.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWeakPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace presentation {
|
||||
|
||||
class DNSServiceWrappedListener;
|
||||
class MulticastDNSService;
|
||||
|
||||
class MulticastDNSDeviceProvider final
|
||||
: public nsIPresentationDeviceProvider
|
||||
, public nsIDNSServiceDiscoveryListener
|
||||
, public nsIDNSRegistrationListener
|
||||
, public nsIDNSServiceResolveListener
|
||||
, public nsITCPPresentationServerListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPRESENTATIONDEVICEPROVIDER
|
||||
NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
|
||||
NS_DECL_NSIDNSREGISTRATIONLISTENER
|
||||
NS_DECL_NSIDNSSERVICERESOLVELISTENER
|
||||
NS_DECL_NSITCPPRESENTATIONSERVERLISTENER
|
||||
|
||||
explicit MulticastDNSDeviceProvider() = default;
|
||||
nsresult Init();
|
||||
nsresult Uninit();
|
||||
|
||||
private:
|
||||
virtual ~MulticastDNSDeviceProvider();
|
||||
nsresult RegisterService(uint32_t aPort);
|
||||
|
||||
bool mInitialized = false;
|
||||
nsWeakPtr mDeviceListener;
|
||||
nsCOMPtr<nsITCPPresentationServer> mPresentationServer;
|
||||
nsCOMPtr<nsIDNSServiceDiscovery> mMulticastDNS;
|
||||
nsRefPtr<DNSServiceWrappedListener> mWrappedListener;
|
||||
|
||||
nsCOMPtr<nsICancelable> mDiscoveryRequest;
|
||||
nsCOMPtr<nsICancelable> mRegisterRequest;
|
||||
|
||||
nsCString mRegisteredName;
|
||||
};
|
||||
|
||||
} // namespace presentation
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_presentation_provider_MulticastDNSDeviceProvider_h
|
@ -0,0 +1,44 @@
|
||||
/* -*- 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 "MulticastDNSDeviceProvider.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
|
||||
#define MULTICAST_DNS_PROVIDER_CID \
|
||||
{0x814f947a, 0x52f7, 0x41c9, \
|
||||
{ 0x94, 0xa1, 0x36, 0x84, 0x79, 0x72, 0x84, 0xac }}
|
||||
|
||||
#define MULTICAST_DNS_PROVIDER_CONTRACT_ID "@mozilla.org/presentation-device/multicastdns-provider;1"
|
||||
|
||||
using mozilla::dom::presentation::MulticastDNSDeviceProvider;
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(MulticastDNSDeviceProvider)
|
||||
NS_DEFINE_NAMED_CID(MULTICAST_DNS_PROVIDER_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kPresentationDeviceProviderCIDs[] = {
|
||||
{ &kMULTICAST_DNS_PROVIDER_CID, false, nullptr, MulticastDNSDeviceProviderConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kPresentationDeviceProviderContracts[] = {
|
||||
{ MULTICAST_DNS_PROVIDER_CONTRACT_ID, &kMULTICAST_DNS_PROVIDER_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::CategoryEntry kPresentationDeviceProviderCategories[] = {
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 16
|
||||
{ PRESENTATION_DEVICE_PROVIDER_CATEGORY, "MulticastDNSDeviceProvider", MULTICAST_DNS_PROVIDER_CONTRACT_ID},
|
||||
#endif
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module kPresentationDeviceProviderModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kPresentationDeviceProviderCIDs,
|
||||
kPresentationDeviceProviderContracts,
|
||||
kPresentationDeviceProviderCategories
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(PresentationDeviceProviderModule) = &kPresentationDeviceProviderModule;
|
@ -8,3 +8,13 @@ EXTRA_COMPONENTS += [
|
||||
'BuiltinProviders.manifest',
|
||||
'TCPPresentationServer.js'
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'MulticastDNSDeviceProvider.cpp',
|
||||
'PresentationDeviceProviderModule.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
@ -0,0 +1,255 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const INFO_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-info;1";
|
||||
const PROVIDER_CONTRACT_ID = "@mozilla.org/presentation-device/multicastdns-provider;1";
|
||||
const SD_CONTRACT_ID = "@mozilla.org/toolkit/components/mdnsresponder/dns-sd;1";
|
||||
const UUID_CONTRACT_ID = "@mozilla.org/uuid-generator;1";
|
||||
|
||||
let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
function MockFactory(aClass) {
|
||||
this._cls = aClass;
|
||||
}
|
||||
MockFactory.prototype = {
|
||||
createInstance: function(aOuter, aIID) {
|
||||
if (aOuter) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
switch(typeof(this._cls)) {
|
||||
case "function":
|
||||
return new this._cls().QueryInterface(aIID);
|
||||
case "object":
|
||||
return this._cls.QueryInterface(aIID);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
lockFactory: function(aLock) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
|
||||
};
|
||||
|
||||
function ContractHook(aContractID, aClass) {
|
||||
this._contractID = aContractID;
|
||||
this.classID = Cc[UUID_CONTRACT_ID].getService(Ci.nsIUUIDGenerator).generateUUID();
|
||||
this._newFactory = new MockFactory(aClass);
|
||||
|
||||
if (!this.hookedMap.has(this._contractID)) {
|
||||
this.hookedMap.set(this._contractID, new Array());
|
||||
}
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
ContractHook.prototype = {
|
||||
hookedMap: new Map(), // remember only the most original factory.
|
||||
|
||||
init: function() {
|
||||
this.reset();
|
||||
|
||||
let oldContract = this.unregister();
|
||||
this.hookedMap.get(this._contractID).push(oldContract);
|
||||
registrar.registerFactory(this.classID, "", this._contractID, this._newFactory);
|
||||
|
||||
do_register_cleanup(() => { this.cleanup.apply(this); });
|
||||
},
|
||||
|
||||
reset: function() {},
|
||||
|
||||
cleanup: function() {
|
||||
this.reset();
|
||||
|
||||
this.unregister();
|
||||
let prevContract = this.hookedMap.get(this._contractID).pop();
|
||||
|
||||
if (prevContract.factory) {
|
||||
registrar.registerFactory(prevContract.classID, "", this._contractID, prevContract.factory);
|
||||
}
|
||||
},
|
||||
|
||||
unregister: function() {
|
||||
var classID, factory;
|
||||
|
||||
try {
|
||||
classID = registrar.contractIDToCID(this._contractID);
|
||||
factory = Cm.getClassObject(Cc[this._contractID], Ci.nsIFactory);
|
||||
} catch (ex) {
|
||||
classID = "";
|
||||
factory = null;
|
||||
}
|
||||
|
||||
if (factory) {
|
||||
registrar.unregisterFactory(classID, factory);
|
||||
}
|
||||
|
||||
return { classID: classID, factory: factory };
|
||||
}
|
||||
};
|
||||
|
||||
function MockDNSServiceInfo() {}
|
||||
MockDNSServiceInfo.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceInfo]),
|
||||
|
||||
set host(aHost) {
|
||||
this._host = aHost;
|
||||
},
|
||||
|
||||
get host() {
|
||||
return this._host;
|
||||
},
|
||||
|
||||
set port(aPort) {
|
||||
this._port = aPort;
|
||||
},
|
||||
|
||||
get port() {
|
||||
return this._port;
|
||||
},
|
||||
|
||||
set serviceName(aServiceName) {
|
||||
this._serviceName = aServiceName;
|
||||
},
|
||||
|
||||
get serviceName() {
|
||||
return this._serviceName;
|
||||
},
|
||||
|
||||
set serviceType(aServiceType) {
|
||||
this._serviceType = aServiceType;
|
||||
},
|
||||
|
||||
get serviceType() {
|
||||
return this._serviceType;
|
||||
},
|
||||
|
||||
set domainName(aDomainName) {
|
||||
this._domainName = aDomainName;
|
||||
},
|
||||
|
||||
get domainName() {
|
||||
return this._domainName;
|
||||
},
|
||||
|
||||
set attributes(aAttributes) {
|
||||
this._attributes = aAttributes;
|
||||
},
|
||||
|
||||
get attributes() {
|
||||
return this._attributes;
|
||||
}
|
||||
};
|
||||
|
||||
function TestPresentationDeviceListener() {}
|
||||
TestPresentationDeviceListener.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener]),
|
||||
|
||||
addDevice: function(device) {},
|
||||
removeDevice: function(device) {},
|
||||
updateDevice: function(device) {}
|
||||
};
|
||||
|
||||
function createDevice(host, port, serviceName, serviceType, domainName, attributes) {
|
||||
let device = new MockDNSServiceInfo();
|
||||
device.host = host || "";
|
||||
device.port = port || 0;
|
||||
device.serviceName = serviceName || "";
|
||||
device.serviceType = serviceType || "";
|
||||
device.domainName = domainName || "";
|
||||
device.attributes = attributes || null;
|
||||
return device;
|
||||
}
|
||||
|
||||
function registerService() {
|
||||
let mockObj = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
|
||||
startDiscovery: function(serviceType, listener) {},
|
||||
registerService: function(serviceInfo, listener) {
|
||||
this.serviceRegistered++;
|
||||
return {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
|
||||
cancel: function() {
|
||||
this.serviceUnregistered++;
|
||||
}.bind(this)
|
||||
}
|
||||
},
|
||||
resolveService: function(serviceInfo, listener) {},
|
||||
serviceRegistered: 0,
|
||||
serviceUnregistered: 0
|
||||
};
|
||||
let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
|
||||
|
||||
Assert.equal(mockObj.serviceRegistered, 0);
|
||||
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
|
||||
Assert.equal(mockObj.serviceRegistered, 0);
|
||||
provider.listener = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener, Ci.nsISupportsWeakReference]),
|
||||
addDevice: function(device) {},
|
||||
removeDevice: function(device) {},
|
||||
updateDevice: function(device) {},
|
||||
};
|
||||
Assert.equal(mockObj.serviceRegistered, 1);
|
||||
|
||||
Assert.equal(mockObj.serviceUnregistered, 0);
|
||||
provider.listener = null;
|
||||
Assert.equal(mockObj.serviceUnregistered, 1);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function addDevice() {
|
||||
let mockDevice = createDevice("device.local", 12345, "service.name", "_mozilla_papi._tcp");
|
||||
let mockObj = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
|
||||
startDiscovery: function(serviceType, listener) {
|
||||
listener.onDiscoveryStarted(serviceType);
|
||||
listener.onServiceFound(createDevice("", 0, mockDevice.serviceName, mockDevice.serviceType));
|
||||
return {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
|
||||
cancel: function() {}
|
||||
}
|
||||
},
|
||||
registerService: function(serviceInfo, listener) {},
|
||||
resolveService: function(serviceInfo, listener) {
|
||||
Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
|
||||
Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
|
||||
listener.onServiceResolved(createDevice(mockDevice.host, mockDevice.port, mockDevice.serviceName, mockDevice.serviceType));
|
||||
}
|
||||
};
|
||||
let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
|
||||
|
||||
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
|
||||
let listener = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener, Ci.nsISupportsWeakReference]),
|
||||
addDevice: function(device) { this.devices.push(device); },
|
||||
removeDevice: function(device) {},
|
||||
updateDevice: function(device) {},
|
||||
devices: []
|
||||
};
|
||||
provider.listener = listener;
|
||||
|
||||
Assert.equal(listener.devices.length, 0);
|
||||
provider.forceDiscovery();
|
||||
Assert.equal(listener.devices.length, 1);
|
||||
|
||||
provider.listener = null;
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
let infoHook = new ContractHook(INFO_CONTRACT_ID, MockDNSServiceInfo);
|
||||
|
||||
add_test(registerService);
|
||||
add_test(addDevice);
|
||||
|
||||
run_next_test();
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
|
||||
[test_multicast_dns_device_provider.js]
|
||||
[test_presentation_device_manager.js]
|
||||
[test_tcp_control_channel.js]
|
||||
|
Loading…
Reference in New Issue
Block a user