diff -r 000000000000 -r 6474c204b198 netwerk/dns/ChildDNSService.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/netwerk/dns/ChildDNSService.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,231 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/net/ChildDNSService.h" +#include "nsIDNSListener.h" +#include "nsNetUtil.h" +#include "nsIThread.h" +#include "nsThreadUtils.h" +#include "nsIXPConnect.h" +#include "nsIPrefService.h" +#include "nsIProtocolProxyService.h" +#include "mozilla/net/NeckoChild.h" +#include "mozilla/net/DNSRequestChild.h" +#include "mozilla/net/DNSListenerProxy.h" + +namespace mozilla { +namespace net { + +//----------------------------------------------------------------------------- +// ChildDNSService +//----------------------------------------------------------------------------- + +static ChildDNSService *gChildDNSService; +static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch"; + +ChildDNSService* ChildDNSService::GetSingleton() +{ + MOZ_ASSERT(IsNeckoChild()); + + if (!gChildDNSService) { + gChildDNSService = new ChildDNSService(); + } + + NS_ADDREF(gChildDNSService); + return gChildDNSService; +} + +NS_IMPL_ISUPPORTS(ChildDNSService, + nsIDNSService, + nsPIDNSService, + nsIObserver) + +ChildDNSService::ChildDNSService() + : mFirstTime(true) + , mOffline(false) +{ + MOZ_ASSERT(IsNeckoChild()); +} + +ChildDNSService::~ChildDNSService() +{ + +} + +//----------------------------------------------------------------------------- +// ChildDNSService::nsIDNSService +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ChildDNSService::AsyncResolve(const nsACString &hostname, + uint32_t flags, + nsIDNSListener *listener, + nsIEventTarget *target_, + nsICancelable **result) +{ + NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE); + + if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) { + return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; + } + + // Support apps being 'offline' even if parent is not: avoids DNS traffic by + // apps that have been told they are offline. + if (mOffline) { + flags |= RESOLVE_OFFLINE; + } + + // make sure JS callers get notification on the main thread + nsCOMPtr target = target_; + nsCOMPtr wrappedListener = do_QueryInterface(listener); + if (wrappedListener && !target) { + nsCOMPtr mainThread; + NS_GetMainThread(getter_AddRefs(mainThread)); + target = do_QueryInterface(mainThread); + } + if (target) { + // Guarantee listener freed on main thread. Not sure we need this in child + // (or in parent in nsDNSService.cpp) but doesn't hurt. + listener = new DNSListenerProxy(listener, target); + } + + nsRefPtr childReq = + new DNSRequestChild(nsCString(hostname), flags, listener, target); + + childReq->StartRequest(); + + childReq.forget(result); + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::CancelAsyncResolve(const nsACString &aHostname, + uint32_t aFlags, + nsIDNSListener *aListener, + nsresult aReason) +{ + if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) { + return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; + } + + // TODO: keep a hashtable of pending requests, so we can obey cancel semantics + // (call OnLookupComplete with aReason). Also possible we could send IPDL to + // parent to cancel. + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +ChildDNSService::Resolve(const nsACString &hostname, + uint32_t flags, + nsIDNSRecord **result) +{ + // not planning to ever support this, since sync IPDL is evil. + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +ChildDNSService::GetDNSCacheEntries(nsTArray *args) +{ + // Only used by networking dashboard, so may not ever need this in child. + // (and would provide a way to spy on what hosts other apps are connecting to, + // unless we start keeping per-app DNS caches). + return NS_ERROR_NOT_AVAILABLE; +} + +NS_IMETHODIMP +ChildDNSService::GetMyHostName(nsACString &result) +{ + // TODO: get value from parent during PNecko construction? + return NS_ERROR_NOT_AVAILABLE; +} + +//----------------------------------------------------------------------------- +// ChildDNSService::nsPIDNSService +//----------------------------------------------------------------------------- + +nsresult +ChildDNSService::Init() +{ + // Disable prefetching either by explicit preference or if a manual proxy + // is configured + bool disablePrefetch = false; + int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT; + + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch); + if (prefs) { + prefs->GetIntPref("network.proxy.type", &proxyType); + prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch); + } + + if (mFirstTime) { + mFirstTime = false; + if (prefs) { + prefs->AddObserver(kPrefNameDisablePrefetch, this, false); + + // Monitor these to see if there is a change in proxy configuration + // If a manual proxy is in use, disable prefetch implicitly + prefs->AddObserver("network.proxy.type", this, false); + } + } + + mDisablePrefetch = disablePrefetch || + (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL); + + return NS_OK; +} + +nsresult +ChildDNSService::Shutdown() +{ + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::GetPrefetchEnabled(bool *outVal) +{ + *outVal = !mDisablePrefetch; + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::SetPrefetchEnabled(bool inVal) +{ + mDisablePrefetch = !inVal; + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::GetOffline(bool* aResult) +{ + *aResult = mOffline; + return NS_OK; +} + +NS_IMETHODIMP +ChildDNSService::SetOffline(bool value) +{ + mOffline = value; + return NS_OK; +} + +//----------------------------------------------------------------------------- +// ChildDNSService::nsIObserver +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +ChildDNSService::Observe(nsISupports *subject, const char *topic, + const char16_t *data) +{ + // we are only getting called if a preference has changed. + NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0, + "unexpected observe call"); + + // Reread prefs + Init(); + return NS_OK; +} + +} // namespace net +} // namespace mozilla