summaryrefslogtreecommitdiffstats
path: root/dom/flyweb/FlyWebService.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/flyweb/FlyWebService.cpp')
-rw-r--r--dom/flyweb/FlyWebService.cpp1310
1 files changed, 0 insertions, 1310 deletions
diff --git a/dom/flyweb/FlyWebService.cpp b/dom/flyweb/FlyWebService.cpp
deleted file mode 100644
index 5f3b0d66f..000000000
--- a/dom/flyweb/FlyWebService.cpp
+++ /dev/null
@@ -1,1310 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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 "mozilla/dom/FlyWebService.h"
-#include "mozilla/ClearOnShutdown.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/ScopeExit.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/dom/FlyWebPublishedServerIPC.h"
-#include "mozilla/AddonPathService.h"
-#include "nsISocketTransportService.h"
-#include "mdns/libmdns/nsDNSServiceInfo.h"
-#include "nsIUUIDGenerator.h"
-#include "nsStandardURL.h"
-#include "mozilla/Services.h"
-#include "nsISupportsPrimitives.h"
-#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
-#include "prnetdb.h"
-#include "DNS.h"
-#include "nsContentPermissionHelper.h"
-#include "nsSocketTransportService2.h"
-#include "nsSocketTransport2.h"
-#include "nsHashPropertyBag.h"
-#include "nsNetUtil.h"
-#include "nsISimpleEnumerator.h"
-#include "nsIProperty.h"
-#include "nsICertOverrideService.h"
-
-namespace mozilla {
-namespace dom {
-
-struct FlyWebPublishOptions;
-
-static LazyLogModule gFlyWebServiceLog("FlyWebService");
-#undef LOG_I
-#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
-
-#undef LOG_E
-#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__))
-
-#undef LOG_TEST_I
-#define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug)
-
-class FlyWebPublishServerPermissionCheck final
- : public nsIContentPermissionRequest
- , public nsIRunnable
-{
-public:
- NS_DECL_ISUPPORTS
-
- FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID,
- FlyWebPublishedServer* aServer)
- : mServiceName(aServiceName)
- , mWindowID(aWindowID)
- , mServer(aServer)
- {}
-
- uint64_t WindowID() const
- {
- return mWindowID;
- }
-
- NS_IMETHOD Run() override
- {
- MOZ_ASSERT(NS_IsMainThread());
-
- nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
- if (!globalWindow) {
- return Cancel();
- }
- mWindow = globalWindow->AsInner();
- if (NS_WARN_IF(!mWindow)) {
- return Cancel();
- }
-
- nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
- if (NS_WARN_IF(!doc)) {
- return Cancel();
- }
-
- mPrincipal = doc->NodePrincipal();
- MOZ_ASSERT(mPrincipal);
-
- mRequester = new nsContentPermissionRequester(mWindow);
- return nsContentPermissionUtils::AskPermission(this, mWindow);
- }
-
- NS_IMETHOD Cancel() override
- {
- Resolve(false);
- return NS_OK;
- }
-
- NS_IMETHOD Allow(JS::HandleValue aChoices) override
- {
- MOZ_ASSERT(aChoices.isUndefined());
- Resolve(true);
- return NS_OK;
- }
-
- NS_IMETHOD GetTypes(nsIArray** aTypes) override
- {
- nsTArray<nsString> emptyOptions;
- return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"),
- NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes);
- }
-
- NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override
- {
- NS_ENSURE_ARG_POINTER(aRequester);
- nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
- requester.forget(aRequester);
- return NS_OK;
- }
-
- NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override
- {
- NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
- return NS_OK;
- }
-
- NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override
- {
- NS_IF_ADDREF(*aRequestingWindow = mWindow);
- return NS_OK;
- }
-
- NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override
- {
- *aRequestingElement = nullptr;
- return NS_OK;
- }
-
-private:
- void Resolve(bool aResolve)
- {
- mServer->PermissionGranted(aResolve);
- }
-
- virtual ~FlyWebPublishServerPermissionCheck() = default;
-
- nsCString mServiceName;
- uint64_t mWindowID;
- RefPtr<FlyWebPublishedServer> mServer;
- nsCOMPtr<nsPIDOMWindowInner> mWindow;
- nsCOMPtr<nsIPrincipal> mPrincipal;
- nsCOMPtr<nsIContentPermissionRequester> mRequester;
-};
-
-NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck,
- nsIContentPermissionRequest,
- nsIRunnable)
-
-class FlyWebMDNSService final
- : public nsIDNSServiceDiscoveryListener
- , public nsIDNSServiceResolveListener
- , public nsIDNSRegistrationListener
- , public nsITimerCallback
-{
- friend class FlyWebService;
-
-private:
- enum DiscoveryState {
- DISCOVERY_IDLE,
- DISCOVERY_STARTING,
- DISCOVERY_RUNNING,
- DISCOVERY_STOPPING
- };
-
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
- NS_DECL_NSIDNSSERVICERESOLVELISTENER
- NS_DECL_NSIDNSREGISTRATIONLISTENER
- NS_DECL_NSITIMERCALLBACK
-
- explicit FlyWebMDNSService(FlyWebService* aService,
- const nsACString& aServiceType);
-
-private:
- virtual ~FlyWebMDNSService() = default;
-
- nsresult Init();
- nsresult StartDiscovery();
- nsresult StopDiscovery();
-
- void ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices);
- bool HasService(const nsAString& aServiceId);
- nsresult PairWithService(const nsAString& aServiceId,
- UniquePtr<FlyWebService::PairedInfo>& aInfo);
-
- nsresult StartDiscoveryOf(FlyWebPublishedServerImpl* aServer);
-
- void EnsureDiscoveryStarted();
- void EnsureDiscoveryStopped();
-
- // Cycle-breaking link to manager.
- FlyWebService* mService;
- nsCString mServiceType;
-
- // Indicates the desired state of the system. If mDiscoveryActive is true,
- // it indicates that backend discovery "should be happening", and discovery
- // events should be forwarded to listeners.
- // If false, the backend discovery "should be idle", and any discovery events
- // that show up should not be forwarded to listeners.
- bool mDiscoveryActive;
-
- uint32_t mNumConsecutiveStartDiscoveryFailures;
-
- // Represents the internal discovery state as it relates to nsDNSServiceDiscovery.
- // When mDiscoveryActive is true, this state will periodically loop from
- // (IDLE => STARTING => RUNNING => STOPPING => IDLE).
- DiscoveryState mDiscoveryState;
-
- nsCOMPtr<nsITimer> mDiscoveryStartTimer;
- nsCOMPtr<nsITimer> mDiscoveryStopTimer;
- nsCOMPtr<nsIDNSServiceDiscovery> mDNSServiceDiscovery;
- nsCOMPtr<nsICancelable> mCancelDiscovery;
- nsTHashtable<nsStringHashKey> mNewServiceSet;
-
- struct DiscoveredInfo
- {
- explicit DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo);
- FlyWebDiscoveredService mService;
- nsCOMPtr<nsIDNSServiceInfo> mDNSServiceInfo;
- };
- nsClassHashtable<nsStringHashKey, DiscoveredInfo> mServiceMap;
-};
-
-void
-LogDNSInfo(nsIDNSServiceInfo* aServiceInfo, const char* aFunc)
-{
- if (!LOG_TEST_I()) {
- return;
- }
-
- nsCString tmp;
- aServiceInfo->GetServiceName(tmp);
- LOG_I("%s: serviceName=%s", aFunc, tmp.get());
-
- aServiceInfo->GetHost(tmp);
- LOG_I("%s: host=%s", aFunc, tmp.get());
-
- aServiceInfo->GetAddress(tmp);
- LOG_I("%s: address=%s", aFunc, tmp.get());
-
- uint16_t port = -2;
- aServiceInfo->GetPort(&port);
- LOG_I("%s: port=%d", aFunc, (int)port);
-
- nsCOMPtr<nsIPropertyBag2> attributes;
- aServiceInfo->GetAttributes(getter_AddRefs(attributes));
- if (!attributes) {
- LOG_I("%s: no attributes", aFunc);
- } else {
- nsCOMPtr<nsISimpleEnumerator> enumerator;
- attributes->GetEnumerator(getter_AddRefs(enumerator));
- MOZ_ASSERT(enumerator);
-
- LOG_I("%s: attributes start", aFunc);
-
- bool hasMoreElements;
- while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) &&
- hasMoreElements) {
- nsCOMPtr<nsISupports> element;
- MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element)));
- nsCOMPtr<nsIProperty> property = do_QueryInterface(element);
- MOZ_ASSERT(property);
-
- nsAutoString name;
- nsCOMPtr<nsIVariant> value;
- MOZ_ALWAYS_SUCCEEDS(property->GetName(name));
- MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value)));
-
- nsAutoCString str;
- nsresult rv = value->GetAsACString(str);
- if (NS_SUCCEEDED(rv)) {
- LOG_I("%s: attribute name=%s value=%s", aFunc,
- NS_ConvertUTF16toUTF8(name).get(), str.get());
- } else {
- uint16_t type;
- MOZ_ALWAYS_SUCCEEDS(value->GetDataType(&type));
- LOG_I("%s: attribute *unstringifiable* name=%s type=%d", aFunc,
- NS_ConvertUTF16toUTF8(name).get(), (int)type);
- }
- }
-
- LOG_I("%s: attributes end", aFunc);
- }
-}
-
-NS_IMPL_ISUPPORTS(FlyWebMDNSService,
- nsIDNSServiceDiscoveryListener,
- nsIDNSServiceResolveListener,
- nsIDNSRegistrationListener,
- nsITimerCallback)
-
-FlyWebMDNSService::FlyWebMDNSService(
- FlyWebService* aService,
- const nsACString& aServiceType)
- : mService(aService)
- , mServiceType(aServiceType)
- , mDiscoveryActive(false)
- , mNumConsecutiveStartDiscoveryFailures(0)
- , mDiscoveryState(DISCOVERY_IDLE)
-{}
-
-nsresult
-FlyWebMDNSService::OnDiscoveryStarted(const nsACString& aServiceType)
-{
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
- mDiscoveryState = DISCOVERY_RUNNING;
- // Reset consecutive start discovery failures.
- mNumConsecutiveStartDiscoveryFailures = 0;
- LOG_I("===========================================");
- LOG_I("MDNSService::OnDiscoveryStarted(%s)", PromiseFlatCString(aServiceType).get());
- LOG_I("===========================================");
-
- // Clear the new service array.
- mNewServiceSet.Clear();
-
- // If service discovery is inactive, then stop network discovery immediately.
- if (!mDiscoveryActive) {
- // Set the stop timer to fire immediately.
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
- return NS_OK;
- }
-
- // Otherwise, set the stop timer to fire in 5 seconds.
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT)));
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnDiscoveryStopped(const nsACString& aServiceType)
-{
- LOG_I("///////////////////////////////////////////");
- LOG_I("MDNSService::OnDiscoveryStopped(%s)", PromiseFlatCString(aServiceType).get());
- LOG_I("///////////////////////////////////////////");
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
- mDiscoveryState = DISCOVERY_IDLE;
-
- // If service discovery is inactive, then discard all results and do not proceed.
- if (!mDiscoveryActive) {
- mServiceMap.Clear();
- mNewServiceSet.Clear();
- return NS_OK;
- }
-
- // Process the service map, add to the pair map.
- for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
- DiscoveredInfo* service = iter.UserData();
-
- if (!mNewServiceSet.Contains(service->mService.mServiceId)) {
- iter.Remove();
- }
- }
-
- // Notify FlyWebService of changed service list.
- mService->NotifyDiscoveredServicesChanged();
-
- // Start discovery again immediately.
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceFound");
-
- // If discovery is not active, don't do anything with the result.
- // If there is no discovery underway, ignore this.
- if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
- return NS_OK;
- }
-
- // Discovery is underway - resolve the service.
- nsresult rv = mDNSServiceDiscovery->ResolveService(aServiceInfo, this);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceLost");
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
-{
- LOG_E("MDNSService::OnStartDiscoveryFailed(%s): %d", PromiseFlatCString(aServiceType).get(), (int) aErrorCode);
-
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
- mDiscoveryState = DISCOVERY_IDLE;
- mNumConsecutiveStartDiscoveryFailures++;
-
- // If discovery is active, and the number of consecutive failures is < 3, try starting again.
- if (mDiscoveryActive && mNumConsecutiveStartDiscoveryFailures < 3) {
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
- }
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
-{
- LOG_E("MDNSService::OnStopDiscoveryFailed(%s)", PromiseFlatCString(aServiceType).get());
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
- mDiscoveryState = DISCOVERY_IDLE;
-
- // If discovery is active, start discovery again immediately.
- if (mDiscoveryActive) {
- Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
- }
-
- return NS_OK;
-}
-
-static bool
-IsAcceptableServiceAddress(const nsCString& addr)
-{
- PRNetAddr prNetAddr;
- PRStatus status = PR_StringToNetAddr(addr.get(), &prNetAddr);
- if (status == PR_FAILURE) {
- return false;
- }
- // Only allow ipv4 addreses for now.
- return prNetAddr.raw.family == PR_AF_INET;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceResolved");
-
- // If discovery is not active, don't do anything with the result.
- // If there is no discovery underway, ignore this resolve.
- if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
- return NS_OK;
- }
-
- nsresult rv;
-
- nsCString address;
- rv = aServiceInfo->GetAddress(address);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (!IsAcceptableServiceAddress(address)) {
- return NS_OK;
- }
-
- // Create a new serviceInfo and stuff it in the new service array.
- UniquePtr<DiscoveredInfo> svc(new DiscoveredInfo(aServiceInfo));
- mNewServiceSet.PutEntry(svc->mService.mServiceId);
-
- DiscoveredInfo* existingSvc =
- mServiceMap.Get(svc->mService.mServiceId);
- if (existingSvc) {
- // Update the underlying DNS service info, but leave the old object in place.
- existingSvc->mDNSServiceInfo = aServiceInfo;
- } else {
- DiscoveredInfo* info = svc.release();
- mServiceMap.Put(info->mService.mServiceId, info);
- }
-
- // Notify FlyWebService of changed service list.
- mService->NotifyDiscoveredServicesChanged();
-
- return NS_OK;
-}
-
-FlyWebMDNSService::DiscoveredInfo::DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo)
- : mDNSServiceInfo(aDNSServiceInfo)
-{
- nsCString tmp;
- DebugOnly<nsresult> drv = aDNSServiceInfo->GetServiceName(tmp);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- CopyUTF8toUTF16(tmp, mService.mDisplayName);
-
- mService.mTransport = NS_LITERAL_STRING("mdns");
-
- drv = aDNSServiceInfo->GetServiceType(tmp);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- CopyUTF8toUTF16(tmp, mService.mServiceType);
-
- nsCOMPtr<nsIPropertyBag2> attrs;
- drv = aDNSServiceInfo->GetAttributes(getter_AddRefs(attrs));
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- if (attrs) {
- attrs->GetPropertyAsAString(NS_LITERAL_STRING("cert"), mService.mCert);
- attrs->GetPropertyAsAString(NS_LITERAL_STRING("path"), mService.mPath);
- }
-
- // Construct a service id from the name, host, address, and port.
- nsCString cHost;
- drv = aDNSServiceInfo->GetHost(cHost);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
-
- nsCString cAddress;
- drv = aDNSServiceInfo->GetAddress(cAddress);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
-
- uint16_t port;
- drv = aDNSServiceInfo->GetPort(&port);
- MOZ_ASSERT(NS_SUCCEEDED(drv));
- nsAutoString portStr;
- portStr.AppendInt(port, 10);
-
- mService.mServiceId =
- NS_ConvertUTF8toUTF16(cAddress) +
- NS_LITERAL_STRING(":") +
- portStr +
- NS_LITERAL_STRING("|") +
- mService.mServiceType +
- NS_LITERAL_STRING("|") +
- NS_ConvertUTF8toUTF16(cHost) +
- NS_LITERAL_STRING("|") +
- mService.mDisplayName;
-}
-
-
-nsresult
-FlyWebMDNSService::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnResolveFailed");
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceRegistered");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- existingServer->PublishedServerStarted(NS_OK);
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceUnregistered");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- LOG_I("OnServiceRegistered(MDNS): De-advertised server with name %s.", cName.get());
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnRegistrationFailed");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- LOG_I("OnServiceRegistered(MDNS): Registration of server with name %s failed.", cName.get());
-
- // Remove the nsICancelable from the published server.
- existingServer->PublishedServerStarted(NS_ERROR_FAILURE);
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
-{
- LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnUnregistrationFailed");
-
- nsCString cName;
- if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
- return NS_ERROR_FAILURE;
- }
-
- nsString name = NS_ConvertUTF8toUTF16(cName);
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
- if (!existingServer) {
- return NS_ERROR_FAILURE;
- }
-
- LOG_I("OnServiceRegistered(MDNS): Un-Advertisement of server with name %s failed.", cName.get());
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::Notify(nsITimer* timer)
-{
- if (timer == mDiscoveryStopTimer.get()) {
- LOG_I("MDNSService::Notify() got discovery stop timeout");
- // Internet discovery stop timer has fired.
- nsresult rv = StopDiscovery();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
-
- if (timer == mDiscoveryStartTimer.get()) {
- LOG_I("MDNSService::Notify() got discovery start timeout");
- // Internet discovery start timer has fired.
- nsresult rv = StartDiscovery();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return NS_OK;
- }
-
- LOG_E("MDNSService::Notify got unknown timeout.");
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::Init()
-{
- MOZ_ASSERT(mDiscoveryState == DISCOVERY_IDLE);
-
- mDiscoveryStartTimer = do_CreateInstance("@mozilla.org/timer;1");
- if (!mDiscoveryStartTimer) {
- return NS_ERROR_FAILURE;
- }
-
- mDiscoveryStopTimer = do_CreateInstance("@mozilla.org/timer;1");
- if (!mDiscoveryStopTimer) {
- return NS_ERROR_FAILURE;
- }
-
- nsresult rv;
- mDNSServiceDiscovery = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::StartDiscovery()
-{
- nsresult rv;
-
- // Always cancel the timer.
- rv = mDiscoveryStartTimer->Cancel();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to cancel DNS service discovery start timer.");
- }
-
- // If discovery is not idle, don't start it.
- if (mDiscoveryState != DISCOVERY_IDLE) {
- return NS_OK;
- }
-
- LOG_I("FlyWeb starting dicovery.");
- mDiscoveryState = DISCOVERY_STARTING;
-
- // start the discovery.
- rv = mDNSServiceDiscovery->StartDiscovery(mServiceType, this,
- getter_AddRefs(mCancelDiscovery));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to start DNS service discovery.");
- return rv;
- }
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::StopDiscovery()
-{
- nsresult rv;
-
- // Always cancel the timer.
- rv = mDiscoveryStopTimer->Cancel();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to cancel DNS service discovery stop timer.");
- }
-
- // If discovery is not running, do nothing.
- if (mDiscoveryState != DISCOVERY_RUNNING) {
- return NS_OK;
- }
-
- LOG_I("FlyWeb stopping dicovery.");
-
- // Mark service discovery as stopping.
- mDiscoveryState = DISCOVERY_STOPPING;
-
- if (mCancelDiscovery) {
- LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery exists!");
- nsCOMPtr<nsICancelable> cancelDiscovery = mCancelDiscovery.forget();
- rv = cancelDiscovery->Cancel(NS_ERROR_ABORT);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("FlyWeb failed to cancel DNS stop service discovery.");
- }
- } else {
- LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery does not exist!");
- mDiscoveryState = DISCOVERY_IDLE;
- }
-
- return NS_OK;
-}
-
-void
-FlyWebMDNSService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
-{
- for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
- aServices.AppendElement(iter.UserData()->mService);
- }
-}
-
-bool
-FlyWebMDNSService::HasService(const nsAString& aServiceId)
-{
- return mServiceMap.Contains(aServiceId);
-}
-
-nsresult
-FlyWebMDNSService::PairWithService(const nsAString& aServiceId,
- UniquePtr<FlyWebService::PairedInfo>& aInfo)
-{
- MOZ_ASSERT(HasService(aServiceId));
-
- nsresult rv;
- nsCOMPtr<nsIUUIDGenerator> uuidgen =
- do_GetService("@mozilla.org/uuid-generator;1", &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsID id;
- rv = uuidgen->GenerateUUIDInPlace(&id);
- NS_ENSURE_SUCCESS(rv, rv);
-
- aInfo.reset(new FlyWebService::PairedInfo());
-
- char uuidChars[NSID_LENGTH];
- id.ToProvidedString(uuidChars);
- CopyUTF8toUTF16(Substring(uuidChars + 1, uuidChars + NSID_LENGTH - 2),
- aInfo->mService.mHostname);
-
- DiscoveredInfo* discInfo = mServiceMap.Get(aServiceId);
-
- nsAutoString url;
- if (discInfo->mService.mCert.IsEmpty()) {
- url.AssignLiteral("http://");
- } else {
- url.AssignLiteral("https://");
- }
- url.Append(aInfo->mService.mHostname + NS_LITERAL_STRING("/"));
- nsCOMPtr<nsIURI> uiURL;
- NS_NewURI(getter_AddRefs(uiURL), url);
- MOZ_ASSERT(uiURL);
- if (!discInfo->mService.mPath.IsEmpty()) {
- nsCOMPtr<nsIURI> tmp = uiURL.forget();
- NS_NewURI(getter_AddRefs(uiURL), discInfo->mService.mPath, nullptr, tmp);
- }
- if (uiURL) {
- nsAutoCString spec;
- uiURL->GetSpec(spec);
- CopyUTF8toUTF16(spec, aInfo->mService.mUiUrl);
- }
-
- aInfo->mService.mDiscoveredService = discInfo->mService;
- aInfo->mDNSServiceInfo = discInfo->mDNSServiceInfo;
-
- return NS_OK;
-}
-
-nsresult
-FlyWebMDNSService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
-{
-
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(aServer->Name());
- MOZ_ASSERT(existingServer);
-
- // Advertise the service via mdns.
- RefPtr<net::nsDNSServiceInfo> serviceInfo(new net::nsDNSServiceInfo());
-
- serviceInfo->SetPort(aServer->Port());
- serviceInfo->SetServiceType(mServiceType);
-
- nsCString certKey;
- aServer->GetCertKey(certKey);
- nsString uiURL;
- aServer->GetUiUrl(uiURL);
-
- if (!uiURL.IsEmpty() || !certKey.IsEmpty()) {
- RefPtr<nsHashPropertyBag> attrs = new nsHashPropertyBag();
- if (!uiURL.IsEmpty()) {
- attrs->SetPropertyAsAString(NS_LITERAL_STRING("path"), uiURL);
- }
- if (!certKey.IsEmpty()) {
- attrs->SetPropertyAsACString(NS_LITERAL_STRING("cert"), certKey);
- }
- serviceInfo->SetAttributes(attrs);
- }
-
- nsCString cstrName = NS_ConvertUTF16toUTF8(aServer->Name());
- LOG_I("MDNSService::StartDiscoveryOf() advertising service %s", cstrName.get());
- serviceInfo->SetServiceName(cstrName);
-
- LogDNSInfo(serviceInfo, "FlyWebMDNSService::StartDiscoveryOf");
-
- // Advertise the service.
- nsCOMPtr<nsICancelable> cancelRegister;
- nsresult rv = mDNSServiceDiscovery->
- RegisterService(serviceInfo, this, getter_AddRefs(cancelRegister));
- NS_ENSURE_SUCCESS(rv, rv);
-
- // All done.
- aServer->SetCancelRegister(cancelRegister);
-
- return NS_OK;
-}
-
-void
-FlyWebMDNSService::EnsureDiscoveryStarted()
-{
- mDiscoveryActive = true;
- // If state is idle, start discovery immediately.
- if (mDiscoveryState == DISCOVERY_IDLE) {
- StartDiscovery();
- }
-}
-
-void
-FlyWebMDNSService::EnsureDiscoveryStopped()
-{
- // All we need to do is set the flag to false.
- // If current state is IDLE, it's already the correct state.
- // Otherwise, the handlers for the internal state
- // transitions will check this flag and drive the state
- // towards IDLE.
- mDiscoveryActive = false;
-}
-
-static StaticRefPtr<FlyWebService> gFlyWebService;
-
-NS_IMPL_ISUPPORTS(FlyWebService, nsIObserver)
-
-FlyWebService::FlyWebService()
- : mMonitor("FlyWebService::mMonitor")
-{
- MOZ_ASSERT(NS_IsMainThread());
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->AddObserver(this, "inner-window-destroyed", false);
- }
-}
-
-FlyWebService::~FlyWebService()
-{
-}
-
-FlyWebService*
-FlyWebService::GetExisting()
-{
- return gFlyWebService;
-}
-
-FlyWebService*
-FlyWebService::GetOrCreate()
-{
- if (!gFlyWebService) {
- gFlyWebService = new FlyWebService();
- ClearOnShutdown(&gFlyWebService);
- ErrorResult rv = gFlyWebService->Init();
- if (rv.Failed()) {
- gFlyWebService = nullptr;
- return nullptr;
- }
- }
- return gFlyWebService;
-}
-
-ErrorResult
-FlyWebService::Init()
-{
- // Most functions of FlyWebService should not be started in the child.
- // Instead FlyWebService in the child is mainly responsible for tracking
- // publishedServer lifetimes. Other functions are handled by the
- // FlyWebService running in the parent.
- if (XRE_GetProcessType() == GeckoProcessType_Content) {
- return ErrorResult(NS_OK);
- }
-
- MOZ_ASSERT(NS_IsMainThread());
- if (!mMDNSHttpService) {
- mMDNSHttpService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_http._tcp."));
- ErrorResult rv;
-
- rv = mMDNSHttpService->Init();
- if (rv.Failed()) {
- LOG_E("FlyWebService failed to initialize MDNS _http._tcp.");
- mMDNSHttpService = nullptr;
- rv.SuppressException();
- }
- }
-
- if (!mMDNSFlywebService) {
- mMDNSFlywebService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_flyweb._tcp."));
- ErrorResult rv;
-
- rv = mMDNSFlywebService->Init();
- if (rv.Failed()) {
- LOG_E("FlyWebService failed to initialize MDNS _flyweb._tcp.");
- mMDNSFlywebService = nullptr;
- rv.SuppressException();
- }
- }
-
- return ErrorResult(NS_OK);
-}
-
-static already_AddRefed<FlyWebPublishPromise>
-MakeRejectionPromise(const char* name)
-{
- MozPromiseHolder<FlyWebPublishPromise> holder;
- RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name);
- holder.Reject(NS_ERROR_FAILURE, name);
- return promise.forget();
-}
-
-static bool
-CheckForFlyWebAddon(const nsACString& uriString)
-{
- // Before proceeding, ensure that the FlyWeb system addon exists.
- nsresult rv;
- nsCOMPtr<nsIURI> uri;
- rv = NS_NewURI(getter_AddRefs(uri), uriString);
- if (NS_FAILED(rv)) {
- return false;
- }
-
- JSAddonId *addonId = MapURIToAddonID(uri);
- if (!addonId) {
- return false;
- }
-
- JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
- nsAutoString addonIdString;
- AssignJSFlatString(addonIdString, flat);
- if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) {
- nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString);
- return false;
- }
-
- return true;
-}
-
-already_AddRefed<FlyWebPublishPromise>
-FlyWebService::PublishServer(const nsAString& aName,
- const FlyWebPublishOptions& aOptions,
- nsPIDOMWindowInner* aWindow)
-{
- // Scan uiUrl for illegal characters
-
- RefPtr<FlyWebPublishedServer> existingServer =
- FlyWebService::GetOrCreate()->FindPublishedServerByName(aName);
- if (existingServer) {
- LOG_I("PublishServer: Trying to publish server with already-existing name %s.",
- NS_ConvertUTF16toUTF8(aName).get());
- return MakeRejectionPromise(__func__);
- }
-
- RefPtr<FlyWebPublishedServer> server;
- if (XRE_GetProcessType() == GeckoProcessType_Content) {
- server = new FlyWebPublishedServerChild(aWindow, aName, aOptions);
- } else {
- server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions);
-
- // Before proceeding, ensure that the FlyWeb system addon exists.
- if (!CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png")) &&
- !CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/content/icon-64.png")))
- {
- LOG_E("PublishServer: Failed to find FlyWeb system addon.");
- return MakeRejectionPromise(__func__);
- }
- }
-
- if (aWindow) {
- nsresult rv;
-
- MOZ_ASSERT(NS_IsMainThread());
- rv = NS_DispatchToCurrentThread(
- MakeAndAddRef<FlyWebPublishServerPermissionCheck>(
- NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- LOG_E("PublishServer: Failed to dispatch permission check runnable for %s",
- NS_ConvertUTF16toUTF8(aName).get());
- return MakeRejectionPromise(__func__);
- }
- } else {
- // If aWindow is null, we're definitely in the e10s parent process.
- // In this case, we know that permission has already been granted
- // by the user because of content-process prompt.
- MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
- server->PermissionGranted(true);
- }
-
- mServers.AppendElement(server);
-
- return server->GetPublishPromise();
-}
-
-already_AddRefed<FlyWebPublishedServer>
-FlyWebService::FindPublishedServerByName(
- const nsAString& aName)
-{
- MOZ_ASSERT(NS_IsMainThread());
- for (FlyWebPublishedServer* publishedServer : mServers) {
- if (publishedServer->Name().Equals(aName)) {
- RefPtr<FlyWebPublishedServer> server = publishedServer;
- return server.forget();
- }
- }
- return nullptr;
-}
-
-void
-FlyWebService::RegisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
-{
- MOZ_ASSERT(NS_IsMainThread());
- mDiscoveryManagerTable.PutEntry(aDiscoveryManager);
- if (mMDNSHttpService) {
- mMDNSHttpService->EnsureDiscoveryStarted();
- }
- if (mMDNSFlywebService) {
- mMDNSFlywebService->EnsureDiscoveryStarted();
- }
-}
-
-void
-FlyWebService::UnregisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
-{
- MOZ_ASSERT(NS_IsMainThread());
- mDiscoveryManagerTable.RemoveEntry(aDiscoveryManager);
- if (mDiscoveryManagerTable.IsEmpty()) {
- if (mMDNSHttpService) {
- mMDNSHttpService->EnsureDiscoveryStopped();
- }
- if (mMDNSFlywebService) {
- mMDNSFlywebService->EnsureDiscoveryStopped();
- }
- }
-}
-
-NS_IMETHODIMP
-FlyWebService::Observe(nsISupports* aSubject, const char* aTopic,
- const char16_t* aData)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (strcmp(aTopic, "inner-window-destroyed")) {
- return NS_OK;
- }
-
- nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
- NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
-
- uint64_t innerID;
- nsresult rv = wrapper->GetData(&innerID);
- NS_ENSURE_SUCCESS(rv, rv);
-
- for (FlyWebPublishedServer* server : mServers) {
- if (server->OwnerWindowID() == innerID) {
- server->Close();
- }
- }
-
- return NS_OK;
-}
-
-void
-FlyWebService::UnregisterServer(FlyWebPublishedServer* aServer)
-{
- MOZ_ASSERT(NS_IsMainThread());
- DebugOnly<bool> removed = mServers.RemoveElement(aServer);
- MOZ_ASSERT(removed);
-}
-
-bool
-FlyWebService::HasConnectionOrServer(uint64_t aWindowID)
-{
- MOZ_ASSERT(NS_IsMainThread());
- for (FlyWebPublishedServer* server : mServers) {
- nsPIDOMWindowInner* win = server->GetOwner();
- if (win && win->WindowID() == aWindowID) {
- return true;
- }
- }
-
- return false;
-}
-
-void
-FlyWebService::NotifyDiscoveredServicesChanged()
-{
- // Process the service map, add to the pair map.
- for (auto iter = mDiscoveryManagerTable.Iter(); !iter.Done(); iter.Next()) {
- iter.Get()->GetKey()->NotifyDiscoveredServicesChanged();
- }
-}
-
-void
-FlyWebService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
-{
- MOZ_ASSERT(NS_IsMainThread());
- if (mMDNSHttpService) {
- mMDNSHttpService->ListDiscoveredServices(aServices);
- }
- if (mMDNSFlywebService) {
- mMDNSFlywebService->ListDiscoveredServices(aServices);
- }
-}
-
-void
-FlyWebService::PairWithService(const nsAString& aServiceId,
- FlyWebPairingCallback& aCallback)
-{
- MOZ_ASSERT(NS_IsMainThread());
- // See if we have already paired with this service. If so, re-use the
- // FlyWebPairedService for that.
- {
- ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
- for (auto iter = mPairedServiceTable.Iter(); !iter.Done(); iter.Next()) {
- PairedInfo* pairInfo = iter.UserData();
- if (pairInfo->mService.mDiscoveredService.mServiceId.Equals(aServiceId)) {
- ErrorResult er;
- ReentrantMonitorAutoExit pairedMapRelease(mMonitor);
- aCallback.PairingSucceeded(pairInfo->mService, er);
- ENSURE_SUCCESS_VOID(er);
- return;
- }
- }
- }
-
- UniquePtr<PairedInfo> pairInfo;
-
- nsresult rv = NS_OK;
- bool notFound = false;
- if (mMDNSHttpService && mMDNSHttpService->HasService(aServiceId)) {
- rv = mMDNSHttpService->PairWithService(aServiceId, pairInfo);
- } else if (mMDNSFlywebService && mMDNSFlywebService->HasService(aServiceId)) {
- rv = mMDNSFlywebService->PairWithService(aServiceId, pairInfo);
- } else {
- notFound = true;
- }
-
- if (NS_FAILED(rv)) {
- ErrorResult result;
- result.Throw(rv);
- const nsAString& reason = NS_LITERAL_STRING("Error pairing.");
- aCallback.PairingFailed(reason, result);
- ENSURE_SUCCESS_VOID(result);
- return;
- }
-
- if (!pairInfo) {
- ErrorResult res;
- const nsAString& reason = notFound ?
- NS_LITERAL_STRING("No such service.") :
- NS_LITERAL_STRING("Error pairing.");
- aCallback.PairingFailed(reason, res);
- ENSURE_SUCCESS_VOID(res);
- return;
- }
-
- // Add fingerprint to certificate override database.
- if (!pairInfo->mService.mDiscoveredService.mCert.IsEmpty()) {
- nsCOMPtr<nsICertOverrideService> override =
- do_GetService("@mozilla.org/security/certoverride;1");
- if (!override ||
- NS_FAILED(override->RememberTemporaryValidityOverrideUsingFingerprint(
- NS_ConvertUTF16toUTF8(pairInfo->mService.mHostname),
- -1,
- NS_ConvertUTF16toUTF8(pairInfo->mService.mDiscoveredService.mCert),
- nsICertOverrideService::ERROR_UNTRUSTED |
- nsICertOverrideService::ERROR_MISMATCH))) {
- ErrorResult res;
- aCallback.PairingFailed(NS_LITERAL_STRING("Error adding certificate override."), res);
- ENSURE_SUCCESS_VOID(res);
- return;
- }
- }
-
- // Grab a weak reference to the PairedInfo so that we can
- // use it even after ownership has been transferred to mPairedServiceTable
- PairedInfo* pairInfoWeak = pairInfo.release();
-
- {
- ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
- mPairedServiceTable.Put(
- NS_ConvertUTF16toUTF8(pairInfoWeak->mService.mHostname), pairInfoWeak);
- }
-
- ErrorResult er;
- aCallback.PairingSucceeded(pairInfoWeak->mService, er);
- ENSURE_SUCCESS_VOID(er);
-}
-
-nsresult
-FlyWebService::CreateTransportForHost(const char **types,
- uint32_t typeCount,
- const nsACString &host,
- int32_t port,
- const nsACString &hostRoute,
- int32_t portRoute,
- nsIProxyInfo *proxyInfo,
- nsISocketTransport **result)
-{
- // This might be called on background threads
-
- *result = nullptr;
-
- nsCString ipAddrString;
- uint16_t discPort;
-
- {
- ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
-
- PairedInfo* info = mPairedServiceTable.Get(host);
-
- if (!info) {
- return NS_OK;
- }
-
- // Get the ip address of the underlying service.
- info->mDNSServiceInfo->GetAddress(ipAddrString);
- info->mDNSServiceInfo->GetPort(&discPort);
- }
-
- // Parse it into an NetAddr.
- PRNetAddr prNetAddr;
- PRStatus status = PR_StringToNetAddr(ipAddrString.get(), &prNetAddr);
- NS_ENSURE_FALSE(status == PR_FAILURE, NS_ERROR_FAILURE);
-
- // Convert PRNetAddr to NetAddr.
- mozilla::net::NetAddr netAddr;
- PRNetAddrToNetAddr(&prNetAddr, &netAddr);
- netAddr.inet.port = htons(discPort);
-
- RefPtr<mozilla::net::nsSocketTransport> trans = new mozilla::net::nsSocketTransport();
- nsresult rv = trans->InitPreResolved(
- types, typeCount, host, port, hostRoute, portRoute, proxyInfo, &netAddr);
- NS_ENSURE_SUCCESS(rv, rv);
-
- trans.forget(result);
- return NS_OK;
-}
-
-void
-FlyWebService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
-{
- MOZ_ASSERT(NS_IsMainThread());
- nsresult rv = mMDNSFlywebService ?
- mMDNSFlywebService->StartDiscoveryOf(aServer) :
- NS_ERROR_FAILURE;
-
- if (NS_FAILED(rv)) {
- aServer->PublishedServerStarted(rv);
- }
-}
-
-} // namespace dom
-} // namespace mozilla