Bug 1838739 - Initialize result of SetAsGPUOutOfMemoryError. r=webgpu-reviewers,nical
[gecko.git] / netwerk / dns / DNSRequestChild.cpp
blobd8ee335b6fff7e951cb8f4eecf9996678d0b1d20
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(TaskCategory::Other, 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 TaskCategory::Other,
427 NewRunnableMethod("net::DNSRequestSender::StartRequest", this,
428 &DNSRequestSender::StartRequest));
429 return;
432 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) {
433 if (XRE_IsContentProcess()) {
434 mozilla::dom::ContentChild* cc =
435 static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
436 if (cc->IsShuttingDown()) {
437 return;
440 // Send request to Parent process.
441 gNeckoChild->SendPDNSRequestConstructor(child, mHost, mTrrServer, mPort,
442 mType, mOriginAttributes, mFlags);
443 } else if (XRE_IsSocketProcess()) {
444 // DNS resolution is done in the parent process. Send a DNS request to
445 // parent process.
446 MOZ_ASSERT(!nsIOService::UseSocketProcess());
448 SocketProcessChild* socketProcessChild =
449 SocketProcessChild::GetSingleton();
450 if (!socketProcessChild->CanSend()) {
451 return;
454 socketProcessChild->SendPDNSRequestConstructor(
455 child, mHost, mTrrServer, mPort, mType, mOriginAttributes, mFlags);
456 } else {
457 MOZ_ASSERT(false, "Wrong process");
458 return;
460 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
461 // DNS resolution is done in the socket process. Send a DNS request to
462 // socket process.
463 MOZ_ASSERT(nsIOService::UseSocketProcess());
465 RefPtr<DNSRequestParent> requestParent = parent;
466 RefPtr<DNSRequestSender> self = this;
467 auto task = [requestParent, self]() {
468 Unused << SocketProcessParent::GetSingleton()->SendPDNSRequestConstructor(
469 requestParent, self->mHost, self->mTrrServer, self->mPort,
470 self->mType, self->mOriginAttributes, self->mFlags);
472 if (!gIOService->SocketProcessReady()) {
473 gIOService->CallOrWaitForSocketProcess(std::move(task));
474 return;
477 task();
481 void DNSRequestSender::CallOnLookupComplete() {
482 MOZ_ASSERT(mListener);
483 mListener->OnLookupComplete(this, mResultRecord, mResultStatus);
486 bool DNSRequestSender::OnRecvLookupCompleted(const DNSRequestResponse& reply) {
487 MOZ_ASSERT(mListener);
489 switch (reply.type()) {
490 case DNSRequestResponse::TDNSRecord: {
491 mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags);
492 break;
494 case DNSRequestResponse::Tnsresult: {
495 mResultStatus = reply.get_nsresult();
496 break;
498 case DNSRequestResponse::TIPCTypeRecord: {
499 MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
500 mResultRecord =
501 new ChildDNSByTypeRecord(reply.get_IPCTypeRecord().mData, mHost,
502 reply.get_IPCTypeRecord().mTTL);
503 break;
505 default:
506 MOZ_ASSERT_UNREACHABLE("unknown type");
507 return false;
510 MOZ_ASSERT(NS_IsMainThread());
512 bool targetIsMain = false;
513 if (!mTarget) {
514 targetIsMain = true;
515 } else {
516 mTarget->IsOnCurrentThread(&targetIsMain);
519 if (targetIsMain) {
520 CallOnLookupComplete();
521 } else {
522 nsCOMPtr<nsIRunnable> event =
523 NewRunnableMethod("net::DNSRequestSender::CallOnLookupComplete", this,
524 &DNSRequestSender::CallOnLookupComplete);
525 mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
528 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) {
529 Unused << mozilla::net::DNSRequestChild::Send__delete__(child);
530 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) {
531 Unused << mozilla::net::DNSRequestParent::Send__delete__(parent);
534 return true;
537 void DNSRequestSender::OnIPCActorDestroy() {
538 // Request is done or destroyed. Remove it from the hash table.
539 RefPtr<ChildDNSService> dnsServiceChild =
540 dont_AddRef(ChildDNSService::GetSingleton());
541 dnsServiceChild->NotifyRequestDone(this);
543 mIPCActor = nullptr;
546 //-----------------------------------------------------------------------------
547 // DNSRequestChild
548 //-----------------------------------------------------------------------------
550 DNSRequestChild::DNSRequestChild(DNSRequestBase* aRequest)
551 : DNSRequestActor(aRequest) {
552 aRequest->SetIPCActor(this);
555 mozilla::ipc::IPCResult DNSRequestChild::RecvCancelDNSRequest(
556 const nsCString& hostName, const nsCString& trrServer, const int32_t& port,
557 const uint16_t& type, const OriginAttributes& originAttributes,
558 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {
559 mDNSRequest->OnRecvCancelDNSRequest(hostName, trrServer, port, type,
560 originAttributes, flags, reason);
561 return IPC_OK();
564 mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted(
565 const DNSRequestResponse& reply) {
566 return mDNSRequest->OnRecvLookupCompleted(reply) ? IPC_OK()
567 : IPC_FAIL_NO_REASON(this);
570 void DNSRequestChild::ActorDestroy(ActorDestroyReason) {
571 mDNSRequest->OnIPCActorDestroy();
572 mDNSRequest = nullptr;
575 //------------------------------------------------------------------------------
576 } // namespace net
577 } // namespace mozilla