Bug 1115480 - Part 2: Implement mDNS device provider. r=schien

This commit is contained in:
Liang-Heng Chen 2015-05-20 23:06:00 -04:00
parent 0f95d0e95a
commit c3f3d7e3df
8 changed files with 871 additions and 3 deletions

View File

@ -22,7 +22,8 @@ NS_IMPL_ISUPPORTS(PresentationDeviceManager,
nsIPresentationDeviceManager,
nsIPresentationDeviceListener,
nsIPresentationDeviceEventListener,
nsIObserver)
nsIObserver,
nsISupportsWeakReference)
PresentationDeviceManager::PresentationDeviceManager()
{

View File

@ -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

View 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

View 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

View File

@ -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;

View File

@ -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'

View File

@ -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();
}

View File

@ -1,6 +1,5 @@
[DEFAULT]
head =
tail =
[test_multicast_dns_device_provider.js]
[test_presentation_device_manager.js]
[test_tcp_control_channel.js]