Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / netwerk / dns / ChildDNSService.cpp
blob8ef9f33329349aa63ecf66bf455c37a0e8106b3d
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 "nsDNSPrefetch.h"
7 #include "nsIDNSListener.h"
8 #include "nsIOService.h"
9 #include "nsThreadUtils.h"
10 #include "nsIXPConnect.h"
11 #include "nsIProtocolProxyService.h"
12 #include "nsNetCID.h"
13 #include "nsQueryObject.h"
14 #include "mozilla/ClearOnShutdown.h"
15 #include "mozilla/StaticPrefs_network.h"
16 #include "mozilla/StaticPtr.h"
17 #include "mozilla/SyncRunnable.h"
18 #include "mozilla/net/NeckoChild.h"
19 #include "mozilla/net/DNSListenerProxy.h"
20 #include "mozilla/net/TRRServiceParent.h"
21 #include "nsHostResolver.h"
22 #include "nsServiceManagerUtils.h"
23 #include "prsystem.h"
24 #include "DNSAdditionalInfo.h"
25 #include "TRRService.h"
27 namespace mozilla {
28 namespace net {
30 //-----------------------------------------------------------------------------
31 // ChildDNSService
32 //-----------------------------------------------------------------------------
34 static StaticRefPtr<ChildDNSService> gChildDNSService;
36 already_AddRefed<ChildDNSService> ChildDNSService::GetSingleton() {
37 MOZ_ASSERT_IF(nsIOService::UseSocketProcess(),
38 XRE_IsContentProcess() || XRE_IsParentProcess());
39 MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(),
40 XRE_IsContentProcess() || XRE_IsSocketProcess());
42 if (!gChildDNSService) {
43 if (NS_WARN_IF(!NS_IsMainThread())) {
44 return nullptr;
46 gChildDNSService = new ChildDNSService();
47 gChildDNSService->Init();
48 ClearOnShutdown(&gChildDNSService);
51 return do_AddRef(gChildDNSService);
54 NS_IMPL_ISUPPORTS_INHERITED(ChildDNSService, DNSServiceBase, nsIDNSService,
55 nsPIDNSService)
57 ChildDNSService::ChildDNSService() {
58 MOZ_ASSERT_IF(nsIOService::UseSocketProcess(),
59 XRE_IsContentProcess() || XRE_IsParentProcess());
60 MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(),
61 XRE_IsContentProcess() || XRE_IsSocketProcess());
62 if (XRE_IsParentProcess() && nsIOService::UseSocketProcess()) {
63 nsDNSPrefetch::Initialize(this);
64 mTRRServiceParent = new TRRServiceParent();
65 mTRRServiceParent->Init();
69 void ChildDNSService::GetDNSRecordHashKey(
70 const nsACString& aHost, const nsACString& aTrrServer, int32_t aPort,
71 uint16_t aType, const OriginAttributes& aOriginAttributes,
72 nsIDNSService::DNSFlags aFlags, uintptr_t aListenerAddr,
73 nsACString& aHashKey) {
74 aHashKey.Assign(aHost);
75 aHashKey.Assign(aTrrServer);
76 aHashKey.AppendInt(aPort);
77 aHashKey.AppendInt(aType);
79 nsAutoCString originSuffix;
80 aOriginAttributes.CreateSuffix(originSuffix);
81 aHashKey.Append(originSuffix);
83 aHashKey.AppendInt(aFlags);
84 aHashKey.AppendPrintf("0x%" PRIxPTR, aListenerAddr);
87 nsresult ChildDNSService::AsyncResolveInternal(
88 const nsACString& hostname, uint16_t type, nsIDNSService::DNSFlags flags,
89 nsIDNSAdditionalInfo* aInfo, nsIDNSListener* listener,
90 nsIEventTarget* target_, const OriginAttributes& aOriginAttributes,
91 nsICancelable** result) {
92 if (XRE_IsContentProcess()) {
93 NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
96 if (DNSForbiddenByActiveProxy(hostname, flags)) {
97 // nsHostResolver returns NS_ERROR_UNKNOWN_HOST for lots of reasons.
98 // We use a different error code to differentiate this failure and to make
99 // it clear(er) where this error comes from.
100 return NS_ERROR_UNKNOWN_PROXY_HOST;
103 bool resolveDNSInSocketProcess = false;
104 if (XRE_IsParentProcess() && nsIOService::UseSocketProcess()) {
105 resolveDNSInSocketProcess = true;
106 if (type != nsIDNSService::RESOLVE_TYPE_DEFAULT &&
107 (mTRRServiceParent->Mode() != nsIDNSService::MODE_TRRFIRST &&
108 mTRRServiceParent->Mode() != nsIDNSService::MODE_TRRONLY)) {
109 return NS_ERROR_UNKNOWN_HOST;
113 if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) {
114 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
117 // We need original listener for the pending requests hash.
118 uintptr_t originalListenerAddr = reinterpret_cast<uintptr_t>(listener);
120 // make sure JS callers get notification on the main thread
121 nsCOMPtr<nsIEventTarget> target = target_;
122 nsCOMPtr<nsIXPConnectWrappedJS> wrappedListener = do_QueryInterface(listener);
123 if (wrappedListener && !target) {
124 target = GetMainThreadSerialEventTarget();
126 if (target) {
127 // Guarantee listener freed on main thread. Not sure we need this in child
128 // (or in parent in nsDNSService.cpp) but doesn't hurt.
129 listener = new DNSListenerProxy(listener, target);
132 RefPtr<DNSRequestSender> sender = new DNSRequestSender(
133 hostname, DNSAdditionalInfo::URL(aInfo), DNSAdditionalInfo::Port(aInfo),
134 type, aOriginAttributes, flags, listener, target);
135 RefPtr<DNSRequestActor> dnsReq;
136 if (resolveDNSInSocketProcess) {
137 dnsReq = new DNSRequestParent(sender);
138 if (!mTRRServiceParent->TRRConnectionInfoInited()) {
139 mTRRServiceParent->InitTRRConnectionInfo();
141 } else {
142 dnsReq = new DNSRequestChild(sender);
146 MutexAutoLock lock(mPendingRequestsLock);
147 nsCString key;
148 GetDNSRecordHashKey(hostname, DNSAdditionalInfo::URL(aInfo),
149 DNSAdditionalInfo::Port(aInfo), type, aOriginAttributes,
150 flags, originalListenerAddr, key);
151 mPendingRequests.GetOrInsertNew(key)->AppendElement(sender);
154 sender->StartRequest();
156 sender.forget(result);
157 return NS_OK;
160 nsresult ChildDNSService::CancelAsyncResolveInternal(
161 const nsACString& aHostname, uint16_t aType, nsIDNSService::DNSFlags aFlags,
162 nsIDNSAdditionalInfo* aInfo, nsIDNSListener* aListener, nsresult aReason,
163 const OriginAttributes& aOriginAttributes) {
164 if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
165 return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
168 MutexAutoLock lock(mPendingRequestsLock);
169 nsTArray<RefPtr<DNSRequestSender>>* hashEntry;
170 nsCString key;
171 uintptr_t listenerAddr = reinterpret_cast<uintptr_t>(aListener);
172 GetDNSRecordHashKey(aHostname, DNSAdditionalInfo::URL(aInfo),
173 DNSAdditionalInfo::Port(aInfo), aType, aOriginAttributes,
174 aFlags, listenerAddr, key);
175 if (mPendingRequests.Get(key, &hashEntry)) {
176 // We cancel just one.
177 hashEntry->ElementAt(0)->Cancel(aReason);
180 return NS_OK;
183 //-----------------------------------------------------------------------------
184 // ChildDNSService::nsIDNSService
185 //-----------------------------------------------------------------------------
187 NS_IMETHODIMP
188 ChildDNSService::AsyncResolve(const nsACString& hostname,
189 nsIDNSService::ResolveType aType,
190 nsIDNSService::DNSFlags flags,
191 nsIDNSAdditionalInfo* aInfo,
192 nsIDNSListener* listener, nsIEventTarget* target_,
193 JS::Handle<JS::Value> aOriginAttributes,
194 JSContext* aCx, uint8_t aArgc,
195 nsICancelable** result) {
196 OriginAttributes attrs;
198 if (aArgc == 1) {
199 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
200 return NS_ERROR_INVALID_ARG;
204 return AsyncResolveInternal(hostname, aType, flags, aInfo, listener, target_,
205 attrs, result);
208 NS_IMETHODIMP
209 ChildDNSService::AsyncResolveNative(
210 const nsACString& hostname, nsIDNSService::ResolveType aType,
211 nsIDNSService::DNSFlags flags, nsIDNSAdditionalInfo* aInfo,
212 nsIDNSListener* listener, nsIEventTarget* target_,
213 const OriginAttributes& aOriginAttributes, nsICancelable** result) {
214 return AsyncResolveInternal(hostname, aType, flags, aInfo, listener, target_,
215 aOriginAttributes, result);
218 NS_IMETHODIMP
219 ChildDNSService::NewAdditionalInfo(const nsACString& aTrrURL, int32_t aPort,
220 nsIDNSAdditionalInfo** aInfo) {
221 RefPtr<DNSAdditionalInfo> res = new DNSAdditionalInfo(aTrrURL, aPort);
222 res.forget(aInfo);
223 return NS_OK;
226 NS_IMETHODIMP
227 ChildDNSService::CancelAsyncResolve(const nsACString& aHostname,
228 nsIDNSService::ResolveType aType,
229 nsIDNSService::DNSFlags aFlags,
230 nsIDNSAdditionalInfo* aInfo,
231 nsIDNSListener* aListener, nsresult aReason,
232 JS::Handle<JS::Value> aOriginAttributes,
233 JSContext* aCx, uint8_t aArgc) {
234 OriginAttributes attrs;
236 if (aArgc == 1) {
237 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
238 return NS_ERROR_INVALID_ARG;
242 return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener,
243 aReason, attrs);
246 NS_IMETHODIMP
247 ChildDNSService::CancelAsyncResolveNative(
248 const nsACString& aHostname, nsIDNSService::ResolveType aType,
249 nsIDNSService::DNSFlags aFlags, nsIDNSAdditionalInfo* aInfo,
250 nsIDNSListener* aListener, nsresult aReason,
251 const OriginAttributes& aOriginAttributes) {
252 return CancelAsyncResolveInternal(aHostname, aType, aFlags, aInfo, aListener,
253 aReason, aOriginAttributes);
256 NS_IMETHODIMP
257 ChildDNSService::Resolve(const nsACString& hostname,
258 nsIDNSService::DNSFlags flags,
259 JS::Handle<JS::Value> aOriginAttributes,
260 JSContext* aCx, uint8_t aArgc, nsIDNSRecord** result) {
261 // not planning to ever support this, since sync IPDL is evil.
262 return NS_ERROR_NOT_AVAILABLE;
265 NS_IMETHODIMP
266 ChildDNSService::ResolveNative(const nsACString& hostname,
267 nsIDNSService::DNSFlags flags,
268 const OriginAttributes& aOriginAttributes,
269 nsIDNSRecord** result) {
270 // not planning to ever support this, since sync IPDL is evil.
271 return NS_ERROR_NOT_AVAILABLE;
274 NS_IMETHODIMP
275 ChildDNSService::GetDNSCacheEntries(
276 nsTArray<mozilla::net::DNSCacheEntries>* args) {
277 // Only used by networking dashboard, so may not ever need this in child.
278 // (and would provide a way to spy on what hosts other apps are connecting to,
279 // unless we start keeping per-app DNS caches).
280 return NS_ERROR_NOT_AVAILABLE;
283 NS_IMETHODIMP
284 ChildDNSService::ClearCache(bool aTrrToo) {
285 if (!mTRRServiceParent || !mTRRServiceParent->CanSend()) {
286 return NS_ERROR_NOT_AVAILABLE;
289 Unused << mTRRServiceParent->SendClearDNSCache(aTrrToo);
290 return NS_OK;
293 NS_IMETHODIMP
294 ChildDNSService::ReloadParentalControlEnabled() {
295 if (!mTRRServiceParent) {
296 return NS_ERROR_NOT_AVAILABLE;
299 mTRRServiceParent->UpdateParentalControlEnabled();
300 return NS_OK;
303 NS_IMETHODIMP
304 ChildDNSService::SetDetectedTrrURI(const nsACString& aURI) {
305 if (!mTRRServiceParent) {
306 return NS_ERROR_NOT_AVAILABLE;
309 mTRRServiceParent->SetDetectedTrrURI(aURI);
310 return NS_OK;
313 NS_IMETHODIMP
314 ChildDNSService::SetHeuristicDetectionResult(nsITRRSkipReason::value aValue) {
315 return NS_ERROR_NOT_IMPLEMENTED;
318 NS_IMETHODIMP
319 ChildDNSService::GetHeuristicDetectionResult(nsITRRSkipReason::value* aValue) {
320 return NS_ERROR_NOT_IMPLEMENTED;
323 NS_IMETHODIMP
324 ChildDNSService::GetTRRSkipReasonName(nsITRRSkipReason::value aValue,
325 nsACString& aName) {
326 return mozilla::net::GetTRRSkipReasonName(aValue, aName);
329 NS_IMETHODIMP
330 ChildDNSService::GetCurrentTrrURI(nsACString& aURI) {
331 if (!mTRRServiceParent) {
332 return NS_ERROR_NOT_AVAILABLE;
335 mTRRServiceParent->GetURI(aURI);
336 return NS_OK;
339 NS_IMETHODIMP
340 ChildDNSService::GetCurrentTrrMode(nsIDNSService::ResolverMode* aMode) {
341 if (XRE_IsContentProcess()) {
342 *aMode = mTRRMode;
343 return NS_OK;
345 if (!mTRRServiceParent) {
346 return NS_ERROR_NOT_AVAILABLE;
349 *aMode = mTRRServiceParent->Mode();
350 return NS_OK;
353 void ChildDNSService::SetTRRModeInChild(
354 nsIDNSService::ResolverMode mode,
355 nsIDNSService::ResolverMode modeFromPref) {
356 if (!XRE_IsContentProcess()) {
357 MOZ_ASSERT(false, "Why are we calling this?");
358 return;
360 mTRRMode = mode;
361 TRRService::SetCurrentTRRMode(modeFromPref);
364 NS_IMETHODIMP
365 ChildDNSService::GetCurrentTrrConfirmationState(uint32_t* aConfirmationState) {
366 if (!mTRRServiceParent) {
367 return NS_ERROR_NOT_AVAILABLE;
370 *aConfirmationState = mTRRServiceParent->GetConfirmationState();
371 return NS_OK;
374 NS_IMETHODIMP
375 ChildDNSService::GetMyHostName(nsACString& result) {
376 if (XRE_IsParentProcess()) {
377 char name[100];
378 if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) {
379 result = name;
380 return NS_OK;
383 return NS_ERROR_FAILURE;
385 // TODO: get value from parent during PNecko construction?
386 return NS_ERROR_NOT_AVAILABLE;
389 void ChildDNSService::NotifyRequestDone(DNSRequestSender* aDnsRequest) {
390 // We need the original flags and listener for the pending requests hash.
391 nsIDNSService::DNSFlags originalFlags =
392 aDnsRequest->mFlags & ~RESOLVE_OFFLINE;
393 uintptr_t originalListenerAddr =
394 reinterpret_cast<uintptr_t>(aDnsRequest->mListener.get());
395 RefPtr<DNSListenerProxy> wrapper = do_QueryObject(aDnsRequest->mListener);
396 if (wrapper) {
397 originalListenerAddr = wrapper->GetOriginalListenerAddress();
400 MutexAutoLock lock(mPendingRequestsLock);
402 nsCString key;
403 GetDNSRecordHashKey(aDnsRequest->mHost, aDnsRequest->mTrrServer,
404 aDnsRequest->mPort, aDnsRequest->mType,
405 aDnsRequest->mOriginAttributes, originalFlags,
406 originalListenerAddr, key);
408 nsTArray<RefPtr<DNSRequestSender>>* hashEntry;
410 if (mPendingRequests.Get(key, &hashEntry)) {
411 auto idx = hashEntry->IndexOf(aDnsRequest);
412 if (idx != nsTArray<RefPtr<DNSRequestSender>>::NoIndex) {
413 hashEntry->RemoveElementAt(idx);
414 if (hashEntry->IsEmpty()) {
415 mPendingRequests.Remove(key);
421 //-----------------------------------------------------------------------------
422 // ChildDNSService::nsPIDNSService
423 //-----------------------------------------------------------------------------
425 nsresult ChildDNSService::Init() {
426 ReadPrefs(nullptr);
428 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
429 if (prefs) {
430 AddPrefObserver(prefs);
433 return NS_OK;
436 nsresult ChildDNSService::Shutdown() { return NS_OK; }
438 NS_IMETHODIMP
439 ChildDNSService::GetPrefetchEnabled(bool* outVal) {
440 *outVal = !mDisablePrefetch;
441 return NS_OK;
444 NS_IMETHODIMP
445 ChildDNSService::SetPrefetchEnabled(bool inVal) {
446 mDisablePrefetch = !inVal;
447 return NS_OK;
450 NS_IMETHODIMP
451 ChildDNSService::ReportFailedSVCDomainName(const nsACString& aOwnerName,
452 const nsACString& aSVCDomainName) {
453 return NS_ERROR_NOT_IMPLEMENTED;
456 NS_IMETHODIMP
457 ChildDNSService::IsSVCDomainNameFailed(const nsACString& aOwnerName,
458 const nsACString& aSVCDomainName,
459 bool* aResult) {
460 return NS_ERROR_NOT_IMPLEMENTED;
463 NS_IMETHODIMP
464 ChildDNSService::ResetExcludedSVCDomainName(const nsACString& aOwnerName) {
465 return NS_ERROR_NOT_IMPLEMENTED;
468 //-----------------------------------------------------------------------------
469 // ChildDNSService::nsIObserver
470 //-----------------------------------------------------------------------------
472 NS_IMETHODIMP
473 ChildDNSService::Observe(nsISupports* subject, const char* topic,
474 const char16_t* data) {
475 if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
476 // Reread prefs
477 ReadPrefs(NS_ConvertUTF16toUTF8(data).get());
479 return NS_OK;
482 void ChildDNSService::SetTRRDomain(const nsACString& aTRRDomain) {
483 mTRRDomain = aTRRDomain;
484 TRRService::SetProviderDomain(aTRRDomain);
487 nsresult ChildDNSService::GetTRRDomainKey(nsACString& aTRRDomain) {
488 aTRRDomain = TRRService::ProviderKey();
489 return NS_OK;
492 NS_IMETHODIMP
493 ChildDNSService::GetTrrDomain(nsACString& aTRRDomain) {
494 aTRRDomain = mTRRDomain;
495 return NS_OK;
498 NS_IMETHODIMP
499 ChildDNSService::GetLastConfirmationStatus(nsresult* aConfirmationStatus) {
500 // XXX(valentin): Fix for socket process
501 *aConfirmationStatus = NS_OK;
502 return NS_OK;
505 NS_IMETHODIMP ChildDNSService::GetLastConfirmationSkipReason(
506 TRRSkippedReason* aSkipReason) {
507 // XXX(valentin): Fix for socket process
508 *aSkipReason = nsITRRSkipReason::TRR_UNSET;
509 return NS_OK;
512 } // namespace net
513 } // namespace mozilla