DNSRequestChild.cpp (18800B)
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/. */ 6 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 "nsIDNSRecord.h" 17 #include "nsIDNSByTypeRecord.h" 18 #include "nsHostResolver.h" 19 #include "nsIOService.h" 20 #include "nsTArray.h" 21 #include "nsNetAddr.h" 22 #include "nsThreadUtils.h" 23 24 using namespace mozilla::ipc; 25 26 namespace mozilla { 27 namespace net { 28 29 void DNSRequestBase::SetIPCActor(DNSRequestActor* aActor) { 30 mIPCActor = aActor; 31 } 32 33 //----------------------------------------------------------------------------- 34 // ChildDNSRecord: 35 // A simple class to provide nsIDNSRecord on the child 36 //----------------------------------------------------------------------------- 37 38 class ChildDNSRecord : public nsIDNSAddrRecord { 39 public: 40 NS_DECL_THREADSAFE_ISUPPORTS 41 NS_DECL_NSIDNSRECORD 42 NS_DECL_NSIDNSADDRRECORD 43 44 ChildDNSRecord(const DNSRecord& reply, nsIDNSService::DNSFlags flags); 45 46 private: 47 virtual ~ChildDNSRecord() = default; 48 49 nsCString mCanonicalName; 50 nsTArray<NetAddr> mAddresses; 51 uint32_t mCurrent = 0; // addr iterator 52 nsIDNSService::DNSFlags mFlags = nsIDNSService::RESOLVE_DEFAULT_FLAGS; 53 double mTrrFetchDuration = 0; 54 double mTrrFetchDurationNetworkOnly = 0; 55 bool mIsTRR = false; 56 bool mResolvedInSocketProcess = false; 57 nsIRequest::TRRMode mEffectiveTRRMode = nsIRequest::TRR_DEFAULT_MODE; 58 nsITRRSkipReason::value mTRRSkipReason = nsITRRSkipReason::TRR_UNSET; 59 uint32_t mTTL = 0; 60 TimeStamp mLastUpdate = mozilla::TimeStamp::NowLoRes(); 61 }; 62 63 NS_IMPL_ISUPPORTS(ChildDNSRecord, nsIDNSRecord, nsIDNSAddrRecord) 64 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(); 76 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(); 81 mLastUpdate = reply.lastUpdate(); 82 } 83 84 //----------------------------------------------------------------------------- 85 // ChildDNSRecord::nsIDNSAddrRecord 86 //----------------------------------------------------------------------------- 87 88 NS_IMETHODIMP 89 ChildDNSRecord::GetCanonicalName(nsACString& result) { 90 if (!(mFlags & nsIDNSService::RESOLVE_CANONICAL_NAME)) { 91 return NS_ERROR_NOT_AVAILABLE; 92 } 93 94 result = mCanonicalName; 95 return NS_OK; 96 } 97 98 NS_IMETHODIMP 99 ChildDNSRecord::IsTRR(bool* retval) { 100 *retval = mIsTRR; 101 return NS_OK; 102 } 103 104 NS_IMETHODIMP 105 ChildDNSRecord::ResolvedInSocketProcess(bool* retval) { 106 *retval = mResolvedInSocketProcess; 107 return NS_OK; 108 } 109 110 NS_IMETHODIMP 111 ChildDNSRecord::GetTrrFetchDuration(double* aTime) { 112 *aTime = mTrrFetchDuration; 113 return NS_OK; 114 } 115 116 NS_IMETHODIMP 117 ChildDNSRecord::GetTrrFetchDurationNetworkOnly(double* aTime) { 118 *aTime = mTrrFetchDurationNetworkOnly; 119 return NS_OK; 120 } 121 122 NS_IMETHODIMP 123 ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr* addr) { 124 if (mCurrent >= mAddresses.Length()) { 125 return NS_ERROR_NOT_AVAILABLE; 126 } 127 128 *addr = mAddresses[mCurrent++]; 129 130 // both Ipv4/6 use same bits for port, so safe to just use ipv4's field 131 addr->inet.port = htons(port); 132 133 return NS_OK; 134 } 135 136 NS_IMETHODIMP 137 ChildDNSRecord::GetAddresses(nsTArray<NetAddr>& aAddressArray) { 138 aAddressArray = mAddresses.Clone(); 139 return NS_OK; 140 } 141 142 // shamelessly copied from nsDNSRecord 143 NS_IMETHODIMP 144 ChildDNSRecord::GetScriptableNextAddr(uint16_t port, nsINetAddr** result) { 145 NetAddr addr; 146 nsresult rv = GetNextAddr(port, &addr); 147 if (NS_FAILED(rv)) { 148 return rv; 149 } 150 151 RefPtr<nsNetAddr> netaddr = new nsNetAddr(&addr); 152 netaddr.forget(result); 153 154 return NS_OK; 155 } 156 157 // also copied from nsDNSRecord 158 NS_IMETHODIMP 159 ChildDNSRecord::GetNextAddrAsString(nsACString& result) { 160 NetAddr addr; 161 nsresult rv = GetNextAddr(0, &addr); 162 if (NS_FAILED(rv)) { 163 return rv; 164 } 165 166 char buf[kIPv6CStrBufSize]; 167 if (addr.ToStringBuffer(buf, sizeof(buf))) { 168 result.Assign(buf); 169 return NS_OK; 170 } 171 NS_ERROR("NetAddrToString failed unexpectedly"); 172 return NS_ERROR_FAILURE; // conversion failed for some reason 173 } 174 175 NS_IMETHODIMP 176 ChildDNSRecord::HasMore(bool* result) { 177 *result = mCurrent < mAddresses.Length(); 178 return NS_OK; 179 } 180 181 NS_IMETHODIMP 182 ChildDNSRecord::Rewind() { 183 mCurrent = 0; 184 return NS_OK; 185 } 186 187 NS_IMETHODIMP 188 ChildDNSRecord::ReportUnusable(uint16_t aPort) { 189 // "We thank you for your feedback" == >/dev/null 190 // TODO: we could send info back to parent. 191 return NS_OK; 192 } 193 194 NS_IMETHODIMP 195 ChildDNSRecord::GetEffectiveTRRMode(nsIRequest::TRRMode* aMode) { 196 *aMode = mEffectiveTRRMode; 197 return NS_OK; 198 } 199 200 NS_IMETHODIMP ChildDNSRecord::GetTrrSkipReason( 201 nsITRRSkipReason::value* aTrrSkipReason) { 202 *aTrrSkipReason = mTRRSkipReason; 203 return NS_OK; 204 } 205 206 NS_IMETHODIMP 207 ChildDNSRecord::GetTtl(uint32_t* aTtl) { 208 *aTtl = mTTL; 209 return NS_OK; 210 } 211 212 NS_IMETHODIMP 213 ChildDNSRecord::GetLastUpdate(TimeStamp* aLastUpdate) { 214 *aLastUpdate = mLastUpdate; 215 return NS_OK; 216 } 217 218 class ChildDNSByTypeRecord : public nsIDNSByTypeRecord, 219 public nsIDNSTXTRecord, 220 public nsIDNSHTTPSSVCRecord, 221 public DNSHTTPSSVCRecordBase { 222 public: 223 NS_DECL_THREADSAFE_ISUPPORTS 224 NS_DECL_NSIDNSRECORD 225 NS_DECL_NSIDNSBYTYPERECORD 226 NS_DECL_NSIDNSTXTRECORD 227 NS_DECL_NSIDNSHTTPSSVCRECORD 228 229 explicit ChildDNSByTypeRecord(const TypeRecordResultType& reply, 230 const nsACString& aHost, uint32_t aTTL, 231 bool aIsTRR); 232 233 private: 234 virtual ~ChildDNSByTypeRecord() = default; 235 236 TypeRecordResultType mResults = AsVariant(mozilla::Nothing()); 237 bool mAllRecordsExcluded = false; 238 uint32_t mTTL = 0; 239 bool mIsTRR = false; 240 }; 241 242 NS_IMPL_ISUPPORTS(ChildDNSByTypeRecord, nsIDNSByTypeRecord, nsIDNSRecord, 243 nsIDNSTXTRecord, nsIDNSHTTPSSVCRecord) 244 245 ChildDNSByTypeRecord::ChildDNSByTypeRecord(const TypeRecordResultType& reply, 246 const nsACString& aHost, 247 uint32_t aTTL, bool aIsTRR) 248 : DNSHTTPSSVCRecordBase(aHost) { 249 mResults = reply; 250 mTTL = aTTL; 251 mIsTRR = aIsTRR; 252 } 253 254 NS_IMETHODIMP 255 ChildDNSByTypeRecord::GetType(uint32_t* aType) { 256 *aType = mResults.match( 257 [](TypeRecordEmpty&) { 258 MOZ_ASSERT(false, "This should never be the case"); 259 return nsIDNSService::RESOLVE_TYPE_DEFAULT; 260 }, 261 [](TypeRecordTxt&) { return nsIDNSService::RESOLVE_TYPE_TXT; }, 262 [](TypeRecordHTTPSSVC&) { return nsIDNSService::RESOLVE_TYPE_HTTPSSVC; }); 263 return NS_OK; 264 } 265 266 NS_IMETHODIMP 267 ChildDNSByTypeRecord::GetRecords(CopyableTArray<nsCString>& aRecords) { 268 if (!mResults.is<TypeRecordTxt>()) { 269 return NS_ERROR_NOT_AVAILABLE; 270 } 271 aRecords = mResults.as<CopyableTArray<nsCString>>(); 272 return NS_OK; 273 } 274 275 NS_IMETHODIMP 276 ChildDNSByTypeRecord::GetRecordsAsOneString(nsACString& aRecords) { 277 // deep copy 278 if (!mResults.is<TypeRecordTxt>()) { 279 return NS_ERROR_NOT_AVAILABLE; 280 } 281 auto& results = mResults.as<CopyableTArray<nsCString>>(); 282 for (uint32_t i = 0; i < results.Length(); i++) { 283 aRecords.Append(results[i]); 284 } 285 return NS_OK; 286 } 287 288 NS_IMETHODIMP 289 ChildDNSByTypeRecord::GetRecords(nsTArray<RefPtr<nsISVCBRecord>>& aRecords) { 290 if (!mResults.is<TypeRecordHTTPSSVC>()) { 291 return NS_ERROR_NOT_AVAILABLE; 292 } 293 294 auto& results = mResults.as<TypeRecordHTTPSSVC>(); 295 296 for (const SVCB& r : results) { 297 RefPtr<nsISVCBRecord> rec = new SVCBRecord(r); 298 aRecords.AppendElement(rec); 299 } 300 return NS_OK; 301 } 302 303 NS_IMETHODIMP 304 ChildDNSByTypeRecord::GetServiceModeRecord(bool aNoHttp2, bool aNoHttp3, 305 nsISVCBRecord** aRecord) { 306 return GetServiceModeRecordWithCname(aNoHttp2, aNoHttp3, ""_ns, aRecord); 307 } 308 309 NS_IMETHODIMP 310 ChildDNSByTypeRecord::IsTRR(bool* aResult) { 311 *aResult = mIsTRR; 312 return NS_OK; 313 } 314 315 NS_IMETHODIMP 316 ChildDNSByTypeRecord::GetServiceModeRecordWithCname(bool aNoHttp2, 317 bool aNoHttp3, 318 const nsACString& aCname, 319 nsISVCBRecord** aRecord) { 320 if (!mResults.is<TypeRecordHTTPSSVC>()) { 321 return NS_ERROR_NOT_AVAILABLE; 322 } 323 324 auto& results = mResults.as<TypeRecordHTTPSSVC>(); 325 nsCOMPtr<nsISVCBRecord> result = GetServiceModeRecordInternal( 326 aNoHttp2, aNoHttp3, results, mAllRecordsExcluded, true, aCname); 327 if (!result) { 328 return NS_ERROR_NOT_AVAILABLE; 329 } 330 331 result.forget(aRecord); 332 return NS_OK; 333 } 334 335 NS_IMETHODIMP 336 ChildDNSByTypeRecord::GetAllRecords(bool aNoHttp2, bool aNoHttp3, 337 const nsACString& aCname, 338 nsTArray<RefPtr<nsISVCBRecord>>& aResult) { 339 if (!mResults.is<TypeRecordHTTPSSVC>()) { 340 return NS_ERROR_NOT_AVAILABLE; 341 } 342 343 auto& records = mResults.as<TypeRecordHTTPSSVC>(); 344 bool notused; 345 GetAllRecordsInternal(aNoHttp2, aNoHttp3, aCname, records, false, ¬used, 346 ¬used, aResult); 347 return NS_OK; 348 } 349 350 NS_IMETHODIMP 351 ChildDNSByTypeRecord::GetAllRecordsWithEchConfig( 352 bool aNoHttp2, bool aNoHttp3, const nsACString& aCname, 353 bool* aAllRecordsHaveEchConfig, bool* aAllRecordsInH3ExcludedList, 354 nsTArray<RefPtr<nsISVCBRecord>>& aResult) { 355 if (!mResults.is<TypeRecordHTTPSSVC>()) { 356 return NS_ERROR_NOT_AVAILABLE; 357 } 358 359 auto& records = mResults.as<TypeRecordHTTPSSVC>(); 360 GetAllRecordsInternal(aNoHttp2, aNoHttp3, aCname, records, true, 361 aAllRecordsHaveEchConfig, aAllRecordsInH3ExcludedList, 362 aResult); 363 return NS_OK; 364 } 365 366 NS_IMETHODIMP 367 ChildDNSByTypeRecord::GetHasIPAddresses(bool* aResult) { 368 NS_ENSURE_ARG(aResult); 369 370 if (!mResults.is<TypeRecordHTTPSSVC>()) { 371 return NS_ERROR_NOT_AVAILABLE; 372 } 373 374 auto& results = mResults.as<TypeRecordHTTPSSVC>(); 375 *aResult = HasIPAddressesInternal(results); 376 return NS_OK; 377 } 378 379 NS_IMETHODIMP 380 ChildDNSByTypeRecord::GetAllRecordsExcluded(bool* aResult) { 381 NS_ENSURE_ARG(aResult); 382 383 if (!mResults.is<TypeRecordHTTPSSVC>()) { 384 return NS_ERROR_NOT_AVAILABLE; 385 } 386 387 *aResult = mAllRecordsExcluded; 388 return NS_OK; 389 } 390 391 NS_IMETHODIMP 392 ChildDNSByTypeRecord::GetResults(mozilla::net::TypeRecordResultType* aResults) { 393 *aResults = mResults; 394 return NS_OK; 395 } 396 397 NS_IMETHODIMP 398 ChildDNSByTypeRecord::GetTtl(uint32_t* aResult) { 399 *aResult = mTTL; 400 return NS_OK; 401 } 402 403 //----------------------------------------------------------------------------- 404 // DNSRequestSender 405 //----------------------------------------------------------------------------- 406 407 NS_IMPL_ISUPPORTS(DNSRequestSender, nsICancelable) 408 409 DNSRequestSender::DNSRequestSender(const nsACString& aHost, 410 const nsACString& aTrrServer, int32_t aPort, 411 const uint16_t& aType, 412 const OriginAttributes& aOriginAttributes, 413 const nsIDNSService::DNSFlags& aFlags, 414 nsIDNSListener* aListener, 415 nsIEventTarget* target) 416 : mListener(aListener), 417 mTarget(target), 418 mResultStatus(NS_OK), 419 mHost(aHost), 420 mTrrServer(aTrrServer), 421 mPort(aPort), 422 mType(aType), 423 mOriginAttributes(aOriginAttributes), 424 mFlags(aFlags) {} 425 426 void DNSRequestSender::OnRecvCancelDNSRequest( 427 const nsCString& hostName, const nsCString& trrServer, const int32_t& port, 428 const uint16_t& type, const OriginAttributes& originAttributes, 429 const nsIDNSService::DNSFlags& flags, const nsresult& reason) {} 430 431 NS_IMETHODIMP 432 DNSRequestSender::Cancel(nsresult reason) { 433 // we can only do IPC on the MainThread 434 if (!NS_IsMainThread()) { 435 SchedulerGroup::Dispatch( 436 NewRunnableMethod<nsresult>("net::DNSRequestSender::Cancel", this, 437 &DNSRequestSender::Cancel, reason)); 438 return NS_OK; 439 } 440 441 if (!mIPCActor || !mIPCActor->CanSend()) { 442 // Really a failure, but we won't be able to tell anyone about it anyways 443 return NS_OK; 444 } 445 446 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) { 447 (void)child->SendCancelDNSRequest(mHost, mTrrServer, mPort, mType, 448 mOriginAttributes, mFlags, reason); 449 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) { 450 (void)parent->SendCancelDNSRequest(mHost, mTrrServer, mPort, mType, 451 mOriginAttributes, mFlags, reason); 452 } 453 454 return NS_OK; 455 } 456 457 void DNSRequestSender::StartRequest() { 458 // we can only do IPC on the MainThread 459 if (!NS_IsMainThread()) { 460 SchedulerGroup::Dispatch( 461 NewRunnableMethod("net::DNSRequestSender::StartRequest", this, 462 &DNSRequestSender::StartRequest)); 463 return; 464 } 465 466 if (RefPtr<DNSRequestChild> child = mIPCActor->AsDNSRequestChild()) { 467 if (XRE_IsContentProcess()) { 468 mozilla::dom::ContentChild* cc = 469 static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager()); 470 if (cc->IsShuttingDown()) { 471 return; 472 } 473 474 // Send request to Parent process. 475 gNeckoChild->SendPDNSRequestConstructor(child, mHost, mTrrServer, mPort, 476 mType, mOriginAttributes, mFlags); 477 } else if (XRE_IsSocketProcess()) { 478 // DNS resolution is done in the parent process. Send a DNS request to 479 // parent process. 480 MOZ_ASSERT(!nsIOService::UseSocketProcess()); 481 482 SocketProcessChild* socketProcessChild = 483 SocketProcessChild::GetSingleton(); 484 if (!socketProcessChild->CanSend()) { 485 return; 486 } 487 488 MOZ_ALWAYS_TRUE(socketProcessChild->SendPDNSRequestConstructor( 489 child, mHost, mTrrServer, mPort, mType, mOriginAttributes, mFlags)); 490 } else { 491 MOZ_ASSERT(false, "Wrong process"); 492 return; 493 } 494 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) { 495 // DNS resolution is done in the socket process. Send a DNS request to 496 // socket process. 497 MOZ_ASSERT(nsIOService::UseSocketProcess()); 498 499 RefPtr<DNSRequestParent> requestParent = parent; 500 RefPtr<DNSRequestSender> self = this; 501 auto task = [requestParent, self]() { 502 RefPtr<SocketProcessParent> socketParent = 503 SocketProcessParent::GetSingleton(); 504 (void)socketParent->SendPDNSRequestConstructor( 505 requestParent, self->mHost, self->mTrrServer, self->mPort, 506 self->mType, self->mOriginAttributes, self->mFlags); 507 }; 508 if (!gIOService->SocketProcessReady()) { 509 gIOService->CallOrWaitForSocketProcess(std::move(task)); 510 return; 511 } 512 513 task(); 514 } 515 } 516 517 void DNSRequestSender::CallOnLookupComplete() { 518 MOZ_ASSERT(mListener); 519 mListener->OnLookupComplete(this, mResultRecord, mResultStatus); 520 } 521 522 bool DNSRequestSender::OnRecvLookupCompleted(const DNSRequestResponse& reply) { 523 MOZ_ASSERT(mListener); 524 525 switch (reply.type()) { 526 case DNSRequestResponse::TDNSRecord: { 527 mResultRecord = new ChildDNSRecord(reply.get_DNSRecord(), mFlags); 528 break; 529 } 530 case DNSRequestResponse::Tnsresult: { 531 mResultStatus = reply.get_nsresult(); 532 break; 533 } 534 case DNSRequestResponse::TIPCTypeRecord: { 535 MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT); 536 mResultRecord = new ChildDNSByTypeRecord( 537 reply.get_IPCTypeRecord().mData, mHost, 538 reply.get_IPCTypeRecord().mTTL, reply.get_IPCTypeRecord().mIsTRR); 539 break; 540 } 541 default: 542 MOZ_ASSERT_UNREACHABLE("unknown type"); 543 return false; 544 } 545 546 MOZ_ASSERT(NS_IsMainThread()); 547 548 bool targetIsMain = false; 549 if (!mTarget) { 550 targetIsMain = true; 551 } else { 552 mTarget->IsOnCurrentThread(&targetIsMain); 553 } 554 555 if (targetIsMain) { 556 CallOnLookupComplete(); 557 } else { 558 nsCOMPtr<nsIRunnable> event = 559 NewRunnableMethod("net::DNSRequestSender::CallOnLookupComplete", this, 560 &DNSRequestSender::CallOnLookupComplete); 561 mTarget->Dispatch(event, NS_DISPATCH_NORMAL); 562 } 563 564 if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) { 565 (void)mozilla::net::DNSRequestChild::Send__delete__(child); 566 } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) { 567 (void)mozilla::net::DNSRequestParent::Send__delete__(parent); 568 } 569 570 return true; 571 } 572 573 void DNSRequestSender::OnIPCActorDestroy() { 574 // Request is done or destroyed. Remove it from the hash table. 575 RefPtr<ChildDNSService> dnsServiceChild = 576 dont_AddRef(ChildDNSService::GetSingleton()); 577 dnsServiceChild->NotifyRequestDone(this); 578 579 mIPCActor = nullptr; 580 } 581 582 //----------------------------------------------------------------------------- 583 // DNSRequestChild 584 //----------------------------------------------------------------------------- 585 586 DNSRequestChild::DNSRequestChild(DNSRequestBase* aRequest) 587 : DNSRequestActor(aRequest) { 588 aRequest->SetIPCActor(this); 589 } 590 591 mozilla::ipc::IPCResult DNSRequestChild::RecvCancelDNSRequest( 592 const nsCString& hostName, const nsCString& trrServer, const int32_t& port, 593 const uint16_t& type, const OriginAttributes& originAttributes, 594 const nsIDNSService::DNSFlags& flags, const nsresult& reason) { 595 mDNSRequest->OnRecvCancelDNSRequest(hostName, trrServer, port, type, 596 originAttributes, flags, reason); 597 return IPC_OK(); 598 } 599 600 mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted( 601 const DNSRequestResponse& reply) { 602 return mDNSRequest->OnRecvLookupCompleted(reply) ? IPC_OK() 603 : IPC_FAIL_NO_REASON(this); 604 } 605 606 void DNSRequestChild::ActorDestroy(ActorDestroyReason) { 607 mDNSRequest->OnIPCActorDestroy(); 608 mDNSRequest = nullptr; 609 } 610 611 //------------------------------------------------------------------------------ 612 } // namespace net 613 } // namespace mozilla