Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / netwerk / dns / DNSRequestChild.cpp
blob578895186a1f2f568ae0352265204b4b59928c40
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/ContentChild.h"
8 #include "mozilla/net/ChildDNSService.h"
9 #include "mozilla/net/DNSByTypeRecord.h"
10 #include "mozilla/net/DNSRequestChild.h"
11 #include "mozilla/net/DNSRequestParent.h"
12 #include "mozilla/net/NeckoChild.h"
13 #include "mozilla/net/SocketProcessChild.h"
14 #include "mozilla/SchedulerGroup.h"
15 #include "mozilla/net/SocketProcessParent.h"
16 #include "mozilla/Unused.h"
17 #include "nsIDNSRecord.h"
18 #include "nsIDNSByTypeRecord.h"
19 #include "nsHostResolver.h"
20 #include "nsIOService.h"
21 #include "nsTArray.h"
22 #include "nsNetAddr.h"
23 #include "nsThreadUtils.h"
25 using namespace mozilla::ipc;
27 namespace mozilla {
28 namespace net {
30 void DNSRequestBase::SetIPCActor(DNSRequestActor* aActor) {
31 mIPCActor = aActor;
34 //-----------------------------------------------------------------------------
35 // ChildDNSRecord:
36 // A simple class to provide nsIDNSRecord on the child
37 //-----------------------------------------------------------------------------
39 class ChildDNSRecord : public nsIDNSAddrRecord {
40 public:
41 NS_DECL_THREADSAFE_ISUPPORTS
42 NS_DECL_NSIDNSRECORD
43 NS_DECL_NSIDNSADDRRECORD
45 ChildDNSRecord(const DNSRecord& reply, nsIDNSService::DNSFlags flags);
47 private:
48 virtual ~ChildDNSRecord() = default;
50 nsCString mCanonicalName;
51 nsTArray<NetAddr> mAddresses;
52 uint32_t mCurrent = 0; // addr iterator
53 nsIDNSService::DNSFlags mFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS;
54 double mTrrFetchDuration = 0;
55 double mTrrFetchDurationNetworkOnly = 0;
56 bool mIsTRR = false;
57 bool mResolvedInSocketProcess = false;
58 nsIRequest::TRRMode mEffectiveTRRMode = nsIRequest::TRR_DEFAULT_MODE;
59 nsITRRSkipReason::value mTRRSkipReason = nsITRRSkipReason::TRR_UNSET;
60 uint32_t mTTL = 0;
63 NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord, nsIDNSAddrRecord)
65 ChildDNSRecord::ChildDNSRecord(const DNSRecord& reply,
66 nsIDNSService::DNSFlags flags)
67 : mFlags(flags) {
68 mCanonicalName = reply.canonicalName();
69 mTrrFetchDuration = reply.trrFetchDuration();
70 mTrrFetchDurationNetworkOnly = reply.trrFetchDurationNetworkOnly();
71 mIsTRR = reply.isTRR();
72 // When ChildDNSRecord is created in parent process, we know this is case that
73 // DNS resolution is done in socket process.
74 mResolvedInSocketProcess = XRE_IsParentProcess();
75 mEffectiveTRRMode = reply.effectiveTRRMode();
77 // A shame IPDL gives us no way to grab ownership of array: so copy it.
78 const nsTArray<NetAddr>& addrs = reply.addrs();
79 mAddresses = addrs.Clone();
80 mTTL = reply.ttl();
83 //-----------------------------------------------------------------------------
84 // ChildDNSRecord::nsIDNSAddrRecord
85 //-----------------------------------------------------------------------------
87 NS_IMETHODIMP
88 ChildDNSRecord::GetCanonicalName(nsACString& result) {
89 if (!(mFlags & nsHostResolver::RES_CANON_NAME)) {
90 return NS_ERROR_NOT_AVAILABLE;
93 result = mCanonicalName;
94 return NS_OK;
97 NS_IMETHODIMP
98 ChildDNSRecord::IsTRR(bool* retval) {
99 *retval = mIsTRR;
100 return NS_OK;
103 NS_IMETHODIMP
104 ChildDNSRecord::ResolvedInSocketProcess(bool* retval) {
105 *retval = mResolvedInSocketProcess;
106 return NS_OK;
109 NS_IMETHODIMP
110 ChildDNSRecord::GetTrrFetchDuration(double* aTime) {
111 *aTime = mTrrFetchDuration;
112 return NS_OK;
115 NS_IMETHODIMP
116 ChildDNSRecord::GetTrrFetchDurationNetworkOnly(double* aTime) {
117 *aTime = mTrrFetchDurationNetworkOnly;
118 return NS_OK;
121 NS_IMETHODIMP
122 ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr* addr) {
123 if (mCurrent >= mAddresses.Length()) {
124 return NS_ERROR_NOT_AVAILABLE;
127 memcpy(addr, &mAddresses[mCurrent++], sizeof(NetAddr));
129 // both Ipv4/6 use same bits for port, so safe to just use ipv4's field
130 addr->inet.port = htons(port);
132 return NS_OK;
135 NS_IMETHODIMP
136 ChildDNSRecord::GetAddresses(nsTArray<NetAddr>& aAddressArray) {
137 aAddressArray = mAddresses.Clone();
138 return NS_OK;
141 // shamelessly copied from nsDNSRecord
142 NS_IMETHODIMP
143 ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr** result) {
144 NetAddr addr;
145 nsresult rv = GetNextAddr(port, &addr);
146 if (NS_FAILED(rv)) {
147 return rv;
150 RefPtr<nsNetAddr> netaddr = new nsNetAddr(&addr);
151 netaddr.forget(result);
153 return NS_OK;
156 // also copied from nsDNSRecord
157 NS_IMETHODIMP
158 ChildDNSRecord::GetNextAddrAsString(nsACString& result) {
159 NetAddr addr;
160 nsresult rv = GetNextAddr(0, &addr);
161 if (NS_FAILED(rv)) {
162 return rv;
165 char buf[kIPv6CStrBufSize];
166 if (addr.ToStringBuffer(buf, sizeof(buf))) {
167 result.Assign(buf);
168 return NS_OK;
170 NS_ERROR("NetAddrToString failed unexpectedly");
171 return NS_ERROR_FAILURE; // conversion failed for some reason
174 NS_IMETHODIMP
175 ChildDNSRecord::HasMore(bool* result) {
176 *result = mCurrent < mAddresses.Length();
177 return NS_OK;
180 NS_IMETHODIMP
181 ChildDNSRecord::Rewind() {
182 mCurrent = 0;
183 return NS_OK;
186 NS_IMETHODIMP
187 ChildDNSRecord::ReportUnusable(uint16_t aPort) {
188 // "We thank you for your feedback" == >/dev/null
189 // TODO: we could send info back to parent.
190 return NS_OK;
193 NS_IMETHODIMP
194 ChildDNSRecord::GetEffectiveTRRMode(nsIRequest::TRRMode* aMode) {
195 *aMode = mEffectiveTRRMode;
196 return NS_OK;
199 NS_IMETHODIMP ChildDNSRecord::GetTrrSkipReason(
200 nsITRRSkipReason::value* aTrrSkipReason) {
201 *aTrrSkipReason = mTRRSkipReason;
202 return NS_OK;
205 NS_IMETHODIMP
206 ChildDNSRecord::GetTtl(uint32_t* aTtl) {
207 *aTtl = mTTL;
208 return NS_OK;
211 class ChildDNSByTypeRecord : public nsIDNSByTypeRecord,
212 public nsIDNSTXTRecord,
213 public nsIDNSHTTPSSVCRecord,
214 public DNSHTTPSSVCRecordBase {
215 public:
216 NS_DECL_THREADSAFE_ISUPPORTS
217 NS_DECL_NSIDNSRECORD
218 NS_DECL_NSIDNSBYTYPERECORD
219 NS_DECL_NSIDNSTXTRECORD
220 NS_DECL_NSIDNSHTTPSSVCRECORD
222 explicit ChildDNSByTypeRecord(const TypeRecordResultType& reply,
223 const nsACString& aHost, uint32_t aTTL);
225 private:
226 virtual ~ChildDNSByTypeRecord() = default;
228 TypeRecordResultType mResults = AsVariant(mozilla::Nothing());
229 bool mAllRecordsExcluded = false;
230 uint32_t mTTL = 0;
233 NS_IMPL_ISUPPORTS(ChildDNSByTypeRecord, nsIDNSByTypeRecord, nsIDNSRecord,
234 nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord)
236 ChildDNSByTypeRecord::ChildDNSByTypeRecord(const TypeRecordResultType& reply,
237 const nsACString& aHost,
238 uint32_t aTTL)
239 : DNSHTTPSSVCRecordBase(aHost) {
240 mResults = reply;
241 mTTL = aTTL;
244 NS_IMETHODIMP
245 ChildDNSByTypeRecord::GetType(uint32_t* aType) {
246 *aType = mResults.match(
247 [](TypeRecordEmpty&) {
248 MOZ_ASSERT(false, "This should never be the case");
249 return nsIDNSService::RESOLVE_TYPE_DEFAULT;
251 [](TypeRecordTxt&) { return nsIDNSService::RESOLVE_TYPE_TXT; },
252 [](TypeRecordHTTPSSVC&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC; });
253 return NS_OK;
256 NS_IMETHODIMP
257 ChildDNSByTypeRecord::GetRecords(CopyableTArray<nsCString>& aRecords) {
258 if (!mResults.is<TypeRecordTxt>()) {
259 return NS_ERROR_NOT_AVAILABLE;
261 aRecords = mResults.as<CopyableTArray<nsCString>>();
262 return NS_OK;
265 NS_IMETHODIMP
266 ChildDNSByTypeRecord::GetRecordsAsOneString(nsACString& aRecords) {
267 // deep copy
268 if (!mResults.is<TypeRecordTxt>()) {
269 return NS_ERROR_NOT_AVAILABLE;
271 auto& results = mResults.as<CopyableTArray<nsCString>>();
272 for (uint32_t i = 0; i < results.Length(); i++) {
273 aRecords.Append(results[i]);
275 return NS_OK;
278 NS_IMETHODIMP
279 ChildDNSByTypeRecord::GetRecords(nsTArray<RefPtr<nsISVCBRecord>>& aRecords) {
280 if (!mResults.is<TypeRecordHTTPSSVC>()) {
281 return NS_ERROR_NOT_AVAILABLE;
284 auto& results = mResults.as<TypeRecordHTTPSSVC>();
286 for (const SVCB& r : results) {
287 RefPtr<nsISVCBRecord> rec = new SVCBRecord(r);
288 aRecords.AppendElement(rec);
290 return NS_OK;
293 NS_IMETHODIMP
294 ChildDNSByTypeRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3,
295 nsISVCBRecord** aRecord) {
296 if (!mResults.is<TypeRecordHTTPSSVC>()) {
297 return NS_ERROR_NOT_AVAILABLE;
300 auto& results = mResults.as<TypeRecordHTTPSSVC>();
301 nsCOMPtr<nsISVCBRecord> result = GetServiceModeRecordInternal(
302 aNoHttp2, aNoHttp3, results, mAllRecordsExcluded);
303 if (!result) {
304 return NS_ERROR_NOT_AVAILABLE;
307 result.forget(aRecord);
308 return NS_OK;
311 NS_IMETHODIMP
312 ChildDNSByTypeRecord::GetAllRecordsWithEchConfig(
313 bool aNoHttp2, bool aNoHttp3, bool* aAllRecordsHaveEchConfig,
314 bool* aAllRecordsInH3ExcludedList,
315 nsTArray<RefPtr<nsISVCBRecord>>& aResult) {
316 if (!mResults.is<TypeRecordHTTPSSVC>()) {
317 return NS_ERROR_NOT_AVAILABLE;
320 auto& records = mResults.as<TypeRecordHTTPSSVC>();
321 GetAllRecordsWithEchConfigInternal(aNoHttp2, aNoHttp3, records,
322 aAllRecordsHaveEchConfig,
323 aAllRecordsInH3ExcludedList, aResult);
324 return NS_OK;
327 NS_IMETHODIMP
328 ChildDNSByTypeRecord::GetHasIPAddresses(bool* aResult) {
329 NS_ENSURE_ARG(aResult);
331 if (!mResults.is<TypeRecordHTTPSSVC>()) {
332 return NS_ERROR_NOT_AVAILABLE;
335 auto& results = mResults.as<TypeRecordHTTPSSVC>();
336 *aResult = HasIPAddressesInternal(results);
337 return NS_OK;
340 NS_IMETHODIMP
341 ChildDNSByTypeRecord::GetAllRecordsExcluded(bool* aResult) {
342 NS_ENSURE_ARG(aResult);
344 if (!mResults.is<TypeRecordHTTPSSVC>()) {
345 return NS_ERROR_NOT_AVAILABLE;
348 *aResult = mAllRecordsExcluded;
349 return NS_OK;
352 NS_IMETHODIMP
353 ChildDNSByTypeRecord::GetResults(mozilla::net::TypeRecordResultType* aResults) {
354 *aResults = mResults;
355 return NS_OK;
358 NS_IMETHODIMP
359 ChildDNSByTypeRecord::GetTtl(uint32_t* aResult) {
360 *aResult = mTTL;
361 return NS_OK;
364 //-----------------------------------------------------------------------------
365 // DNSRequestSender
366 //-----------------------------------------------------------------------------
368 NS_IMPL_ISUPPORTS(DNSRequestSender, nsICancelable)
370 DNSRequestSender::DNSRequestSender(const nsACString& aHost,
371 const nsACString& aTrrServer, int32_t aPort,
372 const uint16_t& aType,
373 const OriginAttributes& aOriginAttributes,
374 const nsIDNSService::DNSFlags& aFlags,
375 nsIDNSListener* aListener,
376 nsIEventTarget* target)
377 : mListener(aListener),
378 mTarget(target),
379 mResultStatus(NS_OK),
380 mHost(aHost),
381 mTrrServer(aTrrServer),
382 mPort(aPort),
383 mType(aType),
384 mOriginAttributes(aOriginAttributes),
385 mFlags(aFlags) {}
387 void DNSRequestSender::OnRecvCancelDNSRequest(
388 const nsCString& hostName, const nsCString& trrServer, const int32_t& port,
389 const uint16_t& type, const OriginAttributes& originAttributes,
390 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {}
392 NS_IMETHODIMP
393 DNSRequestSender::Cancel(nsresult reason) {
394 if (!mIPCActor) {
395 return NS_ERROR_NOT_AVAILABLE;
398 if (mIPCActor->CanSend()) {
399 // We can only do IPDL on the main thread
400 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
401 "net::CancelDNSRequestEvent",
402 [actor(mIPCActor), host(mHost), trrServer(mTrrServer), port(mPort),
403 type(mType), originAttributes(mOriginAttributes), flags(mFlags),
404 reason]() {
405 if (!actor->CanSend()) {
406 return;
409 if (DNSRequestChild* child = actor->AsDNSRequestChild()) {
410 Unused << child->SendCancelDNSRequest(
411 host, trrServer, port, type, originAttributes, flags, reason);
412 } else if (DNSRequestParent* parent = actor->AsDNSRequestParent()) {
413 Unused << parent->SendCancelDNSRequest(
414 host, trrServer, port, type, originAttributes, flags, reason);
417 SchedulerGroup::Dispatch(runnable.forget());
419 return NS_OK;
422 void DNSRequestSender::StartRequest() {
423 // we can only do IPDL on the main thread
424 if (!NS_IsMainThread()) {
425 SchedulerGroup::Dispatch(
426 NewRunnableMethod("net::DNSRequestSender::StartRequest", this,
427 &DNSRequestSender::StartRequest));
428 return;
431 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) {
432 if (XRE_IsContentProcess()) {
433 mozilla::dom::ContentChild* cc =
434 static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
435 if (cc->IsShuttingDown()) {
436 return;
439 // Send request to Parent process.
440 gNeckoChild->SendPDNSRequestConstructor(child, mHost, mTrrServer, mPort,
441 mType, mOriginAttributes, mFlags);
442 } else if (XRE_IsSocketProcess()) {
443 // DNS resolution is done in the parent process. Send a DNS request to
444 // parent process.
445 MOZ_ASSERT(!nsIOService::UseSocketProcess());
447 SocketProcessChild* socketProcessChild =
448 SocketProcessChild::GetSingleton();
449 if (!socketProcessChild->CanSend()) {
450 return;
453 socketProcessChild->SendPDNSRequestConstructor(
454 child, mHost, mTrrServer, mPort, mType, mOriginAttributes, mFlags);
455 } else {
456 MOZ_ASSERT(false, "Wrong process");
457 return;
459 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
460 // DNS resolution is done in the socket process. Send a DNS request to
461 // socket process.
462 MOZ_ASSERT(nsIOService::UseSocketProcess());
464 RefPtr<DNSRequestParent> requestParent = parent;
465 RefPtr<DNSRequestSender> self = this;
466 auto task = [requestParent, self]() {
467 Unused << SocketProcessParent::GetSingleton()->SendPDNSRequestConstructor(
468 requestParent, self->mHost, self->mTrrServer, self->mPort,
469 self->mType, self->mOriginAttributes, self->mFlags);
471 if (!gIOService->SocketProcessReady()) {
472 gIOService->CallOrWaitForSocketProcess(std::move(task));
473 return;
476 task();
480 void DNSRequestSender::CallOnLookupComplete() {
481 MOZ_ASSERT(mListener);
482 mListener->OnLookupComplete(this, mResultRecord, mResultStatus);
485 bool DNSRequestSender::OnRecvLookupCompleted(const DNSRequestResponse& reply) {
486 MOZ_ASSERT(mListener);
488 switch (reply.type()) {
489 case DNSRequestResponse::TDNSRecord: {
490 mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags);
491 break;
493 case DNSRequestResponse::Tnsresult: {
494 mResultStatus = reply.get_nsresult();
495 break;
497 case DNSRequestResponse::TIPCTypeRecord: {
498 MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
499 mResultRecord =
500 new ChildDNSByTypeRecord(reply.get_IPCTypeRecord().mData, mHost,
501 reply.get_IPCTypeRecord().mTTL);
502 break;
504 default:
505 MOZ_ASSERT_UNREACHABLE("unknown type");
506 return false;
509 MOZ_ASSERT(NS_IsMainThread());
511 bool targetIsMain = false;
512 if (!mTarget) {
513 targetIsMain = true;
514 } else {
515 mTarget->IsOnCurrentThread(&targetIsMain);
518 if (targetIsMain) {
519 CallOnLookupComplete();
520 } else {
521 nsCOMPtr<nsIRunnable> event =
522 NewRunnableMethod("net::DNSRequestSender::CallOnLookupComplete", this,
523 &DNSRequestSender::CallOnLookupComplete);
524 mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
527 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) {
528 Unused << mozilla::net::DNSRequestChild::Send__delete__(child);
529 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
530 Unused << mozilla::net::DNSRequestParent::Send__delete__(parent);
533 return true;
536 void DNSRequestSender::OnIPCActorDestroy() {
537 // Request is done or destroyed. Remove it from the hash table.
538 RefPtr<ChildDNSService> dnsServiceChild =
539 dont_AddRef(ChildDNSService::GetSingleton());
540 dnsServiceChild->NotifyRequestDone(this);
542 mIPCActor = nullptr;
545 //-----------------------------------------------------------------------------
546 // DNSRequestChild
547 //-----------------------------------------------------------------------------
549 DNSRequestChild::DNSRequestChild(DNSRequestBase* aRequest)
550 : DNSRequestActor(aRequest) {
551 aRequest->SetIPCActor(this);
554 mozilla::ipc::IPCResult DNSRequestChild::RecvCancelDNSRequest(
555 const nsCString& hostName, const nsCString& trrServer, const int32_t& port,
556 const uint16_t& type, const OriginAttributes& originAttributes,
557 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {
558 mDNSRequest->OnRecvCancelDNSRequest(hostName, trrServer, port, type,
559 originAttributes, flags, reason);
560 return IPC_OK();
563 mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted(
564 const DNSRequestResponse& reply) {
565 return mDNSRequest->OnRecvLookupCompleted(reply) ? IPC_OK()
566 : IPC_FAIL_NO_REASON(this);
569 void DNSRequestChild::ActorDestroy(ActorDestroyReason) {
570 mDNSRequest->OnIPCActorDestroy();
571 mDNSRequest = nullptr;
574 //------------------------------------------------------------------------------
575 } // namespace net
576 } // namespace mozilla