LCOV - code coverage report
Current view: top level - netwerk/dns - ChildDNSService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 30 155 19.4 %
Date: 2017-07-14 16:53:18 Functions: 7 27 25.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "mozilla/net/ChildDNSService.h"
       6             : #include "nsIDNSListener.h"
       7             : #include "nsIIOService.h"
       8             : #include "nsIThread.h"
       9             : #include "nsThreadUtils.h"
      10             : #include "nsIXPConnect.h"
      11             : #include "nsIPrefService.h"
      12             : #include "nsIProtocolProxyService.h"
      13             : #include "nsNetCID.h"
      14             : #include "mozilla/SystemGroup.h"
      15             : #include "mozilla/net/NeckoChild.h"
      16             : #include "mozilla/net/DNSListenerProxy.h"
      17             : #include "nsServiceManagerUtils.h"
      18             : 
      19             : namespace mozilla {
      20             : namespace net {
      21             : 
      22             : //-----------------------------------------------------------------------------
      23             : // ChildDNSService
      24             : //-----------------------------------------------------------------------------
      25             : 
      26             : static ChildDNSService *gChildDNSService;
      27             : static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch";
      28             : 
      29           2 : ChildDNSService* ChildDNSService::GetSingleton()
      30             : {
      31           2 :   MOZ_ASSERT(IsNeckoChild());
      32             : 
      33           2 :   if (!gChildDNSService) {
      34           2 :     gChildDNSService = new ChildDNSService();
      35             :   }
      36             : 
      37           2 :   NS_ADDREF(gChildDNSService);
      38           2 :   return gChildDNSService;
      39             : }
      40             : 
      41          66 : NS_IMPL_ISUPPORTS(ChildDNSService,
      42             :                   nsIDNSService,
      43             :                   nsPIDNSService,
      44             :                   nsIObserver)
      45             : 
      46           2 : ChildDNSService::ChildDNSService()
      47             :   : mFirstTime(true)
      48             :   , mDisablePrefetch(false)
      49           2 :   , mPendingRequestsLock("DNSPendingRequestsLock")
      50             : {
      51           2 :   MOZ_ASSERT(IsNeckoChild());
      52           2 : }
      53             : 
      54           0 : ChildDNSService::~ChildDNSService()
      55             : {
      56             : 
      57           0 : }
      58             : 
      59             : void
      60           0 : ChildDNSService::GetDNSRecordHashKey(const nsACString &aHost,
      61             :                                      const OriginAttributes &aOriginAttributes,
      62             :                                      uint32_t aFlags,
      63             :                                      const nsACString &aNetworkInterface,
      64             :                                      nsIDNSListener* aListener,
      65             :                                      nsACString &aHashKey)
      66             : {
      67           0 :   aHashKey.Assign(aHost);
      68             : 
      69           0 :   nsAutoCString originSuffix;
      70           0 :   aOriginAttributes.CreateSuffix(originSuffix);
      71           0 :   aHashKey.Assign(originSuffix);
      72             : 
      73           0 :   aHashKey.AppendInt(aFlags);
      74           0 :   if (!aNetworkInterface.IsEmpty()) {
      75           0 :     aHashKey.Append(aNetworkInterface);
      76             :   }
      77           0 :   aHashKey.AppendPrintf("%p", aListener);
      78           0 : }
      79             : 
      80             : //-----------------------------------------------------------------------------
      81             : // ChildDNSService::nsIDNSService
      82             : //-----------------------------------------------------------------------------
      83             : 
      84             : NS_IMETHODIMP
      85           0 : ChildDNSService::AsyncResolve(const nsACString  &hostname,
      86             :                               uint32_t           flags,
      87             :                               nsIDNSListener    *listener,
      88             :                               nsIEventTarget    *target_,
      89             :                               JS::HandleValue    aOriginAttributes,
      90             :                               JSContext         *aCx,
      91             :                               uint8_t            aArgc,
      92             :                               nsICancelable    **result)
      93             : {
      94           0 :   OriginAttributes attrs;
      95             : 
      96           0 :   if (aArgc == 1) {
      97           0 :     if (!aOriginAttributes.isObject() ||
      98           0 :         !attrs.Init(aCx, aOriginAttributes)) {
      99           0 :       return NS_ERROR_INVALID_ARG;
     100             :     }
     101             :   }
     102             : 
     103           0 :   return AsyncResolveExtendedNative(hostname, flags, EmptyCString(),
     104             :                                     listener, target_, attrs,
     105           0 :                                     result);
     106             : }
     107             : 
     108             : NS_IMETHODIMP
     109           0 : ChildDNSService::AsyncResolveNative(const nsACString        &hostname,
     110             :                                     uint32_t                 flags,
     111             :                                     nsIDNSListener          *listener,
     112             :                                     nsIEventTarget          *target_,
     113             :                                     const OriginAttributes  &aOriginAttributes,
     114             :                                     nsICancelable          **result)
     115             : {
     116           0 :   return AsyncResolveExtendedNative(hostname, flags, EmptyCString(),
     117             :                                     listener, target_, aOriginAttributes,
     118           0 :                                     result);
     119             : }
     120             : 
     121             : NS_IMETHODIMP
     122           0 : ChildDNSService::AsyncResolveExtended(const nsACString  &aHostname,
     123             :                                       uint32_t           flags,
     124             :                                       const nsACString  &aNetworkInterface,
     125             :                                       nsIDNSListener    *listener,
     126             :                                       nsIEventTarget    *target_,
     127             :                                       JS::HandleValue    aOriginAttributes,
     128             :                                       JSContext         *aCx,
     129             :                                       uint8_t            aArgc,
     130             :                                       nsICancelable    **result)
     131             : {
     132           0 :     OriginAttributes attrs;
     133             : 
     134           0 :     if (aArgc == 1) {
     135           0 :       if (!aOriginAttributes.isObject() ||
     136           0 :           !attrs.Init(aCx, aOriginAttributes)) {
     137           0 :           return NS_ERROR_INVALID_ARG;
     138             :       }
     139             :     }
     140             : 
     141             :     return AsyncResolveExtendedNative(aHostname, flags, aNetworkInterface,
     142             :                                       listener, target_, attrs,
     143           0 :                                       result);
     144             : }
     145             : 
     146             : NS_IMETHODIMP
     147           0 : ChildDNSService::AsyncResolveExtendedNative(const nsACString        &hostname,
     148             :                                             uint32_t                 flags,
     149             :                                             const nsACString        &aNetworkInterface,
     150             :                                             nsIDNSListener          *listener,
     151             :                                             nsIEventTarget          *target_,
     152             :                                             const OriginAttributes  &aOriginAttributes,
     153             :                                             nsICancelable          **result)
     154             : {
     155           0 :   NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
     156             : 
     157           0 :   if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) {
     158           0 :     return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     159             :   }
     160             : 
     161             :   // We need original flags for the pending requests hash.
     162           0 :   uint32_t originalFlags = flags;
     163             : 
     164             :   // Support apps being 'offline' even if parent is not: avoids DNS traffic by
     165             :   // apps that have been told they are offline.
     166           0 :   if (GetOffline()) {
     167           0 :     flags |= RESOLVE_OFFLINE;
     168             :   }
     169             : 
     170             :   // We need original listener for the pending requests hash.
     171           0 :   nsIDNSListener *originalListener = listener;
     172             : 
     173             :   // make sure JS callers get notification on the main thread
     174           0 :   nsCOMPtr<nsIEventTarget> target = target_;
     175           0 :   nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
     176           0 :   if (wrappedListener && !target) {
     177           0 :     target = SystemGroup::EventTargetFor(TaskCategory::Network);
     178             :   }
     179           0 :   if (target) {
     180             :     // Guarantee listener freed on main thread.  Not sure we need this in child
     181             :     // (or in parent in nsDNSService.cpp) but doesn't hurt.
     182           0 :     listener = new DNSListenerProxy(listener, target);
     183             :   }
     184             : 
     185             :   RefPtr<DNSRequestChild> childReq =
     186           0 :     new DNSRequestChild(nsCString(hostname),
     187             :                         aOriginAttributes,
     188             :                         flags,
     189           0 :                         nsCString(aNetworkInterface),
     190           0 :                         listener, target);
     191             : 
     192             :   {
     193           0 :     MutexAutoLock lock(mPendingRequestsLock);
     194           0 :     nsCString key;
     195             :     GetDNSRecordHashKey(hostname, aOriginAttributes, originalFlags, aNetworkInterface,
     196           0 :                         originalListener, key);
     197             :     nsTArray<RefPtr<DNSRequestChild>> *hashEntry;
     198           0 :     if (mPendingRequests.Get(key, &hashEntry)) {
     199           0 :       hashEntry->AppendElement(childReq);
     200             :     } else {
     201           0 :       hashEntry = new nsTArray<RefPtr<DNSRequestChild>>();
     202           0 :       hashEntry->AppendElement(childReq);
     203           0 :       mPendingRequests.Put(key, hashEntry);
     204             :     }
     205             :   }
     206             : 
     207           0 :   childReq->StartRequest();
     208             : 
     209           0 :   childReq.forget(result);
     210           0 :   return NS_OK;
     211             : }
     212             : 
     213             : NS_IMETHODIMP
     214           0 : ChildDNSService::CancelAsyncResolve(const nsACString  &aHostname,
     215             :                                     uint32_t           aFlags,
     216             :                                     nsIDNSListener    *aListener,
     217             :                                     nsresult           aReason,
     218             :                                     JS::HandleValue    aOriginAttributes,
     219             :                                     JSContext         *aCx,
     220             :                                     uint8_t            aArgc)
     221             : {
     222           0 :   OriginAttributes attrs;
     223             : 
     224           0 :   if (aArgc == 1) {
     225           0 :     if (!aOriginAttributes.isObject() ||
     226           0 :         !attrs.Init(aCx, aOriginAttributes)) {
     227           0 :         return NS_ERROR_INVALID_ARG;
     228             :     }
     229             :   }
     230             : 
     231           0 :   return CancelAsyncResolveExtendedNative(aHostname, aFlags, EmptyCString(),
     232           0 :                                           aListener, aReason, attrs);
     233             : }
     234             : 
     235             : NS_IMETHODIMP
     236           0 : ChildDNSService::CancelAsyncResolveNative(const nsACString       &aHostname,
     237             :                                           uint32_t                aFlags,
     238             :                                           nsIDNSListener         *aListener,
     239             :                                           nsresult                aReason,
     240             :                                           const OriginAttributes &aOriginAttributes)
     241             : {
     242           0 :   return CancelAsyncResolveExtendedNative(aHostname, aFlags, EmptyCString(),
     243           0 :                                           aListener, aReason, aOriginAttributes);
     244             : }
     245             : 
     246             : NS_IMETHODIMP
     247           0 : ChildDNSService::CancelAsyncResolveExtended(const nsACString &aHostname,
     248             :                                             uint32_t          aFlags,
     249             :                                             const nsACString &aNetworkInterface,
     250             :                                             nsIDNSListener   *aListener,
     251             :                                             nsresult          aReason,
     252             :                                             JS::HandleValue   aOriginAttributes,
     253             :                                             JSContext        *aCx,
     254             :                                             uint8_t           aArgc)
     255             : {
     256           0 :   OriginAttributes attrs;
     257             : 
     258           0 :   if (aArgc == 1) {
     259           0 :     if (!aOriginAttributes.isObject() ||
     260           0 :         !attrs.Init(aCx, aOriginAttributes)) {
     261           0 :         return NS_ERROR_INVALID_ARG;
     262             :     }
     263             :   }
     264             : 
     265             :   return CancelAsyncResolveExtendedNative(aHostname, aFlags, aNetworkInterface,
     266           0 :                                           aListener, aReason, attrs);
     267             : }
     268             : 
     269             : NS_IMETHODIMP
     270           0 : ChildDNSService::CancelAsyncResolveExtendedNative(const nsACString &aHostname,
     271             :                                                   uint32_t          aFlags,
     272             :                                                   const nsACString &aNetworkInterface,
     273             :                                                   nsIDNSListener   *aListener,
     274             :                                                   nsresult          aReason,
     275             :                                                   const OriginAttributes &aOriginAttributes)
     276             : {
     277           0 :   if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
     278           0 :     return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     279             :   }
     280             : 
     281           0 :   MutexAutoLock lock(mPendingRequestsLock);
     282             :   nsTArray<RefPtr<DNSRequestChild>> *hashEntry;
     283           0 :   nsCString key;
     284             :   GetDNSRecordHashKey(aHostname, aOriginAttributes, aFlags,
     285           0 :                       aNetworkInterface, aListener, key);
     286           0 :   if (mPendingRequests.Get(key, &hashEntry)) {
     287             :     // We cancel just one.
     288           0 :     hashEntry->ElementAt(0)->Cancel(aReason);
     289             :   }
     290             : 
     291           0 :   return NS_OK;
     292             : }
     293             : 
     294             : NS_IMETHODIMP
     295           0 : ChildDNSService::Resolve(const nsACString &hostname,
     296             :                          uint32_t          flags,
     297             :                          JS::HandleValue   aOriginAttributes,
     298             :                          JSContext        *aCx,
     299             :                          uint8_t           aArgc,
     300             :                          nsIDNSRecord    **result)
     301             : {
     302             :   // not planning to ever support this, since sync IPDL is evil.
     303           0 :   return NS_ERROR_NOT_AVAILABLE;
     304             : }
     305             : 
     306             : NS_IMETHODIMP
     307           0 : ChildDNSService::ResolveNative(const nsACString       &hostname,
     308             :                                uint32_t                flags,
     309             :                                const OriginAttributes &aOriginAttributes,
     310             :                                nsIDNSRecord          **result)
     311             : {
     312             :   // not planning to ever support this, since sync IPDL is evil.
     313           0 :   return NS_ERROR_NOT_AVAILABLE;
     314             : }
     315             : 
     316             : NS_IMETHODIMP
     317           0 : ChildDNSService::GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *args)
     318             : {
     319             :   // Only used by networking dashboard, so may not ever need this in child.
     320             :   // (and would provide a way to spy on what hosts other apps are connecting to,
     321             :   // unless we start keeping per-app DNS caches).
     322           0 :   return NS_ERROR_NOT_AVAILABLE;
     323             : }
     324             : 
     325             : NS_IMETHODIMP
     326           0 : ChildDNSService::GetMyHostName(nsACString &result)
     327             : {
     328             :   // TODO: get value from parent during PNecko construction?
     329           0 :   return NS_ERROR_NOT_AVAILABLE;
     330             : }
     331             : 
     332             : void
     333           0 : ChildDNSService::NotifyRequestDone(DNSRequestChild *aDnsRequest)
     334             : {
     335             :   // We need the original flags and listener for the pending requests hash.
     336           0 :   uint32_t originalFlags = aDnsRequest->mFlags & ~RESOLVE_OFFLINE;
     337           0 :   nsCOMPtr<nsIDNSListener> originalListener = aDnsRequest->mListener;
     338           0 :   nsCOMPtr<nsIDNSListenerProxy> wrapper = do_QueryInterface(originalListener);
     339           0 :   if (wrapper) {
     340           0 :     wrapper->GetOriginalListener(getter_AddRefs(originalListener));
     341           0 :     if (NS_WARN_IF(!originalListener)) {
     342           0 :       MOZ_ASSERT(originalListener);
     343           0 :       return;
     344             :     }
     345             :   }
     346             : 
     347           0 :   MutexAutoLock lock(mPendingRequestsLock);
     348             : 
     349           0 :   nsCString key;
     350           0 :   GetDNSRecordHashKey(aDnsRequest->mHost, aDnsRequest->mOriginAttributes, originalFlags,
     351           0 :                       aDnsRequest->mNetworkInterface, originalListener, key);
     352             : 
     353             :   nsTArray<RefPtr<DNSRequestChild>> *hashEntry;
     354             : 
     355           0 :   if (mPendingRequests.Get(key, &hashEntry)) {
     356             :     int idx;
     357           0 :     if ((idx = hashEntry->IndexOf(aDnsRequest))) {
     358           0 :       hashEntry->RemoveElementAt(idx);
     359           0 :       if (hashEntry->IsEmpty()) {
     360           0 :         mPendingRequests.Remove(key);
     361             :       }
     362             :     }
     363             :   }
     364             : }
     365             : 
     366             : //-----------------------------------------------------------------------------
     367             : // ChildDNSService::nsPIDNSService
     368             : //-----------------------------------------------------------------------------
     369             : 
     370             : nsresult
     371           6 : ChildDNSService::Init()
     372             : {
     373             :   // Disable prefetching either by explicit preference or if a manual proxy
     374             :   // is configured
     375           6 :   bool disablePrefetch = false;
     376           6 :   int  proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
     377             : 
     378          12 :   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     379           6 :   if (prefs) {
     380           6 :     prefs->GetIntPref("network.proxy.type", &proxyType);
     381           6 :     prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch);
     382             :   }
     383             : 
     384           6 :   if (mFirstTime) {
     385           2 :     mFirstTime = false;
     386           2 :     if (prefs) {
     387           2 :       prefs->AddObserver(kPrefNameDisablePrefetch, this, false);
     388             : 
     389             :       // Monitor these to see if there is a change in proxy configuration
     390             :       // If a manual proxy is in use, disable prefetch implicitly
     391           2 :       prefs->AddObserver("network.proxy.type", this, false);
     392             :     }
     393             :   }
     394             : 
     395          12 :   mDisablePrefetch = disablePrefetch ||
     396           6 :                      (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
     397             : 
     398          12 :   return NS_OK;
     399             : }
     400             : 
     401             : nsresult
     402           0 : ChildDNSService::Shutdown()
     403             : {
     404           0 :   return NS_OK;
     405             : }
     406             : 
     407             : NS_IMETHODIMP
     408           0 : ChildDNSService::GetPrefetchEnabled(bool *outVal)
     409             : {
     410           0 :   *outVal = !mDisablePrefetch;
     411           0 :   return NS_OK;
     412             : }
     413             : 
     414             : NS_IMETHODIMP
     415           0 : ChildDNSService::SetPrefetchEnabled(bool inVal)
     416             : {
     417           0 :   mDisablePrefetch = !inVal;
     418           0 :   return NS_OK;
     419             : }
     420             : 
     421             : bool
     422           0 : ChildDNSService::GetOffline() const
     423             : {
     424           0 :   bool offline = false;
     425           0 :   nsCOMPtr<nsIIOService> io = do_GetService(NS_IOSERVICE_CONTRACTID);
     426           0 :   if (io) {
     427           0 :     io->GetOffline(&offline);
     428             :   }
     429           0 :   return offline;
     430             : }
     431             : 
     432             : //-----------------------------------------------------------------------------
     433             : // ChildDNSService::nsIObserver
     434             : //-----------------------------------------------------------------------------
     435             : 
     436             : NS_IMETHODIMP
     437           4 : ChildDNSService::Observe(nsISupports *subject, const char *topic,
     438             :                          const char16_t *data)
     439             : {
     440             :   // we are only getting called if a preference has changed.
     441           4 :   NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
     442             :                "unexpected observe call");
     443             : 
     444             :   // Reread prefs
     445           4 :   Init();
     446           4 :   return NS_OK;
     447             : }
     448             : 
     449             : } // namespace net
     450             : } // namespace mozilla

Generated by: LCOV version 1.13