LCOV - code coverage report
Current view: top level - dom/flyweb - FlyWebService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 3 611 0.5 %
Date: 2017-07-14 16:53:18 Functions: 1 69 1.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/FlyWebService.h"
       8             : #include "mozilla/ClearOnShutdown.h"
       9             : #include "mozilla/StaticPtr.h"
      10             : #include "mozilla/ScopeExit.h"
      11             : #include "mozilla/dom/Promise.h"
      12             : #include "mozilla/dom/FlyWebPublishedServerIPC.h"
      13             : #include "mozilla/AddonPathService.h"
      14             : #include "nsISocketTransportService.h"
      15             : #include "mdns/libmdns/nsDNSServiceInfo.h"
      16             : #include "nsIUUIDGenerator.h"
      17             : #include "nsStandardURL.h"
      18             : #include "mozilla/Services.h"
      19             : #include "nsISupportsPrimitives.h"
      20             : #include "mozilla/dom/FlyWebDiscoveryManagerBinding.h"
      21             : #include "prnetdb.h"
      22             : #include "DNS.h"
      23             : #include "nsContentPermissionHelper.h"
      24             : #include "nsSocketTransportService2.h"
      25             : #include "nsSocketTransport2.h"
      26             : #include "nsHashPropertyBag.h"
      27             : #include "nsNetUtil.h"
      28             : #include "nsISimpleEnumerator.h"
      29             : #include "nsIProperty.h"
      30             : #include "nsICertOverrideService.h"
      31             : 
      32             : namespace mozilla {
      33             : namespace dom {
      34             : 
      35             : struct FlyWebPublishOptions;
      36             : 
      37             : static LazyLogModule gFlyWebServiceLog("FlyWebService");
      38             : #undef LOG_I
      39             : #define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
      40             : 
      41             : #undef LOG_E
      42             : #define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__))
      43             : 
      44             : #undef LOG_TEST_I
      45             : #define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug)
      46             : 
      47             : class FlyWebPublishServerPermissionCheck final
      48             :   : public nsIContentPermissionRequest
      49             :   , public nsIRunnable
      50             : {
      51             : public:
      52             :   NS_DECL_ISUPPORTS
      53             : 
      54           0 :   FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID,
      55             :                                      FlyWebPublishedServer* aServer)
      56           0 :     : mServiceName(aServiceName)
      57             :     , mWindowID(aWindowID)
      58           0 :     , mServer(aServer)
      59           0 :   {}
      60             : 
      61             :   uint64_t WindowID() const
      62             :   {
      63             :     return mWindowID;
      64             :   }
      65             : 
      66           0 :   NS_IMETHOD Run() override
      67             :   {
      68           0 :     MOZ_ASSERT(NS_IsMainThread());
      69             : 
      70           0 :     nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
      71           0 :     if (!globalWindow) {
      72           0 :       return Cancel();
      73             :     }
      74           0 :     mWindow = globalWindow->AsInner();
      75           0 :     if (NS_WARN_IF(!mWindow)) {
      76           0 :       return Cancel();
      77             :     }
      78             : 
      79           0 :     nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
      80           0 :     if (NS_WARN_IF(!doc)) {
      81           0 :       return Cancel();
      82             :     }
      83             : 
      84           0 :     mPrincipal = doc->NodePrincipal();
      85           0 :     MOZ_ASSERT(mPrincipal);
      86             : 
      87           0 :     mRequester = new nsContentPermissionRequester(mWindow);
      88           0 :     return nsContentPermissionUtils::AskPermission(this, mWindow);
      89             :   }
      90             : 
      91           0 :   NS_IMETHOD Cancel() override
      92             :   {
      93           0 :     Resolve(false);
      94           0 :     return NS_OK;
      95             :   }
      96             : 
      97           0 :   NS_IMETHOD Allow(JS::HandleValue aChoices) override
      98             :   {
      99           0 :     MOZ_ASSERT(aChoices.isUndefined());
     100           0 :     Resolve(true);
     101           0 :     return NS_OK;
     102             :   }
     103             : 
     104           0 :   NS_IMETHOD GetTypes(nsIArray** aTypes) override
     105             :   {
     106           0 :     nsTArray<nsString> emptyOptions;
     107           0 :     return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"),
     108           0 :                                                            NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes);
     109             :   }
     110             : 
     111           0 :   NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override
     112             :   {
     113           0 :     NS_ENSURE_ARG_POINTER(aRequester);
     114           0 :     nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
     115           0 :     requester.forget(aRequester);
     116           0 :     return NS_OK;
     117             :   }
     118             : 
     119           0 :   NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override
     120             :   {
     121           0 :     NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
     122           0 :     return NS_OK;
     123             :   }
     124             : 
     125           0 :   NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override
     126             :   {
     127           0 :     NS_IF_ADDREF(*aRequestingWindow = mWindow);
     128           0 :     return NS_OK;
     129             :   }
     130             : 
     131           0 :   NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override
     132             :   {
     133           0 :     *aRequestingElement = nullptr;
     134           0 :     return NS_OK;
     135             :   }
     136             : 
     137             : private:
     138           0 :   void Resolve(bool aResolve)
     139             :   {
     140           0 :     mServer->PermissionGranted(aResolve);
     141           0 :   }
     142             : 
     143           0 :   virtual ~FlyWebPublishServerPermissionCheck() = default;
     144             : 
     145             :   nsCString mServiceName;
     146             :   uint64_t mWindowID;
     147             :   RefPtr<FlyWebPublishedServer> mServer;
     148             :   nsCOMPtr<nsPIDOMWindowInner> mWindow;
     149             :   nsCOMPtr<nsIPrincipal> mPrincipal;
     150             :   nsCOMPtr<nsIContentPermissionRequester> mRequester;
     151             : };
     152             : 
     153           0 : NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck,
     154             :                   nsIContentPermissionRequest,
     155             :                   nsIRunnable)
     156             : 
     157             : class FlyWebMDNSService final
     158             :   : public nsIDNSServiceDiscoveryListener
     159             :   , public nsIDNSServiceResolveListener
     160             :   , public nsIDNSRegistrationListener
     161             :   , public nsITimerCallback
     162             : {
     163             :   friend class FlyWebService;
     164             : 
     165             : private:
     166             :   enum DiscoveryState {
     167             :     DISCOVERY_IDLE,
     168             :     DISCOVERY_STARTING,
     169             :     DISCOVERY_RUNNING,
     170             :     DISCOVERY_STOPPING
     171             :   };
     172             : 
     173             : public:
     174             :   NS_DECL_ISUPPORTS
     175             :   NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER
     176             :   NS_DECL_NSIDNSSERVICERESOLVELISTENER
     177             :   NS_DECL_NSIDNSREGISTRATIONLISTENER
     178             :   NS_DECL_NSITIMERCALLBACK
     179             : 
     180             :   explicit FlyWebMDNSService(FlyWebService* aService,
     181             :                              const nsACString& aServiceType);
     182             : 
     183             : private:
     184           0 :   virtual ~FlyWebMDNSService() = default;
     185             : 
     186             :   nsresult Init();
     187             :   nsresult StartDiscovery();
     188             :   nsresult StopDiscovery();
     189             : 
     190             :   void ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices);
     191             :   bool HasService(const nsAString& aServiceId);
     192             :   nsresult PairWithService(const nsAString& aServiceId,
     193             :                            UniquePtr<FlyWebService::PairedInfo>& aInfo);
     194             : 
     195             :   nsresult StartDiscoveryOf(FlyWebPublishedServerImpl* aServer);
     196             : 
     197             :   void EnsureDiscoveryStarted();
     198             :   void EnsureDiscoveryStopped();
     199             : 
     200             :   // Cycle-breaking link to manager.
     201             :   FlyWebService* mService;
     202             :   nsCString mServiceType;
     203             : 
     204             :   // Indicates the desired state of the system.  If mDiscoveryActive is true,
     205             :   // it indicates that backend discovery "should be happening", and discovery
     206             :   // events should be forwarded to listeners.
     207             :   // If false, the backend discovery "should be idle", and any discovery events
     208             :   // that show up should not be forwarded to listeners.
     209             :   bool mDiscoveryActive;
     210             : 
     211             :   uint32_t mNumConsecutiveStartDiscoveryFailures;
     212             : 
     213             :   // Represents the internal discovery state as it relates to nsDNSServiceDiscovery.
     214             :   // When mDiscoveryActive is true, this state will periodically loop from
     215             :   // (IDLE => STARTING => RUNNING => STOPPING => IDLE).
     216             :   DiscoveryState mDiscoveryState;
     217             : 
     218             :   nsCOMPtr<nsITimer> mDiscoveryStartTimer;
     219             :   nsCOMPtr<nsITimer> mDiscoveryStopTimer;
     220             :   nsCOMPtr<nsIDNSServiceDiscovery> mDNSServiceDiscovery;
     221             :   nsCOMPtr<nsICancelable> mCancelDiscovery;
     222             :   nsTHashtable<nsStringHashKey> mNewServiceSet;
     223             : 
     224           0 :   struct DiscoveredInfo
     225             :   {
     226             :     explicit DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo);
     227             :     FlyWebDiscoveredService mService;
     228             :     nsCOMPtr<nsIDNSServiceInfo> mDNSServiceInfo;
     229             :   };
     230             :   nsClassHashtable<nsStringHashKey, DiscoveredInfo> mServiceMap;
     231             : };
     232             : 
     233             : void
     234           0 : LogDNSInfo(nsIDNSServiceInfo* aServiceInfo, const char* aFunc)
     235             : {
     236           0 :   if (!LOG_TEST_I()) {
     237           0 :     return;
     238             :   }
     239             : 
     240           0 :   nsCString tmp;
     241           0 :   aServiceInfo->GetServiceName(tmp);
     242           0 :   LOG_I("%s: serviceName=%s", aFunc, tmp.get());
     243             : 
     244           0 :   aServiceInfo->GetHost(tmp);
     245           0 :   LOG_I("%s: host=%s", aFunc, tmp.get());
     246             : 
     247           0 :   aServiceInfo->GetAddress(tmp);
     248           0 :   LOG_I("%s: address=%s", aFunc, tmp.get());
     249             : 
     250           0 :   uint16_t port = -2;
     251           0 :   aServiceInfo->GetPort(&port);
     252           0 :   LOG_I("%s: port=%d", aFunc, (int)port);
     253             : 
     254           0 :   nsCOMPtr<nsIPropertyBag2> attributes;
     255           0 :   aServiceInfo->GetAttributes(getter_AddRefs(attributes));
     256           0 :   if (!attributes) {
     257           0 :     LOG_I("%s: no attributes", aFunc);
     258             :   } else {
     259           0 :     nsCOMPtr<nsISimpleEnumerator> enumerator;
     260           0 :     attributes->GetEnumerator(getter_AddRefs(enumerator));
     261           0 :     MOZ_ASSERT(enumerator);
     262             : 
     263           0 :     LOG_I("%s: attributes start", aFunc);
     264             : 
     265             :     bool hasMoreElements;
     266           0 :     while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) &&
     267             :            hasMoreElements) {
     268           0 :       nsCOMPtr<nsISupports> element;
     269           0 :       MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element)));
     270           0 :       nsCOMPtr<nsIProperty> property = do_QueryInterface(element);
     271           0 :       MOZ_ASSERT(property);
     272             : 
     273           0 :       nsAutoString name;
     274           0 :       nsCOMPtr<nsIVariant> value;
     275           0 :       MOZ_ALWAYS_SUCCEEDS(property->GetName(name));
     276           0 :       MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value)));
     277             : 
     278           0 :       nsAutoCString str;
     279           0 :       nsresult rv = value->GetAsACString(str);
     280           0 :       if (NS_SUCCEEDED(rv)) {
     281           0 :         LOG_I("%s: attribute name=%s value=%s", aFunc,
     282             :               NS_ConvertUTF16toUTF8(name).get(), str.get());
     283             :       } else {
     284             :         uint16_t type;
     285           0 :         MOZ_ALWAYS_SUCCEEDS(value->GetDataType(&type));
     286           0 :         LOG_I("%s: attribute *unstringifiable* name=%s type=%d", aFunc,
     287             :               NS_ConvertUTF16toUTF8(name).get(), (int)type);
     288             :       }
     289             :     }
     290             : 
     291           0 :     LOG_I("%s: attributes end", aFunc);
     292             :   }
     293             : }
     294             : 
     295           0 : NS_IMPL_ISUPPORTS(FlyWebMDNSService,
     296             :                   nsIDNSServiceDiscoveryListener,
     297             :                   nsIDNSServiceResolveListener,
     298             :                   nsIDNSRegistrationListener,
     299             :                   nsITimerCallback)
     300             : 
     301           0 : FlyWebMDNSService::FlyWebMDNSService(
     302             :         FlyWebService* aService,
     303           0 :         const nsACString& aServiceType)
     304             :   : mService(aService)
     305             :   , mServiceType(aServiceType)
     306             :   , mDiscoveryActive(false)
     307             :   , mNumConsecutiveStartDiscoveryFailures(0)
     308           0 :   , mDiscoveryState(DISCOVERY_IDLE)
     309           0 : {}
     310             : 
     311             : nsresult
     312           0 : FlyWebMDNSService::OnDiscoveryStarted(const nsACString& aServiceType)
     313             : {
     314           0 :   MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
     315           0 :   mDiscoveryState = DISCOVERY_RUNNING;
     316             :   // Reset consecutive start discovery failures.
     317           0 :   mNumConsecutiveStartDiscoveryFailures = 0;
     318           0 :   LOG_I("===========================================");
     319           0 :   LOG_I("MDNSService::OnDiscoveryStarted(%s)", PromiseFlatCString(aServiceType).get());
     320           0 :   LOG_I("===========================================");
     321             : 
     322             :   // Clear the new service array.
     323           0 :   mNewServiceSet.Clear();
     324             : 
     325             :   // If service discovery is inactive, then stop network discovery immediately.
     326           0 :   if (!mDiscoveryActive) {
     327             :     // Set the stop timer to fire immediately.
     328           0 :     Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
     329           0 :     return NS_OK;
     330             :   }
     331             : 
     332             :   // Otherwise, set the stop timer to fire in 5 seconds.
     333           0 :   Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT)));
     334             : 
     335           0 :   return NS_OK;
     336             : }
     337             : 
     338             : nsresult
     339           0 : FlyWebMDNSService::OnDiscoveryStopped(const nsACString& aServiceType)
     340             : {
     341           0 :   LOG_I("///////////////////////////////////////////");
     342           0 :   LOG_I("MDNSService::OnDiscoveryStopped(%s)", PromiseFlatCString(aServiceType).get());
     343           0 :   LOG_I("///////////////////////////////////////////");
     344           0 :   MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
     345           0 :   mDiscoveryState = DISCOVERY_IDLE;
     346             : 
     347             :   // If service discovery is inactive, then discard all results and do not proceed.
     348           0 :   if (!mDiscoveryActive) {
     349           0 :     mServiceMap.Clear();
     350           0 :     mNewServiceSet.Clear();
     351           0 :     return NS_OK;
     352             :   }
     353             : 
     354             :   // Process the service map, add to the pair map.
     355           0 :   for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
     356           0 :     DiscoveredInfo* service = iter.UserData();
     357             : 
     358           0 :     if (!mNewServiceSet.Contains(service->mService.mServiceId)) {
     359           0 :       iter.Remove();
     360             :     }
     361             :   }
     362             : 
     363             :   // Notify FlyWebService of changed service list.
     364           0 :   mService->NotifyDiscoveredServicesChanged();
     365             : 
     366             :   // Start discovery again immediately.
     367           0 :   Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
     368             : 
     369           0 :   return NS_OK;
     370             : }
     371             : 
     372             : nsresult
     373           0 : FlyWebMDNSService::OnServiceFound(nsIDNSServiceInfo* aServiceInfo)
     374             : {
     375           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceFound");
     376             : 
     377             :   // If discovery is not active, don't do anything with the result.
     378             :   // If there is no discovery underway, ignore this.
     379           0 :   if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
     380           0 :     return NS_OK;
     381             :   }
     382             : 
     383             :   // Discovery is underway - resolve the service.
     384           0 :   nsresult rv = mDNSServiceDiscovery->ResolveService(aServiceInfo, this);
     385           0 :   NS_ENSURE_SUCCESS(rv, rv);
     386             : 
     387           0 :   return NS_OK;
     388             : }
     389             : 
     390             : nsresult
     391           0 : FlyWebMDNSService::OnServiceLost(nsIDNSServiceInfo* aServiceInfo)
     392             : {
     393           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceLost");
     394             : 
     395           0 :   return NS_OK;
     396             : }
     397             : 
     398             : nsresult
     399           0 : FlyWebMDNSService::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
     400             : {
     401           0 :   LOG_E("MDNSService::OnStartDiscoveryFailed(%s): %d", PromiseFlatCString(aServiceType).get(), (int) aErrorCode);
     402             : 
     403           0 :   MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING);
     404           0 :   mDiscoveryState = DISCOVERY_IDLE;
     405           0 :   mNumConsecutiveStartDiscoveryFailures++;
     406             : 
     407             :   // If discovery is active, and the number of consecutive failures is < 3, try starting again.
     408           0 :   if (mDiscoveryActive && mNumConsecutiveStartDiscoveryFailures < 3) {
     409           0 :     Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
     410             :   }
     411             : 
     412           0 :   return NS_OK;
     413             : }
     414             : 
     415             : nsresult
     416           0 : FlyWebMDNSService::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode)
     417             : {
     418           0 :   LOG_E("MDNSService::OnStopDiscoveryFailed(%s)", PromiseFlatCString(aServiceType).get());
     419           0 :   MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING);
     420           0 :   mDiscoveryState = DISCOVERY_IDLE;
     421             : 
     422             :   // If discovery is active, start discovery again immediately.
     423           0 :   if (mDiscoveryActive) {
     424           0 :     Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT)));
     425             :   }
     426             : 
     427           0 :   return NS_OK;
     428             : }
     429             : 
     430             : static bool
     431           0 : IsAcceptableServiceAddress(const nsCString& addr)
     432             : {
     433             :   PRNetAddr prNetAddr;
     434           0 :   PRStatus status = PR_StringToNetAddr(addr.get(), &prNetAddr);
     435           0 :   if (status == PR_FAILURE) {
     436           0 :     return false;
     437             :   }
     438             :   // Only allow ipv4 addreses for now.
     439           0 :   return prNetAddr.raw.family == PR_AF_INET;
     440             : }
     441             : 
     442             : nsresult
     443           0 : FlyWebMDNSService::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo)
     444             : {
     445           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceResolved");
     446             : 
     447             :   // If discovery is not active, don't do anything with the result.
     448             :   // If there is no discovery underway, ignore this resolve.
     449           0 :   if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) {
     450           0 :     return NS_OK;
     451             :   }
     452             : 
     453             :   nsresult rv;
     454             : 
     455           0 :   nsCString address;
     456           0 :   rv = aServiceInfo->GetAddress(address);
     457           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     458           0 :     return rv;
     459             :   }
     460             : 
     461           0 :   if (!IsAcceptableServiceAddress(address)) {
     462           0 :     return NS_OK;
     463             :   }
     464             : 
     465             :   // Create a new serviceInfo and stuff it in the new service array.
     466           0 :   UniquePtr<DiscoveredInfo> svc(new DiscoveredInfo(aServiceInfo));
     467           0 :   mNewServiceSet.PutEntry(svc->mService.mServiceId);
     468             : 
     469             :   DiscoveredInfo* existingSvc =
     470           0 :     mServiceMap.Get(svc->mService.mServiceId);
     471           0 :   if (existingSvc) {
     472             :     // Update the underlying DNS service info, but leave the old object in place.
     473           0 :     existingSvc->mDNSServiceInfo = aServiceInfo;
     474             :   } else {
     475           0 :     DiscoveredInfo* info = svc.release();
     476           0 :     mServiceMap.Put(info->mService.mServiceId, info);
     477             :   }
     478             : 
     479             :   // Notify FlyWebService of changed service list.
     480           0 :   mService->NotifyDiscoveredServicesChanged();
     481             : 
     482           0 :   return NS_OK;
     483             : }
     484             : 
     485           0 : FlyWebMDNSService::DiscoveredInfo::DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo)
     486           0 :   : mDNSServiceInfo(aDNSServiceInfo)
     487             : {
     488           0 :   nsCString tmp;
     489           0 :   DebugOnly<nsresult> drv = aDNSServiceInfo->GetServiceName(tmp);
     490           0 :   MOZ_ASSERT(NS_SUCCEEDED(drv));
     491           0 :   CopyUTF8toUTF16(tmp, mService.mDisplayName);
     492             : 
     493           0 :   mService.mTransport = NS_LITERAL_STRING("mdns");
     494             : 
     495           0 :   drv = aDNSServiceInfo->GetServiceType(tmp);
     496           0 :   MOZ_ASSERT(NS_SUCCEEDED(drv));
     497           0 :   CopyUTF8toUTF16(tmp, mService.mServiceType);
     498             : 
     499           0 :   nsCOMPtr<nsIPropertyBag2> attrs;
     500           0 :   drv = aDNSServiceInfo->GetAttributes(getter_AddRefs(attrs));
     501           0 :   MOZ_ASSERT(NS_SUCCEEDED(drv));
     502           0 :   if (attrs) {
     503           0 :     attrs->GetPropertyAsAString(NS_LITERAL_STRING("cert"), mService.mCert);
     504           0 :     attrs->GetPropertyAsAString(NS_LITERAL_STRING("path"), mService.mPath);
     505             :   }
     506             : 
     507             :   // Construct a service id from the name, host, address, and port.
     508           0 :   nsCString cHost;
     509           0 :   drv = aDNSServiceInfo->GetHost(cHost);
     510           0 :   MOZ_ASSERT(NS_SUCCEEDED(drv));
     511             : 
     512           0 :   nsCString cAddress;
     513           0 :   drv = aDNSServiceInfo->GetAddress(cAddress);
     514           0 :   MOZ_ASSERT(NS_SUCCEEDED(drv));
     515             : 
     516             :   uint16_t port;
     517           0 :   drv = aDNSServiceInfo->GetPort(&port);
     518           0 :   MOZ_ASSERT(NS_SUCCEEDED(drv));
     519           0 :   nsAutoString portStr;
     520           0 :   portStr.AppendInt(port, 10);
     521             : 
     522             :   mService.mServiceId =
     523           0 :     NS_ConvertUTF8toUTF16(cAddress) +
     524           0 :     NS_LITERAL_STRING(":") +
     525           0 :     portStr +
     526           0 :     NS_LITERAL_STRING("|") +
     527           0 :     mService.mServiceType +
     528           0 :     NS_LITERAL_STRING("|") +
     529           0 :     NS_ConvertUTF8toUTF16(cHost) +
     530           0 :     NS_LITERAL_STRING("|") +
     531           0 :     mService.mDisplayName;
     532           0 : }
     533             : 
     534             : 
     535             : nsresult
     536           0 : FlyWebMDNSService::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode)
     537             : {
     538           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnResolveFailed");
     539             : 
     540           0 :   return NS_OK;
     541             : }
     542             : 
     543             : nsresult
     544           0 : FlyWebMDNSService::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo)
     545             : {
     546           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceRegistered");
     547             : 
     548           0 :   nsCString cName;
     549           0 :   if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
     550           0 :     return NS_ERROR_FAILURE;
     551             :   }
     552             : 
     553           0 :   nsString name = NS_ConvertUTF8toUTF16(cName);
     554             :   RefPtr<FlyWebPublishedServer> existingServer =
     555           0 :     FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
     556           0 :   if (!existingServer) {
     557           0 :     return NS_ERROR_FAILURE;
     558             :   }
     559             : 
     560           0 :   existingServer->PublishedServerStarted(NS_OK);
     561             : 
     562           0 :   return NS_OK;
     563             : }
     564             : 
     565             : nsresult
     566           0 : FlyWebMDNSService::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo)
     567             : {
     568           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceUnregistered");
     569             : 
     570           0 :   nsCString cName;
     571           0 :   if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
     572           0 :     return NS_ERROR_FAILURE;
     573             :   }
     574             : 
     575           0 :   nsString name = NS_ConvertUTF8toUTF16(cName);
     576             :   RefPtr<FlyWebPublishedServer> existingServer =
     577           0 :     FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
     578           0 :   if (!existingServer) {
     579           0 :     return NS_ERROR_FAILURE;
     580             :   }
     581             : 
     582           0 :   LOG_I("OnServiceRegistered(MDNS): De-advertised server with name %s.", cName.get());
     583             : 
     584           0 :   return NS_OK;
     585             : }
     586             : 
     587             : nsresult
     588           0 : FlyWebMDNSService::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
     589             : {
     590           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnRegistrationFailed");
     591             : 
     592           0 :   nsCString cName;
     593           0 :   if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
     594           0 :     return NS_ERROR_FAILURE;
     595             :   }
     596             : 
     597           0 :   nsString name = NS_ConvertUTF8toUTF16(cName);
     598             :   RefPtr<FlyWebPublishedServer> existingServer =
     599           0 :     FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
     600           0 :   if (!existingServer) {
     601           0 :     return NS_ERROR_FAILURE;
     602             :   }
     603             : 
     604           0 :   LOG_I("OnServiceRegistered(MDNS): Registration of server with name %s failed.", cName.get());
     605             : 
     606             :   // Remove the nsICancelable from the published server.
     607           0 :   existingServer->PublishedServerStarted(NS_ERROR_FAILURE);
     608           0 :   return NS_OK;
     609             : }
     610             : 
     611             : nsresult
     612           0 : FlyWebMDNSService::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode)
     613             : {
     614           0 :   LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnUnregistrationFailed");
     615             : 
     616           0 :   nsCString cName;
     617           0 :   if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) {
     618           0 :     return NS_ERROR_FAILURE;
     619             :   }
     620             : 
     621           0 :   nsString name = NS_ConvertUTF8toUTF16(cName);
     622             :   RefPtr<FlyWebPublishedServer> existingServer =
     623           0 :     FlyWebService::GetOrCreate()->FindPublishedServerByName(name);
     624           0 :   if (!existingServer) {
     625           0 :     return NS_ERROR_FAILURE;
     626             :   }
     627             : 
     628           0 :   LOG_I("OnServiceRegistered(MDNS): Un-Advertisement of server with name %s failed.", cName.get());
     629           0 :   return NS_OK;
     630             : }
     631             : 
     632             : nsresult
     633           0 : FlyWebMDNSService::Notify(nsITimer* timer)
     634             : {
     635           0 :   if (timer == mDiscoveryStopTimer.get()) {
     636           0 :     LOG_I("MDNSService::Notify() got discovery stop timeout");
     637             :     // Internet discovery stop timer has fired.
     638           0 :     nsresult rv = StopDiscovery();
     639           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     640           0 :       return rv;
     641             :     }
     642           0 :     return NS_OK;
     643             :   }
     644             : 
     645           0 :   if (timer == mDiscoveryStartTimer.get()) {
     646           0 :     LOG_I("MDNSService::Notify() got discovery start timeout");
     647             :     // Internet discovery start timer has fired.
     648           0 :     nsresult rv = StartDiscovery();
     649           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     650           0 :       return rv;
     651             :     }
     652           0 :     return NS_OK;
     653             :   }
     654             : 
     655           0 :   LOG_E("MDNSService::Notify got unknown timeout.");
     656           0 :   return NS_OK;
     657             : }
     658             : 
     659             : nsresult
     660           0 : FlyWebMDNSService::Init()
     661             : {
     662           0 :   MOZ_ASSERT(mDiscoveryState == DISCOVERY_IDLE);
     663             : 
     664           0 :   mDiscoveryStartTimer = do_CreateInstance("@mozilla.org/timer;1");
     665           0 :   if (!mDiscoveryStartTimer) {
     666           0 :     return NS_ERROR_FAILURE;
     667             :   }
     668             : 
     669           0 :   mDiscoveryStopTimer = do_CreateInstance("@mozilla.org/timer;1");
     670           0 :   if (!mDiscoveryStopTimer) {
     671           0 :     return NS_ERROR_FAILURE;
     672             :   }
     673             : 
     674             :   nsresult rv;
     675           0 :   mDNSServiceDiscovery = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv);
     676           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     677           0 :     return rv;
     678             :   }
     679             : 
     680           0 :   return NS_OK;
     681             : }
     682             : 
     683             : nsresult
     684           0 : FlyWebMDNSService::StartDiscovery()
     685             : {
     686             :   nsresult rv;
     687             : 
     688             :   // Always cancel the timer.
     689           0 :   rv = mDiscoveryStartTimer->Cancel();
     690           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     691           0 :     LOG_E("FlyWeb failed to cancel DNS service discovery start timer.");
     692             :   }
     693             : 
     694             :   // If discovery is not idle, don't start it.
     695           0 :   if (mDiscoveryState != DISCOVERY_IDLE) {
     696           0 :     return NS_OK;
     697             :   }
     698             : 
     699           0 :   LOG_I("FlyWeb starting dicovery.");
     700           0 :   mDiscoveryState = DISCOVERY_STARTING;
     701             : 
     702             :   // start the discovery.
     703           0 :   rv = mDNSServiceDiscovery->StartDiscovery(mServiceType, this,
     704           0 :                                             getter_AddRefs(mCancelDiscovery));
     705           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     706           0 :     LOG_E("FlyWeb failed to start DNS service discovery.");
     707           0 :     return rv;
     708             :   }
     709             : 
     710           0 :   return NS_OK;
     711             : }
     712             : 
     713             : nsresult
     714           0 : FlyWebMDNSService::StopDiscovery()
     715             : {
     716             :   nsresult rv;
     717             : 
     718             :   // Always cancel the timer.
     719           0 :   rv = mDiscoveryStopTimer->Cancel();
     720           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     721           0 :     LOG_E("FlyWeb failed to cancel DNS service discovery stop timer.");
     722             :   }
     723             : 
     724             :   // If discovery is not running, do nothing.
     725           0 :   if (mDiscoveryState != DISCOVERY_RUNNING) {
     726           0 :     return NS_OK;
     727             :   }
     728             : 
     729           0 :   LOG_I("FlyWeb stopping dicovery.");
     730             : 
     731             :   // Mark service discovery as stopping.
     732           0 :   mDiscoveryState = DISCOVERY_STOPPING;
     733             : 
     734           0 :   if (mCancelDiscovery) {
     735           0 :     LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery exists!");
     736           0 :     nsCOMPtr<nsICancelable> cancelDiscovery = mCancelDiscovery.forget();
     737           0 :     rv = cancelDiscovery->Cancel(NS_ERROR_ABORT);
     738           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     739           0 :       LOG_E("FlyWeb failed to cancel DNS stop service discovery.");
     740             :     }
     741             :   } else {
     742           0 :     LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery does not exist!");
     743           0 :     mDiscoveryState = DISCOVERY_IDLE;
     744             :   }
     745             : 
     746           0 :   return NS_OK;
     747             : }
     748             : 
     749             : void
     750           0 : FlyWebMDNSService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
     751             : {
     752           0 :   for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) {
     753           0 :     aServices.AppendElement(iter.UserData()->mService);
     754             :   }
     755           0 : }
     756             : 
     757             : bool
     758           0 : FlyWebMDNSService::HasService(const nsAString& aServiceId)
     759             : {
     760           0 :   return mServiceMap.Contains(aServiceId);
     761             : }
     762             : 
     763             : nsresult
     764           0 : FlyWebMDNSService::PairWithService(const nsAString& aServiceId,
     765             :                                    UniquePtr<FlyWebService::PairedInfo>& aInfo)
     766             : {
     767           0 :   MOZ_ASSERT(HasService(aServiceId));
     768             : 
     769             :   nsresult rv;
     770             :   nsCOMPtr<nsIUUIDGenerator> uuidgen =
     771           0 :     do_GetService("@mozilla.org/uuid-generator;1", &rv);
     772           0 :   NS_ENSURE_SUCCESS(rv, rv);
     773             : 
     774             :   nsID id;
     775           0 :   rv = uuidgen->GenerateUUIDInPlace(&id);
     776           0 :   NS_ENSURE_SUCCESS(rv, rv);
     777             : 
     778           0 :   aInfo.reset(new FlyWebService::PairedInfo());
     779             : 
     780             :   char uuidChars[NSID_LENGTH];
     781           0 :   id.ToProvidedString(uuidChars);
     782           0 :   CopyUTF8toUTF16(Substring(uuidChars + 1, uuidChars + NSID_LENGTH - 2),
     783           0 :                   aInfo->mService.mHostname);
     784             : 
     785           0 :   DiscoveredInfo* discInfo = mServiceMap.Get(aServiceId);
     786             : 
     787           0 :   nsAutoString url;
     788           0 :   if (discInfo->mService.mCert.IsEmpty()) {
     789           0 :     url.AssignLiteral("http://");
     790             :   } else {
     791           0 :     url.AssignLiteral("https://");
     792             :   }
     793           0 :   url.Append(aInfo->mService.mHostname);
     794           0 :   if (!discInfo->mService.mPath.IsEmpty()) {
     795           0 :     if (discInfo->mService.mPath.Find("/") != 0) {
     796           0 :       url.Append(NS_LITERAL_STRING("/"));
     797             :     }
     798           0 :     url.Append(discInfo->mService.mPath);
     799             :   } else {
     800           0 :     url.Append(NS_LITERAL_STRING("/"));
     801             :   }
     802           0 :   nsCOMPtr<nsIURI> uiURL;
     803           0 :   NS_NewURI(getter_AddRefs(uiURL), url);
     804           0 :   MOZ_ASSERT(uiURL);
     805           0 :   if (uiURL) {
     806           0 :     nsAutoCString spec;
     807           0 :     uiURL->GetSpec(spec);
     808           0 :     CopyUTF8toUTF16(spec, aInfo->mService.mUiUrl);
     809             :   }
     810             : 
     811           0 :   aInfo->mService.mDiscoveredService = discInfo->mService;
     812           0 :   aInfo->mDNSServiceInfo = discInfo->mDNSServiceInfo;
     813             : 
     814           0 :   return NS_OK;
     815             : }
     816             : 
     817             : nsresult
     818           0 : FlyWebMDNSService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
     819             : {
     820             : 
     821             :   RefPtr<FlyWebPublishedServer> existingServer =
     822           0 :     FlyWebService::GetOrCreate()->FindPublishedServerByName(aServer->Name());
     823           0 :   MOZ_ASSERT(existingServer);
     824             : 
     825             :   // Advertise the service via mdns.
     826           0 :   RefPtr<net::nsDNSServiceInfo> serviceInfo(new net::nsDNSServiceInfo());
     827             : 
     828           0 :   serviceInfo->SetPort(aServer->Port());
     829           0 :   serviceInfo->SetServiceType(mServiceType);
     830             : 
     831           0 :   nsCString certKey;
     832           0 :   aServer->GetCertKey(certKey);
     833           0 :   nsString uiURL;
     834           0 :   aServer->GetUiUrl(uiURL);
     835             : 
     836           0 :   if (!uiURL.IsEmpty() || !certKey.IsEmpty()) {
     837           0 :     RefPtr<nsHashPropertyBag> attrs = new nsHashPropertyBag();
     838           0 :     if (!uiURL.IsEmpty()) {
     839           0 :       attrs->SetPropertyAsAString(NS_LITERAL_STRING("path"), uiURL);
     840             :     }
     841           0 :     if (!certKey.IsEmpty()) {
     842           0 :       attrs->SetPropertyAsACString(NS_LITERAL_STRING("cert"), certKey);
     843             :     }
     844           0 :     serviceInfo->SetAttributes(attrs);
     845             :   }
     846             : 
     847           0 :   nsCString cstrName = NS_ConvertUTF16toUTF8(aServer->Name());
     848           0 :   LOG_I("MDNSService::StartDiscoveryOf() advertising service %s", cstrName.get());
     849           0 :   serviceInfo->SetServiceName(cstrName);
     850             : 
     851           0 :   LogDNSInfo(serviceInfo, "FlyWebMDNSService::StartDiscoveryOf");
     852             : 
     853             :   // Advertise the service.
     854           0 :   nsCOMPtr<nsICancelable> cancelRegister;
     855           0 :   nsresult rv = mDNSServiceDiscovery->
     856           0 :     RegisterService(serviceInfo, this, getter_AddRefs(cancelRegister));
     857           0 :   NS_ENSURE_SUCCESS(rv, rv);
     858             : 
     859             :   // All done.
     860           0 :   aServer->SetCancelRegister(cancelRegister);
     861             : 
     862           0 :   return NS_OK;
     863             : }
     864             : 
     865             : void
     866           0 : FlyWebMDNSService::EnsureDiscoveryStarted()
     867             : {
     868           0 :   mDiscoveryActive = true;
     869             :   // If state is idle, start discovery immediately.
     870           0 :   if (mDiscoveryState == DISCOVERY_IDLE) {
     871           0 :     StartDiscovery();
     872             :   }
     873           0 : }
     874             : 
     875             : void
     876           0 : FlyWebMDNSService::EnsureDiscoveryStopped()
     877             : {
     878             :   // All we need to do is set the flag to false.
     879             :   // If current state is IDLE, it's already the correct state.
     880             :   // Otherwise, the handlers for the internal state
     881             :   // transitions will check this flag and drive the state
     882             :   // towards IDLE.
     883           0 :   mDiscoveryActive = false;
     884           0 : }
     885             : 
     886           3 : static StaticRefPtr<FlyWebService> gFlyWebService;
     887             : 
     888           0 : NS_IMPL_ISUPPORTS(FlyWebService, nsIObserver)
     889             : 
     890           0 : FlyWebService::FlyWebService()
     891           0 :   : mMonitor("FlyWebService::mMonitor")
     892             : {
     893           0 :   MOZ_ASSERT(NS_IsMainThread());
     894           0 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     895           0 :   if (obs) {
     896           0 :     obs->AddObserver(this, "inner-window-destroyed", false);
     897             :   }
     898           0 : }
     899             : 
     900           0 : FlyWebService::~FlyWebService()
     901             : {
     902           0 : }
     903             : 
     904             : FlyWebService*
     905           3 : FlyWebService::GetExisting()
     906             : {
     907           3 :   return gFlyWebService;
     908             : }
     909             : 
     910             : FlyWebService*
     911           0 : FlyWebService::GetOrCreate()
     912             : {
     913           0 :   if (!gFlyWebService) {
     914           0 :     gFlyWebService = new FlyWebService();
     915           0 :     ClearOnShutdown(&gFlyWebService);
     916           0 :     ErrorResult rv = gFlyWebService->Init();
     917           0 :     if (rv.Failed()) {
     918           0 :       gFlyWebService = nullptr;
     919           0 :       return nullptr;
     920             :     }
     921             :   }
     922           0 :   return gFlyWebService;
     923             : }
     924             : 
     925             : ErrorResult
     926           0 : FlyWebService::Init()
     927             : {
     928             :   // Most functions of FlyWebService should not be started in the child.
     929             :   // Instead FlyWebService in the child is mainly responsible for tracking
     930             :   // publishedServer lifetimes. Other functions are handled by the
     931             :   // FlyWebService running in the parent.
     932           0 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     933           0 :     return ErrorResult(NS_OK);
     934             :   }
     935             : 
     936           0 :   MOZ_ASSERT(NS_IsMainThread());
     937           0 :   if (!mMDNSHttpService) {
     938           0 :     mMDNSHttpService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_http._tcp."));
     939           0 :     ErrorResult rv;
     940             : 
     941           0 :     rv = mMDNSHttpService->Init();
     942           0 :     if (rv.Failed()) {
     943           0 :       LOG_E("FlyWebService failed to initialize MDNS _http._tcp.");
     944           0 :       mMDNSHttpService = nullptr;
     945           0 :       rv.SuppressException();
     946             :     }
     947             :   }
     948             : 
     949           0 :   if (!mMDNSFlywebService) {
     950           0 :     mMDNSFlywebService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_flyweb._tcp."));
     951           0 :     ErrorResult rv;
     952             : 
     953           0 :     rv = mMDNSFlywebService->Init();
     954           0 :     if (rv.Failed()) {
     955           0 :       LOG_E("FlyWebService failed to initialize MDNS _flyweb._tcp.");
     956           0 :       mMDNSFlywebService = nullptr;
     957           0 :       rv.SuppressException();
     958             :     }
     959             :   }
     960             : 
     961           0 :   return ErrorResult(NS_OK);
     962             : }
     963             : 
     964             : static already_AddRefed<FlyWebPublishPromise>
     965           0 : MakeRejectionPromise(const char* name)
     966             : {
     967           0 :     MozPromiseHolder<FlyWebPublishPromise> holder;
     968           0 :     RefPtr<FlyWebPublishPromise> promise = holder.Ensure(name);
     969           0 :     holder.Reject(NS_ERROR_FAILURE, name);
     970           0 :     return promise.forget();
     971             : }
     972             : 
     973             : static bool
     974           0 : CheckForFlyWebAddon(const nsACString& uriString)
     975             : {
     976             :   // Before proceeding, ensure that the FlyWeb system addon exists.
     977             :   nsresult rv;
     978           0 :   nsCOMPtr<nsIURI> uri;
     979           0 :   rv = NS_NewURI(getter_AddRefs(uri), uriString);
     980           0 :   if (NS_FAILED(rv)) {
     981           0 :     return false;
     982             :   }
     983             : 
     984           0 :   JSAddonId *addonId = MapURIToAddonID(uri);
     985           0 :   if (!addonId) {
     986           0 :     return false;
     987             :   }
     988             : 
     989           0 :   JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
     990           0 :   nsAutoString addonIdString;
     991           0 :   AssignJSFlatString(addonIdString, flat);
     992           0 :   if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) {
     993           0 :     nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString);
     994           0 :     return false;
     995             :   }
     996             : 
     997           0 :   return true;
     998             : }
     999             : 
    1000             : already_AddRefed<FlyWebPublishPromise>
    1001           0 : FlyWebService::PublishServer(const nsAString& aName,
    1002             :                              const FlyWebPublishOptions& aOptions,
    1003             :                              nsPIDOMWindowInner* aWindow)
    1004             : {
    1005             :   // Scan uiUrl for illegal characters
    1006             : 
    1007             :   RefPtr<FlyWebPublishedServer> existingServer =
    1008           0 :     FlyWebService::GetOrCreate()->FindPublishedServerByName(aName);
    1009           0 :   if (existingServer) {
    1010           0 :     LOG_I("PublishServer: Trying to publish server with already-existing name %s.",
    1011             :           NS_ConvertUTF16toUTF8(aName).get());
    1012           0 :     return MakeRejectionPromise(__func__);
    1013             :   }
    1014             : 
    1015           0 :   RefPtr<FlyWebPublishedServer> server;
    1016           0 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
    1017           0 :     server = new FlyWebPublishedServerChild(aWindow, aName, aOptions);
    1018             :   } else {
    1019           0 :     server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions);
    1020             : 
    1021             :     // Before proceeding, ensure that the FlyWeb system addon exists.
    1022           0 :     if (!CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png")) &&
    1023           0 :         !CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/content/icon-64.png")))
    1024             :     {
    1025           0 :       LOG_E("PublishServer: Failed to find FlyWeb system addon.");
    1026           0 :       return MakeRejectionPromise(__func__);
    1027             :     }
    1028             :   }
    1029             : 
    1030           0 :   if (aWindow) {
    1031             :     nsresult rv;
    1032             : 
    1033           0 :     MOZ_ASSERT(NS_IsMainThread());
    1034           0 :     rv = NS_DispatchToCurrentThread(
    1035           0 :       MakeAndAddRef<FlyWebPublishServerPermissionCheck>(
    1036           0 :         NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server));
    1037           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1038           0 :       LOG_E("PublishServer: Failed to dispatch permission check runnable for %s",
    1039             :             NS_ConvertUTF16toUTF8(aName).get());
    1040           0 :       return MakeRejectionPromise(__func__);
    1041             :     }
    1042             :   } else {
    1043             :     // If aWindow is null, we're definitely in the e10s parent process.
    1044             :     // In this case, we know that permission has already been granted
    1045             :     // by the user because of content-process prompt.
    1046           0 :     MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
    1047           0 :     server->PermissionGranted(true);
    1048             :   }
    1049             : 
    1050           0 :   mServers.AppendElement(server);
    1051             : 
    1052           0 :   return server->GetPublishPromise();
    1053             : }
    1054             : 
    1055             : already_AddRefed<FlyWebPublishedServer>
    1056           0 : FlyWebService::FindPublishedServerByName(
    1057             :         const nsAString& aName)
    1058             : {
    1059           0 :   MOZ_ASSERT(NS_IsMainThread());
    1060           0 :   for (FlyWebPublishedServer* publishedServer : mServers) {
    1061           0 :     if (publishedServer->Name().Equals(aName)) {
    1062           0 :       RefPtr<FlyWebPublishedServer> server = publishedServer;
    1063           0 :       return server.forget();
    1064             :     }
    1065             :   }
    1066           0 :   return nullptr;
    1067             : }
    1068             : 
    1069             : void
    1070           0 : FlyWebService::RegisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
    1071             : {
    1072           0 :   MOZ_ASSERT(NS_IsMainThread());
    1073           0 :   mDiscoveryManagerTable.PutEntry(aDiscoveryManager);
    1074           0 :   if (mMDNSHttpService) {
    1075           0 :     mMDNSHttpService->EnsureDiscoveryStarted();
    1076             :   }
    1077           0 :   if (mMDNSFlywebService) {
    1078           0 :     mMDNSFlywebService->EnsureDiscoveryStarted();
    1079             :   }
    1080           0 : }
    1081             : 
    1082             : void
    1083           0 : FlyWebService::UnregisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager)
    1084             : {
    1085           0 :   MOZ_ASSERT(NS_IsMainThread());
    1086           0 :   mDiscoveryManagerTable.RemoveEntry(aDiscoveryManager);
    1087           0 :   if (mDiscoveryManagerTable.IsEmpty()) {
    1088           0 :     if (mMDNSHttpService) {
    1089           0 :       mMDNSHttpService->EnsureDiscoveryStopped();
    1090             :     }
    1091           0 :     if (mMDNSFlywebService) {
    1092           0 :       mMDNSFlywebService->EnsureDiscoveryStopped();
    1093             :     }
    1094             :   }
    1095           0 : }
    1096             : 
    1097             : NS_IMETHODIMP
    1098           0 : FlyWebService::Observe(nsISupports* aSubject, const char* aTopic,
    1099             :                        const char16_t* aData)
    1100             : {
    1101           0 :   MOZ_ASSERT(NS_IsMainThread());
    1102           0 :   if (strcmp(aTopic, "inner-window-destroyed")) {
    1103           0 :     return NS_OK;
    1104             :   }
    1105             : 
    1106           0 :   nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
    1107           0 :   NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
    1108             : 
    1109             :   uint64_t innerID;
    1110           0 :   nsresult rv = wrapper->GetData(&innerID);
    1111           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1112             : 
    1113             :   // Make a copy of mServers to iterate over, because closing a server
    1114             :   // can remove entries from mServers.
    1115           0 :   nsCOMArray<FlyWebPublishedServer> serversCopy;
    1116           0 :   for (FlyWebPublishedServer* server : mServers) {
    1117           0 :     serversCopy.AppendElement(server);
    1118             :   }
    1119             : 
    1120           0 :   for (FlyWebPublishedServer* server : serversCopy) {
    1121           0 :     if (server->OwnerWindowID() == innerID) {
    1122           0 :       server->Close();
    1123             :     }
    1124             :   }
    1125             : 
    1126           0 :   return NS_OK;
    1127             : }
    1128             : 
    1129             : void
    1130           0 : FlyWebService::UnregisterServer(FlyWebPublishedServer* aServer)
    1131             : {
    1132           0 :   MOZ_ASSERT(NS_IsMainThread());
    1133           0 :   DebugOnly<bool> removed = mServers.RemoveElement(aServer);
    1134           0 :   MOZ_ASSERT(removed);
    1135           0 : }
    1136             : 
    1137             : bool
    1138           0 : FlyWebService::HasConnectionOrServer(uint64_t aWindowID)
    1139             : {
    1140           0 :   MOZ_ASSERT(NS_IsMainThread());
    1141           0 :   for (FlyWebPublishedServer* server : mServers) {
    1142           0 :     nsPIDOMWindowInner* win = server->GetOwner();
    1143           0 :     if (win && win->WindowID() == aWindowID) {
    1144           0 :       return true;
    1145             :     }
    1146             :   }
    1147             : 
    1148           0 :   return false;
    1149             : }
    1150             : 
    1151             : void
    1152           0 : FlyWebService::NotifyDiscoveredServicesChanged()
    1153             : {
    1154             :   // Process the service map, add to the pair map.
    1155           0 :   for (auto iter = mDiscoveryManagerTable.Iter(); !iter.Done(); iter.Next()) {
    1156           0 :     iter.Get()->GetKey()->NotifyDiscoveredServicesChanged();
    1157             :   }
    1158           0 : }
    1159             : 
    1160             : void
    1161           0 : FlyWebService::ListDiscoveredServices(nsTArray<FlyWebDiscoveredService>& aServices)
    1162             : {
    1163           0 :   MOZ_ASSERT(NS_IsMainThread());
    1164           0 :   if (mMDNSHttpService) {
    1165           0 :     mMDNSHttpService->ListDiscoveredServices(aServices);
    1166             :   }
    1167           0 :   if (mMDNSFlywebService) {
    1168           0 :     mMDNSFlywebService->ListDiscoveredServices(aServices);
    1169             :   }
    1170           0 : }
    1171             : 
    1172             : void
    1173           0 : FlyWebService::PairWithService(const nsAString& aServiceId,
    1174             :                                FlyWebPairingCallback& aCallback)
    1175             : {
    1176           0 :   MOZ_ASSERT(NS_IsMainThread());
    1177             :   // See if we have already paired with this service.  If so, re-use the
    1178             :   // FlyWebPairedService for that.
    1179             :   {
    1180           0 :     ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
    1181           0 :     for (auto iter = mPairedServiceTable.Iter(); !iter.Done(); iter.Next()) {
    1182           0 :       PairedInfo* pairInfo = iter.UserData();
    1183           0 :       if (pairInfo->mService.mDiscoveredService.mServiceId.Equals(aServiceId)) {
    1184           0 :         ErrorResult er;
    1185           0 :         ReentrantMonitorAutoExit pairedMapRelease(mMonitor);
    1186           0 :         aCallback.PairingSucceeded(pairInfo->mService, er);
    1187           0 :         ENSURE_SUCCESS_VOID(er);
    1188           0 :         return;
    1189             :       }
    1190             :     }
    1191             :   }
    1192             : 
    1193           0 :   UniquePtr<PairedInfo> pairInfo;
    1194             : 
    1195           0 :   nsresult rv = NS_OK;
    1196           0 :   bool notFound = false;
    1197           0 :   if (mMDNSHttpService && mMDNSHttpService->HasService(aServiceId)) {
    1198           0 :     rv = mMDNSHttpService->PairWithService(aServiceId, pairInfo);
    1199           0 :   } else if (mMDNSFlywebService && mMDNSFlywebService->HasService(aServiceId)) {
    1200           0 :     rv = mMDNSFlywebService->PairWithService(aServiceId, pairInfo);
    1201             :   } else {
    1202           0 :     notFound = true;
    1203             :   }
    1204             : 
    1205           0 :   if (NS_FAILED(rv)) {
    1206           0 :     ErrorResult result;
    1207           0 :     result.ThrowWithCustomCleanup(rv);
    1208           0 :     const nsAString& reason = NS_LITERAL_STRING("Error pairing.");
    1209           0 :     aCallback.PairingFailed(reason, result);
    1210           0 :     ENSURE_SUCCESS_VOID(result);
    1211           0 :     return;
    1212             :   }
    1213             : 
    1214           0 :   if (!pairInfo) {
    1215           0 :     ErrorResult res;
    1216             :     const nsAString& reason = notFound ?
    1217           0 :       NS_LITERAL_STRING("No such service.") :
    1218           0 :       NS_LITERAL_STRING("Error pairing.");
    1219           0 :     aCallback.PairingFailed(reason, res);
    1220           0 :     ENSURE_SUCCESS_VOID(res);
    1221           0 :     return;
    1222             :   }
    1223             : 
    1224             :   // Add fingerprint to certificate override database.
    1225           0 :   if (!pairInfo->mService.mDiscoveredService.mCert.IsEmpty()) {
    1226             :     nsCOMPtr<nsICertOverrideService> override =
    1227           0 :       do_GetService("@mozilla.org/security/certoverride;1");
    1228           0 :     if (!override ||
    1229           0 :         NS_FAILED(override->RememberTemporaryValidityOverrideUsingFingerprint(
    1230             :           NS_ConvertUTF16toUTF8(pairInfo->mService.mHostname),
    1231             :           -1,
    1232             :           NS_ConvertUTF16toUTF8(pairInfo->mService.mDiscoveredService.mCert),
    1233             :           nsICertOverrideService::ERROR_UNTRUSTED |
    1234             :           nsICertOverrideService::ERROR_MISMATCH))) {
    1235           0 :       ErrorResult res;
    1236           0 :       aCallback.PairingFailed(NS_LITERAL_STRING("Error adding certificate override."), res);
    1237           0 :       ENSURE_SUCCESS_VOID(res);
    1238           0 :       return;
    1239             :     }
    1240             :   }
    1241             : 
    1242             :   // Grab a weak reference to the PairedInfo so that we can
    1243             :   // use it even after ownership has been transferred to mPairedServiceTable
    1244           0 :   PairedInfo* pairInfoWeak = pairInfo.release();
    1245             : 
    1246             :   {
    1247           0 :     ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
    1248           0 :     mPairedServiceTable.Put(
    1249           0 :       NS_ConvertUTF16toUTF8(pairInfoWeak->mService.mHostname), pairInfoWeak);
    1250             :   }
    1251             : 
    1252           0 :   ErrorResult er;
    1253           0 :   aCallback.PairingSucceeded(pairInfoWeak->mService, er);
    1254           0 :   ENSURE_SUCCESS_VOID(er);
    1255             : }
    1256             : 
    1257             : nsresult
    1258           0 : FlyWebService::CreateTransportForHost(const char **types,
    1259             :                                       uint32_t typeCount,
    1260             :                                       const nsACString &host,
    1261             :                                       int32_t port,
    1262             :                                       const nsACString &hostRoute,
    1263             :                                       int32_t portRoute,
    1264             :                                       nsIProxyInfo *proxyInfo,
    1265             :                                       nsISocketTransport **result)
    1266             : {
    1267             :   // This might be called on background threads
    1268             : 
    1269           0 :   *result = nullptr;
    1270             : 
    1271           0 :   nsCString ipAddrString;
    1272             :   uint16_t discPort;
    1273             : 
    1274             :   {
    1275           0 :     ReentrantMonitorAutoEnter pairedMapLock(mMonitor);
    1276             : 
    1277           0 :     PairedInfo* info = mPairedServiceTable.Get(host);
    1278             : 
    1279           0 :     if (!info) {
    1280           0 :       return NS_OK;
    1281             :     }
    1282             : 
    1283             :     // Get the ip address of the underlying service.
    1284           0 :     info->mDNSServiceInfo->GetAddress(ipAddrString);
    1285           0 :     info->mDNSServiceInfo->GetPort(&discPort);
    1286             :   }
    1287             : 
    1288             :   // Parse it into an NetAddr.
    1289             :   PRNetAddr prNetAddr;
    1290           0 :   PRStatus status = PR_StringToNetAddr(ipAddrString.get(), &prNetAddr);
    1291           0 :   NS_ENSURE_FALSE(status == PR_FAILURE, NS_ERROR_FAILURE);
    1292             : 
    1293             :   // Convert PRNetAddr to NetAddr.
    1294             :   mozilla::net::NetAddr netAddr;
    1295           0 :   PRNetAddrToNetAddr(&prNetAddr, &netAddr);
    1296           0 :   netAddr.inet.port = htons(discPort);
    1297             : 
    1298           0 :   RefPtr<mozilla::net::nsSocketTransport> trans = new mozilla::net::nsSocketTransport();
    1299           0 :   nsresult rv = trans->InitPreResolved(
    1300           0 :     types, typeCount, host, port, hostRoute, portRoute, proxyInfo, &netAddr);
    1301           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1302             : 
    1303           0 :   trans.forget(result);
    1304           0 :   return NS_OK;
    1305             : }
    1306             : 
    1307             : void
    1308           0 : FlyWebService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer)
    1309             : {
    1310           0 :   MOZ_ASSERT(NS_IsMainThread());
    1311           0 :   nsresult rv = mMDNSFlywebService ?
    1312           0 :     mMDNSFlywebService->StartDiscoveryOf(aServer) :
    1313           0 :     NS_ERROR_FAILURE;
    1314             : 
    1315           0 :   if (NS_FAILED(rv)) {
    1316           0 :     aServer->PublishedServerStarted(rv);
    1317             :   }
    1318           0 : }
    1319             : 
    1320             : } // namespace dom
    1321             : } // namespace mozilla

Generated by: LCOV version 1.13