Bumping manifests a=b2g-bump
[gecko.git] / netwerk / dns / ChildDNSService.cpp
blob6a4fc7b208ae4edbfe1e817d044df33033665796
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/. */
5 #include "mozilla/net/ChildDNSService.h"
6 #include "nsIDNSListener.h"
7 #include "nsNetUtil.h"
8 #include "nsIThread.h"
9 #include "nsThreadUtils.h"
10 #include "nsIXPConnect.h"
11 #include "nsIPrefService.h"
12 #include "nsIProtocolProxyService.h"
13 #include "mozilla/net/NeckoChild.h"
14 #include "mozilla/net/DNSListenerProxy.h"
16 namespace mozilla {
17 namespace net {
19 //-----------------------------------------------------------------------------
20 // ChildDNSService
21 //-----------------------------------------------------------------------------
23 static ChildDNSService *gChildDNSService;
24 static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch";
26 ChildDNSService* ChildDNSService::GetSingleton()
28 MOZ_ASSERT(IsNeckoChild());
30 if (!gChildDNSService) {
31 gChildDNSService = new ChildDNSService();
34 NS_ADDREF(gChildDNSService);
35 return gChildDNSService;
38 NS_IMPL_ISUPPORTS(ChildDNSService,
39 nsIDNSService,
40 nsPIDNSService,
41 nsIObserver)
43 ChildDNSService::ChildDNSService()
44 : mFirstTime(true)
45 , mOffline(false)
46 , mPendingRequestsLock("DNSPendingRequestsLock")
48 MOZ_ASSERT(IsNeckoChild());
51 ChildDNSService::~ChildDNSService()
56 void
57 ChildDNSService::GetDNSRecordHashKey(const nsACString &aHost,
58 uint32_t aFlags,
59 const nsACString &aNetworkInterface,
60 nsIDNSListener* aListener,
61 nsACString &aHashKey)
63 aHashKey.Assign(aHost);
64 aHashKey.AppendInt(aFlags);
65 if (!aNetworkInterface.IsEmpty()) {
66 aHashKey.Append(aNetworkInterface);
68 aHashKey.AppendPrintf("%p", aListener);
71 //-----------------------------------------------------------------------------
72 // ChildDNSService::nsIDNSService
73 //-----------------------------------------------------------------------------
75 NS_IMETHODIMP
76 ChildDNSService::AsyncResolve(const nsACString &hostname,
77 uint32_t flags,
78 nsIDNSListener *listener,
79 nsIEventTarget *target_,
80 nsICancelable **result)
82 return AsyncResolveExtended(hostname, flags, EmptyCString(), listener,
83 target_, result);
86 NS_IMETHODIMP
87 ChildDNSService::AsyncResolveExtended(const nsACString &hostname,
88 uint32_t flags,
89 const nsACString &aNetworkInterface,
90 nsIDNSListener *listener,
91 nsIEventTarget *target_,
92 nsICancelable **result)
94 NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
96 if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) {
97 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
100 // We need original flags for the pending requests hash.
101 uint32_t originalFlags = flags;
103 // Support apps being 'offline' even if parent is not: avoids DNS traffic by
104 // apps that have been told they are offline.
105 if (mOffline) {
106 flags |= RESOLVE_OFFLINE;
109 // We need original listener for the pending requests hash.
110 nsIDNSListener *originalListener = listener;
112 // make sure JS callers get notification on the main thread
113 nsCOMPtr<nsIEventTarget> target = target_;
114 nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
115 if (wrappedListener && !target) {
116 nsCOMPtr<nsIThread> mainThread;
117 NS_GetMainThread(getter_AddRefs(mainThread));
118 target = do_QueryInterface(mainThread);
120 if (target) {
121 // Guarantee listener freed on main thread. Not sure we need this in child
122 // (or in parent in nsDNSService.cpp) but doesn't hurt.
123 listener = new DNSListenerProxy(listener, target);
126 nsRefPtr<DNSRequestChild> childReq =
127 new DNSRequestChild(nsCString(hostname), flags,
128 nsCString(aNetworkInterface),
129 listener, target);
132 MutexAutoLock lock(mPendingRequestsLock);
133 nsCString key;
134 GetDNSRecordHashKey(hostname, originalFlags, aNetworkInterface,
135 originalListener, key);
136 nsTArray<nsRefPtr<DNSRequestChild>> *hashEntry;
137 if (mPendingRequests.Get(key, &hashEntry)) {
138 hashEntry->AppendElement(childReq);
139 } else {
140 hashEntry = new nsTArray<nsRefPtr<DNSRequestChild>>();
141 hashEntry->AppendElement(childReq);
142 mPendingRequests.Put(key, hashEntry);
146 childReq->StartRequest();
148 childReq.forget(result);
149 return NS_OK;
152 NS_IMETHODIMP
153 ChildDNSService::CancelAsyncResolve(const nsACString &aHostname,
154 uint32_t aFlags,
155 nsIDNSListener *aListener,
156 nsresult aReason)
158 return CancelAsyncResolveExtended(aHostname, aFlags, EmptyCString(),
159 aListener, aReason);
162 NS_IMETHODIMP
163 ChildDNSService::CancelAsyncResolveExtended(const nsACString &aHostname,
164 uint32_t aFlags,
165 const nsACString &aNetworkInterface,
166 nsIDNSListener *aListener,
167 nsresult aReason)
169 if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
170 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
173 MutexAutoLock lock(mPendingRequestsLock);
174 nsTArray<nsRefPtr<DNSRequestChild>> *hashEntry;
175 nsCString key;
176 GetDNSRecordHashKey(aHostname, aFlags, aNetworkInterface, aListener, key);
177 if (mPendingRequests.Get(key, &hashEntry)) {
178 // We cancel just one.
179 hashEntry->ElementAt(0)->Cancel(aReason);
182 return NS_OK;
185 NS_IMETHODIMP
186 ChildDNSService::Resolve(const nsACString &hostname,
187 uint32_t flags,
188 nsIDNSRecord **result)
190 // not planning to ever support this, since sync IPDL is evil.
191 return NS_ERROR_NOT_AVAILABLE;
194 NS_IMETHODIMP
195 ChildDNSService::GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *args)
197 // Only used by networking dashboard, so may not ever need this in child.
198 // (and would provide a way to spy on what hosts other apps are connecting to,
199 // unless we start keeping per-app DNS caches).
200 return NS_ERROR_NOT_AVAILABLE;
203 NS_IMETHODIMP
204 ChildDNSService::GetMyHostName(nsACString &result)
206 // TODO: get value from parent during PNecko construction?
207 return NS_ERROR_NOT_AVAILABLE;
210 void
211 ChildDNSService::NotifyRequestDone(DNSRequestChild *aDnsRequest)
213 // We need the original flags and listener for the pending requests hash.
214 uint32_t originalFlags = aDnsRequest->mFlags & ~RESOLVE_OFFLINE;
215 nsCOMPtr<nsIDNSListener> originalListener = aDnsRequest->mListener;
216 nsCOMPtr<nsIDNSListenerProxy> wrapper = do_QueryInterface(originalListener);
217 if (wrapper) {
218 wrapper->GetOriginalListener(getter_AddRefs(originalListener));
219 if (NS_WARN_IF(!originalListener)) {
220 MOZ_ASSERT(originalListener);
221 return;
225 MutexAutoLock lock(mPendingRequestsLock);
227 nsCString key;
228 GetDNSRecordHashKey(aDnsRequest->mHost, originalFlags,
229 aDnsRequest->mNetworkInterface, originalListener, key);
231 nsTArray<nsRefPtr<DNSRequestChild>> *hashEntry;
233 if (mPendingRequests.Get(key, &hashEntry)) {
234 int idx;
235 if ((idx = hashEntry->IndexOf(aDnsRequest))) {
236 hashEntry->RemoveElementAt(idx);
237 if (hashEntry->IsEmpty()) {
238 mPendingRequests.Remove(key);
244 //-----------------------------------------------------------------------------
245 // ChildDNSService::nsPIDNSService
246 //-----------------------------------------------------------------------------
248 nsresult
249 ChildDNSService::Init()
251 // Disable prefetching either by explicit preference or if a manual proxy
252 // is configured
253 bool disablePrefetch = false;
254 int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
256 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
257 prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch);
258 if (prefs) {
259 prefs->GetIntPref("network.proxy.type", &proxyType);
260 prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch);
263 if (mFirstTime) {
264 mFirstTime = false;
265 if (prefs) {
266 prefs->AddObserver(kPrefNameDisablePrefetch, this, false);
268 // Monitor these to see if there is a change in proxy configuration
269 // If a manual proxy is in use, disable prefetch implicitly
270 prefs->AddObserver("network.proxy.type", this, false);
274 mDisablePrefetch = disablePrefetch ||
275 (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
277 return NS_OK;
280 nsresult
281 ChildDNSService::Shutdown()
283 return NS_OK;
286 NS_IMETHODIMP
287 ChildDNSService::GetPrefetchEnabled(bool *outVal)
289 *outVal = !mDisablePrefetch;
290 return NS_OK;
293 NS_IMETHODIMP
294 ChildDNSService::SetPrefetchEnabled(bool inVal)
296 mDisablePrefetch = !inVal;
297 return NS_OK;
300 NS_IMETHODIMP
301 ChildDNSService::GetOffline(bool* aResult)
303 *aResult = mOffline;
304 return NS_OK;
307 NS_IMETHODIMP
308 ChildDNSService::SetOffline(bool value)
310 mOffline = value;
311 return NS_OK;
314 //-----------------------------------------------------------------------------
315 // ChildDNSService::nsIObserver
316 //-----------------------------------------------------------------------------
318 NS_IMETHODIMP
319 ChildDNSService::Observe(nsISupports *subject, const char *topic,
320 const char16_t *data)
322 // we are only getting called if a preference has changed.
323 NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
324 "unexpected observe call");
326 // Reread prefs
327 Init();
328 return NS_OK;
331 } // namespace net
332 } // namespace mozilla