Bumping manifests a=b2g-bump
[gecko.git] / netwerk / dns / ChildDNSService.cpp
blob4de1ffdf7adcd3275cb8c33cae6e3865aa0870f4
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 nsIDNSListener* aListener,
60 nsACString &aHashKey)
62 aHashKey.Assign(aHost);
63 aHashKey.AppendInt(aFlags);
64 aHashKey.AppendPrintf("%p", aListener);
67 //-----------------------------------------------------------------------------
68 // ChildDNSService::nsIDNSService
69 //-----------------------------------------------------------------------------
71 NS_IMETHODIMP
72 ChildDNSService::AsyncResolve(const nsACString &hostname,
73 uint32_t flags,
74 nsIDNSListener *listener,
75 nsIEventTarget *target_,
76 nsICancelable **result)
78 NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
80 if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) {
81 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
84 // We need original flags for the pending requests hash.
85 uint32_t originalFlags = flags;
87 // Support apps being 'offline' even if parent is not: avoids DNS traffic by
88 // apps that have been told they are offline.
89 if (mOffline) {
90 flags |= RESOLVE_OFFLINE;
93 // We need original listener for the pending requests hash.
94 nsIDNSListener *originalListener = listener;
96 // make sure JS callers get notification on the main thread
97 nsCOMPtr<nsIEventTarget> target = target_;
98 nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
99 if (wrappedListener && !target) {
100 nsCOMPtr<nsIThread> mainThread;
101 NS_GetMainThread(getter_AddRefs(mainThread));
102 target = do_QueryInterface(mainThread);
104 if (target) {
105 // Guarantee listener freed on main thread. Not sure we need this in child
106 // (or in parent in nsDNSService.cpp) but doesn't hurt.
107 listener = new DNSListenerProxy(listener, target);
110 nsRefPtr<DNSRequestChild> childReq =
111 new DNSRequestChild(nsCString(hostname), flags, listener, target);
114 MutexAutoLock lock(mPendingRequestsLock);
115 nsCString key;
116 GetDNSRecordHashKey(hostname, originalFlags, originalListener, key);
117 nsTArray<nsRefPtr<DNSRequestChild>> *hashEntry;
118 if (mPendingRequests.Get(key, &hashEntry)) {
119 hashEntry->AppendElement(childReq);
120 } else {
121 hashEntry = new nsTArray<nsRefPtr<DNSRequestChild>>();
122 hashEntry->AppendElement(childReq);
123 mPendingRequests.Put(key, hashEntry);
127 childReq->StartRequest();
129 childReq.forget(result);
130 return NS_OK;
133 NS_IMETHODIMP
134 ChildDNSService::CancelAsyncResolve(const nsACString &aHostname,
135 uint32_t aFlags,
136 nsIDNSListener *aListener,
137 nsresult aReason)
139 if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
140 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
143 MutexAutoLock lock(mPendingRequestsLock);
144 nsTArray<nsRefPtr<DNSRequestChild>> *hashEntry;
145 nsCString key;
146 GetDNSRecordHashKey(aHostname, aFlags, aListener, key);
147 if (mPendingRequests.Get(key, &hashEntry)) {
148 // We cancel just one.
149 hashEntry->ElementAt(0)->Cancel(aReason);
152 return NS_OK;
155 NS_IMETHODIMP
156 ChildDNSService::Resolve(const nsACString &hostname,
157 uint32_t flags,
158 nsIDNSRecord **result)
160 // not planning to ever support this, since sync IPDL is evil.
161 return NS_ERROR_NOT_AVAILABLE;
164 NS_IMETHODIMP
165 ChildDNSService::GetDNSCacheEntries(nsTArray<mozilla::net::DNSCacheEntries> *args)
167 // Only used by networking dashboard, so may not ever need this in child.
168 // (and would provide a way to spy on what hosts other apps are connecting to,
169 // unless we start keeping per-app DNS caches).
170 return NS_ERROR_NOT_AVAILABLE;
173 NS_IMETHODIMP
174 ChildDNSService::GetMyHostName(nsACString &result)
176 // TODO: get value from parent during PNecko construction?
177 return NS_ERROR_NOT_AVAILABLE;
180 void
181 ChildDNSService::NotifyRequestDone(DNSRequestChild *aDnsRequest)
183 // We need the original flags and listener for the pending requests hash.
184 uint32_t originalFlags = aDnsRequest->mFlags & ~RESOLVE_OFFLINE;
185 nsCOMPtr<nsIDNSListener> originalListener = aDnsRequest->mListener;
186 nsCOMPtr<nsIDNSListenerProxy> wrapper = do_QueryInterface(originalListener);
187 if (wrapper) {
188 wrapper->GetOriginalListener(getter_AddRefs(originalListener));
189 if (NS_WARN_IF(!originalListener)) {
190 MOZ_ASSERT(originalListener);
191 return;
195 MutexAutoLock lock(mPendingRequestsLock);
197 nsCString key;
198 GetDNSRecordHashKey(aDnsRequest->mHost, originalFlags, originalListener, key);
200 nsTArray<nsRefPtr<DNSRequestChild>> *hashEntry;
202 if (mPendingRequests.Get(key, &hashEntry)) {
203 int idx;
204 if ((idx = hashEntry->IndexOf(aDnsRequest))) {
205 hashEntry->RemoveElementAt(idx);
206 if (hashEntry->IsEmpty()) {
207 mPendingRequests.Remove(key);
213 //-----------------------------------------------------------------------------
214 // ChildDNSService::nsPIDNSService
215 //-----------------------------------------------------------------------------
217 nsresult
218 ChildDNSService::Init()
220 // Disable prefetching either by explicit preference or if a manual proxy
221 // is configured
222 bool disablePrefetch = false;
223 int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
225 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
226 prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch);
227 if (prefs) {
228 prefs->GetIntPref("network.proxy.type", &proxyType);
229 prefs->GetBoolPref(kPrefNameDisablePrefetch, &disablePrefetch);
232 if (mFirstTime) {
233 mFirstTime = false;
234 if (prefs) {
235 prefs->AddObserver(kPrefNameDisablePrefetch, this, false);
237 // Monitor these to see if there is a change in proxy configuration
238 // If a manual proxy is in use, disable prefetch implicitly
239 prefs->AddObserver("network.proxy.type", this, false);
243 mDisablePrefetch = disablePrefetch ||
244 (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
246 return NS_OK;
249 nsresult
250 ChildDNSService::Shutdown()
252 return NS_OK;
255 NS_IMETHODIMP
256 ChildDNSService::GetPrefetchEnabled(bool *outVal)
258 *outVal = !mDisablePrefetch;
259 return NS_OK;
262 NS_IMETHODIMP
263 ChildDNSService::SetPrefetchEnabled(bool inVal)
265 mDisablePrefetch = !inVal;
266 return NS_OK;
269 NS_IMETHODIMP
270 ChildDNSService::GetOffline(bool* aResult)
272 *aResult = mOffline;
273 return NS_OK;
276 NS_IMETHODIMP
277 ChildDNSService::SetOffline(bool value)
279 mOffline = value;
280 return NS_OK;
283 //-----------------------------------------------------------------------------
284 // ChildDNSService::nsIObserver
285 //-----------------------------------------------------------------------------
287 NS_IMETHODIMP
288 ChildDNSService::Observe(nsISupports *subject, const char *topic,
289 const char16_t *data)
291 // we are only getting called if a preference has changed.
292 NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
293 "unexpected observe call");
295 // Reread prefs
296 Init();
297 return NS_OK;
300 } // namespace net
301 } // namespace mozilla