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"
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"
19 //-----------------------------------------------------------------------------
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
,
43 ChildDNSService::ChildDNSService()
46 , mPendingRequestsLock("DNSPendingRequestsLock")
48 MOZ_ASSERT(IsNeckoChild());
51 ChildDNSService::~ChildDNSService()
57 ChildDNSService::GetDNSRecordHashKey(const nsACString
&aHost
,
59 nsIDNSListener
* aListener
,
62 aHashKey
.Assign(aHost
);
63 aHashKey
.AppendInt(aFlags
);
64 aHashKey
.AppendPrintf("%p", aListener
);
67 //-----------------------------------------------------------------------------
68 // ChildDNSService::nsIDNSService
69 //-----------------------------------------------------------------------------
72 ChildDNSService::AsyncResolve(const nsACString
&hostname
,
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.
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
);
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
);
116 GetDNSRecordHashKey(hostname
, originalFlags
, originalListener
, key
);
117 nsTArray
<nsRefPtr
<DNSRequestChild
>> *hashEntry
;
118 if (mPendingRequests
.Get(key
, &hashEntry
)) {
119 hashEntry
->AppendElement(childReq
);
121 hashEntry
= new nsTArray
<nsRefPtr
<DNSRequestChild
>>();
122 hashEntry
->AppendElement(childReq
);
123 mPendingRequests
.Put(key
, hashEntry
);
127 childReq
->StartRequest();
129 childReq
.forget(result
);
134 ChildDNSService::CancelAsyncResolve(const nsACString
&aHostname
,
136 nsIDNSListener
*aListener
,
139 if (mDisablePrefetch
&& (aFlags
& RESOLVE_SPECULATE
)) {
140 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL
;
143 MutexAutoLock
lock(mPendingRequestsLock
);
144 nsTArray
<nsRefPtr
<DNSRequestChild
>> *hashEntry
;
146 GetDNSRecordHashKey(aHostname
, aFlags
, aListener
, key
);
147 if (mPendingRequests
.Get(key
, &hashEntry
)) {
148 // We cancel just one.
149 hashEntry
->ElementAt(0)->Cancel(aReason
);
156 ChildDNSService::Resolve(const nsACString
&hostname
,
158 nsIDNSRecord
**result
)
160 // not planning to ever support this, since sync IPDL is evil.
161 return NS_ERROR_NOT_AVAILABLE
;
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
;
174 ChildDNSService::GetMyHostName(nsACString
&result
)
176 // TODO: get value from parent during PNecko construction?
177 return NS_ERROR_NOT_AVAILABLE
;
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
);
188 wrapper
->GetOriginalListener(getter_AddRefs(originalListener
));
189 if (NS_WARN_IF(!originalListener
)) {
190 MOZ_ASSERT(originalListener
);
195 MutexAutoLock
lock(mPendingRequestsLock
);
198 GetDNSRecordHashKey(aDnsRequest
->mHost
, originalFlags
, originalListener
, key
);
200 nsTArray
<nsRefPtr
<DNSRequestChild
>> *hashEntry
;
202 if (mPendingRequests
.Get(key
, &hashEntry
)) {
204 if ((idx
= hashEntry
->IndexOf(aDnsRequest
))) {
205 hashEntry
->RemoveElementAt(idx
);
206 if (hashEntry
->IsEmpty()) {
207 mPendingRequests
.Remove(key
);
213 //-----------------------------------------------------------------------------
214 // ChildDNSService::nsPIDNSService
215 //-----------------------------------------------------------------------------
218 ChildDNSService::Init()
220 // Disable prefetching either by explicit preference or if a manual proxy
222 bool disablePrefetch
= false;
223 int proxyType
= nsIProtocolProxyService::PROXYCONFIG_DIRECT
;
225 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
);
226 prefs
->GetBoolPref(kPrefNameDisablePrefetch
, &disablePrefetch
);
228 prefs
->GetIntPref("network.proxy.type", &proxyType
);
229 prefs
->GetBoolPref(kPrefNameDisablePrefetch
, &disablePrefetch
);
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
);
250 ChildDNSService::Shutdown()
256 ChildDNSService::GetPrefetchEnabled(bool *outVal
)
258 *outVal
= !mDisablePrefetch
;
263 ChildDNSService::SetPrefetchEnabled(bool inVal
)
265 mDisablePrefetch
= !inVal
;
270 ChildDNSService::GetOffline(bool* aResult
)
277 ChildDNSService::SetOffline(bool value
)
283 //-----------------------------------------------------------------------------
284 // ChildDNSService::nsIObserver
285 //-----------------------------------------------------------------------------
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");
301 } // namespace mozilla