diff options
Diffstat (limited to 'dom/flyweb/FlyWebService.cpp')
-rw-r--r-- | dom/flyweb/FlyWebService.cpp | 1310 |
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 |