From bf843aa911edde48d9fc578e97d0245acdb4c61c Mon Sep 17 00:00:00 2001 From: Kershaw Chang Date: Tue, 14 Apr 2020 09:14:41 +0000 Subject: [PATCH] Bug 1625151 - P1: Move DNS resolution to socket process r=dragana Differential Revision: https://phabricator.services.mozilla.com/D68388 --HG-- extra : moz-landing-system : lando --- netwerk/base/nsIOService.cpp | 5 + netwerk/dns/ChildDNSService.cpp | 46 +++-- netwerk/dns/ChildDNSService.h | 5 +- netwerk/dns/DNSRequestBase.h | 148 ++++++++++++++ netwerk/dns/DNSRequestChild.cpp | 197 ++++++++++++------- netwerk/dns/DNSRequestChild.h | 44 ++--- netwerk/dns/DNSRequestParent.cpp | 87 ++++++-- netwerk/dns/DNSRequestParent.h | 25 +-- netwerk/dns/PDNSRequest.ipdl | 3 +- netwerk/dns/moz.build | 1 + netwerk/dns/nsDNSService2.cpp | 41 +++- netwerk/ipc/NeckoParent.cpp | 9 +- netwerk/ipc/PSocketProcess.ipdl | 4 +- netwerk/ipc/SocketProcessChild.cpp | 23 +++ netwerk/ipc/SocketProcessChild.h | 10 + netwerk/ipc/SocketProcessHost.cpp | 1 + netwerk/ipc/SocketProcessImpl.cpp | 4 + netwerk/ipc/SocketProcessParent.cpp | 9 +- netwerk/test/unit/socks_client_subprocess.js | 2 + 19 files changed, 500 insertions(+), 164 deletions(-) create mode 100644 netwerk/dns/DNSRequestBase.h diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 00e8d5de88b3..d227456157ca 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -525,6 +525,10 @@ void nsIOService::NotifySocketProcessPrefsChanged(const char* aName) { return; } + if (!StaticPrefs::network_process_enabled()) { + return; + } + dom::Pref pref(nsCString(aName), /* isLocked */ false, Nothing(), Nothing()); Preferences::GetPreference(&pref); auto sendPrefUpdate = [pref]() { @@ -562,6 +566,7 @@ void nsIOService::CallOrWaitForSocketProcess( aFunc(); } else { mPendingEvents.AppendElement(aFunc); // infallible + LaunchSocketProcess(); } } diff --git a/netwerk/dns/ChildDNSService.cpp b/netwerk/dns/ChildDNSService.cpp index bd4ce98fa316..3fb397c4be97 100644 --- a/netwerk/dns/ChildDNSService.cpp +++ b/netwerk/dns/ChildDNSService.cpp @@ -3,7 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/net/ChildDNSService.h" +#include "nsDNSPrefetch.h" #include "nsIDNSListener.h" +#include "nsIOService.h" #include "nsThreadUtils.h" #include "nsIXPConnect.h" #include "nsIProtocolProxyService.h" @@ -25,7 +27,10 @@ static StaticRefPtr gChildDNSService; static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch"; already_AddRefed ChildDNSService::GetSingleton() { - MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsSocketProcess()); + MOZ_ASSERT_IF(nsIOService::UseSocketProcess(), + XRE_IsContentProcess() || XRE_IsParentProcess()); + MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(), + XRE_IsContentProcess() || XRE_IsSocketProcess()); if (!gChildDNSService) { gChildDNSService = new ChildDNSService(); @@ -41,7 +46,13 @@ ChildDNSService::ChildDNSService() : mFirstTime(true), mDisablePrefetch(false), mPendingRequestsLock("DNSPendingRequestsLock") { - MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsSocketProcess()); + MOZ_ASSERT_IF(nsIOService::UseSocketProcess(), + XRE_IsContentProcess() || XRE_IsParentProcess()); + MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(), + XRE_IsContentProcess() || XRE_IsSocketProcess()); + if (XRE_IsParentProcess() && nsIOService::UseSocketProcess()) { + nsDNSPrefetch::Initialize(this); + } } void ChildDNSService::GetDNSRecordHashKey( @@ -68,6 +79,11 @@ nsresult ChildDNSService::AsyncResolveInternal( NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE); } + bool resolveDNSInSocketProcess = false; + if (XRE_IsParentProcess() && nsIOService::UseSocketProcess()) { + resolveDNSInSocketProcess = true; + } + if (mDisablePrefetch && (flags & RESOLVE_SPECULATE)) { return NS_ERROR_DNS_LOOKUP_QUEUE_FULL; } @@ -87,8 +103,14 @@ nsresult ChildDNSService::AsyncResolveInternal( listener = new DNSListenerProxy(listener, target); } - RefPtr childReq = new DNSRequestChild( + RefPtr sender = new DNSRequestSender( hostname, aTrrServer, type, aOriginAttributes, flags, listener, target); + RefPtr dnsReq; + if (resolveDNSInSocketProcess) { + dnsReq = new DNSRequestParent(sender); + } else { + dnsReq = new DNSRequestChild(sender); + } { MutexAutoLock lock(mPendingRequestsLock); @@ -97,19 +119,19 @@ nsresult ChildDNSService::AsyncResolveInternal( originalListener, key); auto entry = mPendingRequests.LookupForAdd(key); if (entry) { - entry.Data()->AppendElement(childReq); + entry.Data()->AppendElement(sender); } else { entry.OrInsert([&]() { - auto* hashEntry = new nsTArray>(); - hashEntry->AppendElement(childReq); + auto* hashEntry = new nsTArray>(); + hashEntry->AppendElement(sender); return hashEntry; }); } } - childReq->StartRequest(); + sender->StartRequest(); - childReq.forget(result); + sender.forget(result); return NS_OK; } @@ -122,7 +144,7 @@ nsresult ChildDNSService::CancelAsyncResolveInternal( } MutexAutoLock lock(mPendingRequestsLock); - nsTArray>* hashEntry; + nsTArray>* hashEntry; nsCString key; GetDNSRecordHashKey(aHostname, aTrrServer, aType, aOriginAttributes, aFlags, aListener, key); @@ -347,7 +369,7 @@ ChildDNSService::GetMyHostName(nsACString& result) { return NS_ERROR_NOT_AVAILABLE; } -void ChildDNSService::NotifyRequestDone(DNSRequestChild* aDnsRequest) { +void ChildDNSService::NotifyRequestDone(DNSRequestSender* aDnsRequest) { // We need the original flags and listener for the pending requests hash. uint32_t originalFlags = aDnsRequest->mFlags & ~RESOLVE_OFFLINE; nsCOMPtr originalListener = aDnsRequest->mListener; @@ -367,11 +389,11 @@ void ChildDNSService::NotifyRequestDone(DNSRequestChild* aDnsRequest) { aDnsRequest->mType, aDnsRequest->mOriginAttributes, originalFlags, originalListener, key); - nsTArray>* hashEntry; + nsTArray>* hashEntry; if (mPendingRequests.Get(key, &hashEntry)) { auto idx = hashEntry->IndexOf(aDnsRequest); - if (idx != nsTArray>::NoIndex) { + if (idx != nsTArray>::NoIndex) { hashEntry->RemoveElementAt(idx); if (hashEntry->IsEmpty()) { mPendingRequests.Remove(key); diff --git a/netwerk/dns/ChildDNSService.h b/netwerk/dns/ChildDNSService.h index 08743037d2d3..a813ecae6604 100644 --- a/netwerk/dns/ChildDNSService.h +++ b/netwerk/dns/ChildDNSService.h @@ -12,6 +12,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Mutex.h" #include "DNSRequestChild.h" +#include "DNSRequestParent.h" #include "nsHashKeys.h" #include "nsClassHashtable.h" @@ -30,7 +31,7 @@ class ChildDNSService final : public nsPIDNSService, public nsIObserver { static already_AddRefed GetSingleton(); - void NotifyRequestDone(DNSRequestChild* aDnsRequest); + void NotifyRequestDone(DNSRequestSender* aDnsRequest); private: virtual ~ChildDNSService() = default; @@ -54,7 +55,7 @@ class ChildDNSService final : public nsPIDNSService, public nsIObserver { bool mDisablePrefetch; // We need to remember pending dns requests to be able to cancel them. - nsClassHashtable>> + nsClassHashtable>> mPendingRequests; Mutex mPendingRequestsLock; }; diff --git a/netwerk/dns/DNSRequestBase.h b/netwerk/dns/DNSRequestBase.h new file mode 100644 index 000000000000..a46eb1e4e2f5 --- /dev/null +++ b/netwerk/dns/DNSRequestBase.h @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_net_DNSRequestBase_h +#define mozilla_net_DNSRequestBase_h + +#include "mozilla/net/PDNSRequestParent.h" +#include "nsICancelable.h" +#include "nsIDNSRecord.h" +#include "nsIDNSListener.h" +#include "nsIDNSByTypeRecord.h" +#include "nsIEventTarget.h" + +namespace mozilla { +namespace net { + +class DNSRequestActor; +class DNSRequestChild; +class DNSRequestHandler; +class DNSRequestParent; +class DNSRequestSender; + +// A base class for DNSRequestSender and DNSRequestHandler. +// Provide interfaces for processing DNS requests. +class DNSRequestBase : public nsISupports { + public: + explicit DNSRequestBase() = default; + + void SetIPCActor(DNSRequestActor* aActor); + + virtual void OnRecvCancelDNSRequest(const nsCString& hostName, + const nsCString& trrServer, + const uint16_t& type, + const OriginAttributes& originAttributes, + const uint32_t& flags, + const nsresult& reason) = 0; + virtual bool OnRecvLookupCompleted(const DNSRequestResponse& reply) = 0; + virtual void OnIPCActorDestroy() = 0; + + virtual DNSRequestSender* AsDNSRequestSender() = 0; + virtual DNSRequestHandler* AsDNSRequestHandler() = 0; + + protected: + virtual ~DNSRequestBase() = default; + + RefPtr mIPCActor; +}; + +// DNSRequestSender is used to send an IPC request to DNSRequestHandler and +// deliver the result to nsIDNSListener. +// Note this class could be used both in content process and parent process. +class DNSRequestSender final : public DNSRequestBase, public nsICancelable { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSICANCELABLE + + DNSRequestSender(const nsACString& aHost, const nsACString& aTrrServer, + const uint16_t& aType, + const OriginAttributes& aOriginAttributes, + const uint32_t& aFlags, nsIDNSListener* aListener, + nsIEventTarget* target); + + void OnRecvCancelDNSRequest(const nsCString& hostName, + const nsCString& trrServer, const uint16_t& type, + const OriginAttributes& originAttributes, + const uint32_t& flags, + const nsresult& reason) override; + bool OnRecvLookupCompleted(const DNSRequestResponse& reply) override; + void OnIPCActorDestroy() override; + + // Sends IPDL request to DNSRequestHandler + void StartRequest(); + void CallOnLookupComplete(); + + DNSRequestSender* AsDNSRequestSender() override { return this; } + DNSRequestHandler* AsDNSRequestHandler() override { return nullptr; } + + private: + friend class ChildDNSService; + virtual ~DNSRequestSender() = default; + + nsCOMPtr mListener; + nsCOMPtr mTarget; + nsCOMPtr mResultRecord; + nsresult mResultStatus; + nsCString mHost; + nsCString mTrrServer; + uint16_t mType; + const OriginAttributes mOriginAttributes; + uint16_t mFlags; +}; + +// DNSRequestHandler handles the dns request and sends the result back via IPC. +// Note this class could be used both in parent process and socket process. +class DNSRequestHandler final : public DNSRequestBase, public nsIDNSListener { + public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDNSLISTENER + + DNSRequestHandler(); + + void DoAsyncResolve(const nsACString& hostname, const nsACString& trrServer, + uint16_t type, const OriginAttributes& originAttributes, + uint32_t flags); + + void OnRecvCancelDNSRequest(const nsCString& hostName, + const nsCString& trrServer, const uint16_t& type, + const OriginAttributes& originAttributes, + const uint32_t& flags, + const nsresult& reason) override; + bool OnRecvLookupCompleted(const DNSRequestResponse& reply) override; + void OnIPCActorDestroy() override; + + DNSRequestSender* AsDNSRequestSender() override { return nullptr; } + DNSRequestHandler* AsDNSRequestHandler() override { return this; } + + private: + virtual ~DNSRequestHandler() = default; + + uint32_t mFlags; +}; + +// Provides some common methods for DNSRequestChild and DNSRequestParent. +class DNSRequestActor { + public: + NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING + + explicit DNSRequestActor(DNSRequestBase* aRequest) : mDNSRequest(aRequest) {} + + virtual bool CanSend() const = 0; + virtual DNSRequestChild* AsDNSRequestChild() = 0; + virtual DNSRequestParent* AsDNSRequestParent() = 0; + + DNSRequestBase* GetDNSRequest() { return mDNSRequest.get(); }; + + protected: + virtual ~DNSRequestActor() = default; + + RefPtr mDNSRequest; +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_DNSRequestBase_h diff --git a/netwerk/dns/DNSRequestChild.cpp b/netwerk/dns/DNSRequestChild.cpp index 9c9e643779ea..ff0bd81254da 100644 --- a/netwerk/dns/DNSRequestChild.cpp +++ b/netwerk/dns/DNSRequestChild.cpp @@ -7,13 +7,16 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/net/ChildDNSService.h" #include "mozilla/net/DNSRequestChild.h" +#include "mozilla/net/DNSRequestParent.h" #include "mozilla/net/NeckoChild.h" #include "mozilla/net/SocketProcessChild.h" #include "mozilla/SchedulerGroup.h" +#include "mozilla/net/SocketProcessParent.h" #include "mozilla/Unused.h" #include "nsIDNSRecord.h" #include "nsIDNSByTypeRecord.h" #include "nsHostResolver.h" +#include "nsIOService.h" #include "nsTArray.h" #include "nsNetAddr.h" #include "nsThreadUtils.h" @@ -23,6 +26,10 @@ using namespace mozilla::ipc; namespace mozilla { namespace net { +void DNSRequestBase::SetIPCActor(DNSRequestActor* aActor) { + mIPCActor = aActor; +} + //----------------------------------------------------------------------------- // ChildDNSRecord: // A simple class to provide nsIDNSRecord on the child @@ -193,37 +200,12 @@ ChildDNSByTypeRecord::GetRecordsAsOneString(nsACString& aRecords) { } //----------------------------------------------------------------------------- -// CancelDNSRequestEvent +// DNSRequestSender //----------------------------------------------------------------------------- -class CancelDNSRequestEvent : public Runnable { - public: - CancelDNSRequestEvent(DNSRequestChild* aDnsReq, nsresult aReason) - : Runnable("net::CancelDNSRequestEvent"), - mDnsRequest(aDnsReq), - mReasonForCancel(aReason) {} +NS_IMPL_ISUPPORTS(DNSRequestSender, nsICancelable) - NS_IMETHOD Run() override { - if (mDnsRequest->CanSend()) { - // Send request to Parent process. - mDnsRequest->SendCancelDNSRequest( - mDnsRequest->mHost, mDnsRequest->mTrrServer, mDnsRequest->mType, - mDnsRequest->mOriginAttributes, mDnsRequest->mFlags, - mReasonForCancel); - } - return NS_OK; - } - - private: - RefPtr mDnsRequest; - nsresult mReasonForCancel; -}; - -//----------------------------------------------------------------------------- -// DNSRequestChild -//----------------------------------------------------------------------------- - -DNSRequestChild::DNSRequestChild( +DNSRequestSender::DNSRequestSender( const nsACString& aHost, const nsACString& aTrrServer, const uint16_t& aType, const OriginAttributes& aOriginAttributes, const uint32_t& aFlags, nsIDNSListener* aListener, nsIEventTarget* target) @@ -236,47 +218,105 @@ DNSRequestChild::DNSRequestChild( mOriginAttributes(aOriginAttributes), mFlags(aFlags) {} -void DNSRequestChild::StartRequest() { +void DNSRequestSender::OnRecvCancelDNSRequest( + const nsCString& hostName, const nsCString& trrServer, const uint16_t& type, + const OriginAttributes& originAttributes, const uint32_t& flags, + const nsresult& reason) {} + +NS_IMETHODIMP +DNSRequestSender::Cancel(nsresult reason) { + if (!mIPCActor) { + return NS_ERROR_NOT_AVAILABLE; + } + + if (mIPCActor->CanSend()) { + // We can only do IPDL on the main thread + nsCOMPtr runnable = NS_NewRunnableFunction( + "net::CancelDNSRequestEvent", + [actor(mIPCActor), host(mHost), trrServer(mTrrServer), type(mType), + originAttributes(mOriginAttributes), flags(mFlags), reason]() { + if (!actor->CanSend()) { + return; + } + + if (DNSRequestChild* child = actor->AsDNSRequestChild()) { + Unused << child->SendCancelDNSRequest( + host, trrServer, type, originAttributes, flags, reason); + } else if (DNSRequestParent* parent = actor->AsDNSRequestParent()) { + Unused << parent->SendCancelDNSRequest( + host, trrServer, type, originAttributes, flags, reason); + } + }); + SchedulerGroup::Dispatch(TaskCategory::Other, runnable.forget()); + } + return NS_OK; +} + +void DNSRequestSender::StartRequest() { // we can only do IPDL on the main thread if (!NS_IsMainThread()) { SchedulerGroup::Dispatch( TaskCategory::Other, - NewRunnableMethod("net::DNSRequestChild::StartRequest", this, - &DNSRequestChild::StartRequest)); + NewRunnableMethod("net::DNSRequestSender::StartRequest", this, + &DNSRequestSender::StartRequest)); return; } - if (XRE_IsContentProcess()) { - mozilla::dom::ContentChild* cc = - static_cast(gNeckoChild->Manager()); - if (cc->IsShuttingDown()) { + if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) { + if (XRE_IsContentProcess()) { + mozilla::dom::ContentChild* cc = + static_cast(gNeckoChild->Manager()); + if (cc->IsShuttingDown()) { + return; + } + + // Send request to Parent process. + gNeckoChild->SendPDNSRequestConstructor(child, mHost, mTrrServer, mType, + mOriginAttributes, mFlags); + } else if (XRE_IsSocketProcess()) { + // DNS resolution is done in the parent process. Send a DNS request to + // parent process. + MOZ_ASSERT(!nsIOService::UseSocketProcess()); + + SocketProcessChild* socketProcessChild = + SocketProcessChild::GetSingleton(); + if (!socketProcessChild->CanSend()) { + return; + } + + socketProcessChild->SendPDNSRequestConstructor( + child, mHost, mTrrServer, mType, mOriginAttributes, mFlags); + } else { + MOZ_ASSERT(false, "Wrong process"); + return; + } + } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) { + // DNS resolution is done in the socket process. Send a DNS request to + // socket process. + MOZ_ASSERT(nsIOService::UseSocketProcess()); + + RefPtr requestParent = parent; + RefPtr self = this; + auto task = [requestParent, self]() { + Unused << SocketProcessParent::GetSingleton()->SendPDNSRequestConstructor( + requestParent, self->mHost, self->mTrrServer, self->mType, + self->mOriginAttributes, self->mFlags); + }; + if (!gIOService->SocketProcessReady()) { + gIOService->CallOrWaitForSocketProcess(std::move(task)); return; } - // Send request to Parent process. - gNeckoChild->SendPDNSRequestConstructor(this, mHost, mTrrServer, mType, - mOriginAttributes, mFlags); - } else if (XRE_IsSocketProcess()) { - SocketProcessChild* child = SocketProcessChild::GetSingleton(); - if (!child->CanSend()) { - return; - } - - child->SendPDNSRequestConstructor(this, mHost, mTrrServer, mType, - mOriginAttributes, mFlags); - } else { - MOZ_ASSERT(false, "Wrong process"); - return; + task(); } } -void DNSRequestChild::CallOnLookupComplete() { +void DNSRequestSender::CallOnLookupComplete() { MOZ_ASSERT(mListener); mListener->OnLookupComplete(this, mResultRecord, mResultStatus); } -mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted( - const DNSRequestResponse& reply) { +bool DNSRequestSender::OnRecvLookupCompleted(const DNSRequestResponse& reply) { MOZ_ASSERT(mListener); switch (reply.type()) { @@ -295,7 +335,7 @@ mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted( } default: MOZ_ASSERT_UNREACHABLE("unknown type"); - return IPC_FAIL_NO_REASON(this); + return false; } MOZ_ASSERT(NS_IsMainThread()); @@ -311,41 +351,56 @@ mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted( CallOnLookupComplete(); } else { nsCOMPtr event = - NewRunnableMethod("net::DNSRequestChild::CallOnLookupComplete", this, - &DNSRequestChild::CallOnLookupComplete); + NewRunnableMethod("net::DNSRequestSender::CallOnLookupComplete", this, + &DNSRequestSender::CallOnLookupComplete); mTarget->Dispatch(event, NS_DISPATCH_NORMAL); } - Unused << Send__delete__(this); + if (DNSRequestChild* child = mIPCActor->AsDNSRequestChild()) { + Unused << child->Send__delete__(child); + } else if (DNSRequestParent* parent = mIPCActor->AsDNSRequestParent()) { + Unused << parent->Send__delete__(parent); + } - return IPC_OK(); + return true; } -void DNSRequestChild::ActorDestroy(ActorDestroyReason why) { +void DNSRequestSender::OnIPCActorDestroy() { // Request is done or destroyed. Remove it from the hash table. RefPtr dnsServiceChild = dont_AddRef(ChildDNSService::GetSingleton()); dnsServiceChild->NotifyRequestDone(this); + + mIPCActor = nullptr; } //----------------------------------------------------------------------------- -// DNSRequestChild::nsISupports +// DNSRequestChild //----------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS(DNSRequestChild, nsICancelable) +DNSRequestChild::DNSRequestChild(DNSRequestBase* aRequest) + : DNSRequestActor(aRequest) { + aRequest->SetIPCActor(this); +} -//----------------------------------------------------------------------------- -// DNSRequestChild::nsICancelable -//----------------------------------------------------------------------------- +mozilla::ipc::IPCResult DNSRequestChild::RecvCancelDNSRequest( + const nsCString& hostName, const nsCString& trrServer, const uint16_t& type, + const OriginAttributes& originAttributes, const uint32_t& flags, + const nsresult& reason) { + mDNSRequest->OnRecvCancelDNSRequest(hostName, trrServer, type, + originAttributes, flags, reason); + return IPC_OK(); +} -NS_IMETHODIMP -DNSRequestChild::Cancel(nsresult reason) { - if (CanSend()) { - // We can only do IPDL on the main thread - nsCOMPtr runnable = new CancelDNSRequestEvent(this, reason); - SchedulerGroup::Dispatch(TaskCategory::Other, runnable.forget()); - } - return NS_OK; +mozilla::ipc::IPCResult DNSRequestChild::RecvLookupCompleted( + const DNSRequestResponse& reply) { + return mDNSRequest->OnRecvLookupCompleted(reply) ? IPC_OK() + : IPC_FAIL_NO_REASON(this); +} + +void DNSRequestChild::ActorDestroy(ActorDestroyReason) { + mDNSRequest->OnIPCActorDestroy(); + mDNSRequest = nullptr; } //------------------------------------------------------------------------------ diff --git a/netwerk/dns/DNSRequestChild.h b/netwerk/dns/DNSRequestChild.h index 46388308ed48..c360b8d58b65 100644 --- a/netwerk/dns/DNSRequestChild.h +++ b/netwerk/dns/DNSRequestChild.h @@ -7,50 +7,32 @@ #ifndef mozilla_net_DNSRequestChild_h #define mozilla_net_DNSRequestChild_h +#include "mozilla/net/DNSRequestBase.h" #include "mozilla/net/PDNSRequestChild.h" -#include "nsICancelable.h" -#include "nsIDNSRecord.h" -#include "nsIDNSListener.h" -#include "nsIDNSByTypeRecord.h" -#include "nsIEventTarget.h" namespace mozilla { namespace net { -class DNSRequestChild final : public PDNSRequestChild, public nsICancelable { +class DNSRequestChild final : public DNSRequestActor, public PDNSRequestChild { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DNSRequestChild, override) friend class PDNSRequestChild; - public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSICANCELABLE + explicit DNSRequestChild(DNSRequestBase* aRequest); - DNSRequestChild(const nsACString& aHost, const nsACString& aTrrServer, - const uint16_t& aType, - const OriginAttributes& aOriginAttributes, - const uint32_t& aFlags, nsIDNSListener* aListener, - nsIEventTarget* target); + bool CanSend() const override { return PDNSRequestChild::CanSend(); } + DNSRequestChild* AsDNSRequestChild() override { return this; } + DNSRequestParent* AsDNSRequestParent() override { return nullptr; } - // Sends IPDL request to parent - void StartRequest(); - void CallOnLookupComplete(); - - protected: - friend class CancelDNSRequestEvent; - friend class ChildDNSService; + private: virtual ~DNSRequestChild() = default; + mozilla::ipc::IPCResult RecvCancelDNSRequest( + const nsCString& hostName, const nsCString& trrServer, + const uint16_t& type, const OriginAttributes& originAttributes, + const uint32_t& flags, const nsresult& reason); mozilla::ipc::IPCResult RecvLookupCompleted(const DNSRequestResponse& reply); virtual void ActorDestroy(ActorDestroyReason why) override; - - nsCOMPtr mListener; - nsCOMPtr mTarget; - nsCOMPtr mResultRecord; - nsresult mResultStatus; - nsCString mHost; - nsCString mTrrServer; - uint16_t mType; - const OriginAttributes mOriginAttributes; - uint16_t mFlags; }; } // namespace net diff --git a/netwerk/dns/DNSRequestParent.cpp b/netwerk/dns/DNSRequestParent.cpp index e0fc16cdbe26..cebb13624b46 100644 --- a/netwerk/dns/DNSRequestParent.cpp +++ b/netwerk/dns/DNSRequestParent.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/net/DNSRequestParent.h" +#include "mozilla/net/DNSRequestChild.h" #include "nsIDNSService.h" #include "nsNetCID.h" #include "nsThreadUtils.h" @@ -18,13 +19,28 @@ using namespace mozilla::ipc; namespace mozilla { namespace net { -DNSRequestParent::DNSRequestParent() : mFlags(0) {} +DNSRequestHandler::DNSRequestHandler() : mFlags(0) {} -void DNSRequestParent::DoAsyncResolve(const nsACString& hostname, - const nsACString& trrServer, - uint16_t type, - const OriginAttributes& originAttributes, - uint32_t flags) { +//----------------------------------------------------------------------------- +// DNSRequestHandler::nsISupports +//----------------------------------------------------------------------------- + +NS_IMPL_ISUPPORTS(DNSRequestHandler, nsIDNSListener) + +static void SendLookupCompletedHelper(DNSRequestActor* aActor, + const DNSRequestResponse& aReply) { + if (DNSRequestParent* parent = aActor->AsDNSRequestParent()) { + Unused << parent->SendLookupCompleted(aReply); + } else if (DNSRequestChild* child = aActor->AsDNSRequestChild()) { + Unused << child->SendLookupCompleted(aReply); + } +} + +void DNSRequestHandler::DoAsyncResolve(const nsACString& hostname, + const nsACString& trrServer, + uint16_t type, + const OriginAttributes& originAttributes, + uint32_t flags) { nsresult rv; mFlags = flags; nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); @@ -45,12 +61,12 @@ void DNSRequestParent::DoAsyncResolve(const nsACString& hostname, } } - if (NS_FAILED(rv) && CanSend()) { - Unused << SendLookupCompleted(DNSRequestResponse(rv)); + if (NS_FAILED(rv) && mIPCActor->CanSend()) { + SendLookupCompletedHelper(mIPCActor, DNSRequestResponse(rv)); } } -mozilla::ipc::IPCResult DNSRequestParent::RecvCancelDNSRequest( +void DNSRequestHandler::OnRecvCancelDNSRequest( const nsCString& hostName, const nsCString& aTrrServer, const uint16_t& type, const OriginAttributes& originAttributes, const uint32_t& flags, const nsresult& reason) { @@ -68,23 +84,20 @@ mozilla::ipc::IPCResult DNSRequestParent::RecvCancelDNSRequest( hostName, aTrrServer, flags, this, reason, originAttributes); } } - return IPC_OK(); } -//----------------------------------------------------------------------------- -// DNSRequestParent::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_ISUPPORTS(DNSRequestParent, nsIDNSListener) +bool DNSRequestHandler::OnRecvLookupCompleted(const DNSRequestResponse& reply) { + return true; +} //----------------------------------------------------------------------------- // nsIDNSListener functions //----------------------------------------------------------------------------- NS_IMETHODIMP -DNSRequestParent::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, - nsresult status) { - if (!CanSend()) { +DNSRequestHandler::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, + nsresult status) { + if (!mIPCActor || !mIPCActor->CanSend()) { // nothing to do: child probably crashed return NS_OK; } @@ -96,7 +109,7 @@ DNSRequestParent::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, if (txtRec) { nsTArray rec; txtRec->GetRecords(rec); - Unused << SendLookupCompleted(DNSRequestResponse(rec)); + SendLookupCompletedHelper(mIPCActor, DNSRequestResponse(rec)); return NS_OK; } @@ -112,13 +125,45 @@ DNSRequestParent::OnLookupComplete(nsICancelable* request, nsIDNSRecord* rec, array.AppendElement(addr); } - Unused << SendLookupCompleted(DNSRequestResponse(DNSRecord(cname, array))); + SendLookupCompletedHelper(mIPCActor, + DNSRequestResponse(DNSRecord(cname, array))); } else { - Unused << SendLookupCompleted(DNSRequestResponse(status)); + SendLookupCompletedHelper(mIPCActor, DNSRequestResponse(status)); } return NS_OK; } +void DNSRequestHandler::OnIPCActorDestroy() { mIPCActor = nullptr; } + +//----------------------------------------------------------------------------- +// DNSRequestParent functions +//----------------------------------------------------------------------------- + +DNSRequestParent::DNSRequestParent(DNSRequestBase* aRequest) + : DNSRequestActor(aRequest) { + aRequest->SetIPCActor(this); +} + +mozilla::ipc::IPCResult DNSRequestParent::RecvCancelDNSRequest( + const nsCString& hostName, const nsCString& trrServer, const uint16_t& type, + const OriginAttributes& originAttributes, const uint32_t& flags, + const nsresult& reason) { + mDNSRequest->OnRecvCancelDNSRequest(hostName, trrServer, type, + originAttributes, flags, reason); + return IPC_OK(); +} + +mozilla::ipc::IPCResult DNSRequestParent::RecvLookupCompleted( + const DNSRequestResponse& reply) { + return mDNSRequest->OnRecvLookupCompleted(reply) ? IPC_OK() + : IPC_FAIL_NO_REASON(this); +} + +void DNSRequestParent::ActorDestroy(ActorDestroyReason) { + mDNSRequest->OnIPCActorDestroy(); + mDNSRequest = nullptr; +} + } // namespace net } // namespace mozilla diff --git a/netwerk/dns/DNSRequestParent.h b/netwerk/dns/DNSRequestParent.h index 1e7f41edd4bc..59e6df8235ed 100644 --- a/netwerk/dns/DNSRequestParent.h +++ b/netwerk/dns/DNSRequestParent.h @@ -7,22 +7,26 @@ #ifndef mozilla_net_DNSRequestParent_h #define mozilla_net_DNSRequestParent_h +#include "mozilla/net/DNSRequestBase.h" #include "mozilla/net/PDNSRequestParent.h" #include "nsIDNSListener.h" namespace mozilla { namespace net { -class DNSRequestParent : public PDNSRequestParent, public nsIDNSListener { +class DNSRequestParent : public DNSRequestActor, public PDNSRequestParent { public: - NS_DECL_ISUPPORTS - NS_DECL_NSIDNSLISTENER + friend class PDNSRequestParent; + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DNSRequestParent, override) - DNSRequestParent(); + explicit DNSRequestParent(DNSRequestBase* aRequest); - void DoAsyncResolve(const nsACString& hostname, const nsACString& trrServer, - uint16_t type, const OriginAttributes& originAttributes, - uint32_t flags); + bool CanSend() const override { return PDNSRequestParent::CanSend(); } + DNSRequestChild* AsDNSRequestChild() override { return nullptr; } + DNSRequestParent* AsDNSRequestParent() override { return this; } + + private: + virtual ~DNSRequestParent() = default; // Pass args here rather than storing them in the parent; they are only // needed if the request is to be canceled. @@ -30,11 +34,8 @@ class DNSRequestParent : public PDNSRequestParent, public nsIDNSListener { const nsCString& hostName, const nsCString& trrServer, const uint16_t& type, const OriginAttributes& originAttributes, const uint32_t& flags, const nsresult& reason); - - private: - virtual ~DNSRequestParent() = default; - - uint32_t mFlags; + mozilla::ipc::IPCResult RecvLookupCompleted(const DNSRequestResponse& reply); + void ActorDestroy(ActorDestroyReason) override; }; } // namespace net diff --git a/netwerk/dns/PDNSRequest.ipdl b/netwerk/dns/PDNSRequest.ipdl index a0809bdcce23..f6429c7c54f9 100644 --- a/netwerk/dns/PDNSRequest.ipdl +++ b/netwerk/dns/PDNSRequest.ipdl @@ -21,7 +21,7 @@ async refcounted protocol PDNSRequest { manager PNecko or PSocketProcess; -parent: +both: // constructor in PNecko takes AsyncResolve args that initialize request // Pass args here rather than storing them in the parent; they are only @@ -31,7 +31,6 @@ parent: uint32_t flags, nsresult reason); async __delete__(); -child: async LookupCompleted(DNSRequestResponse reply); }; diff --git a/netwerk/dns/moz.build b/netwerk/dns/moz.build index 0d4717c76640..737e03d80d57 100644 --- a/netwerk/dns/moz.build +++ b/netwerk/dns/moz.build @@ -39,6 +39,7 @@ EXPORTS.mozilla.net += [ 'ChildDNSService.h', 'DNS.h', 'DNSListenerProxy.h', + 'DNSRequestBase.h', 'DNSRequestChild.h', 'DNSRequestParent.h', 'IDNBlocklistUtils.h', diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index a76d9b9358d0..d06125694772 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -10,6 +10,7 @@ #include "nsIDNSByTypeRecord.h" #include "nsICancelable.h" #include "nsIPrefBranch.h" +#include "nsIOService.h" #include "nsIXPConnect.h" #include "nsProxyRelease.h" #include "nsReadableUtils.h" @@ -39,6 +40,7 @@ #include "mozilla/net/DNSListenerProxy.h" #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" +#include "mozilla/SyncRunnable.h" #include "mozilla/TextUtils.h" #include "mozilla/Utf8.h" @@ -545,6 +547,18 @@ NS_IMPL_ISUPPORTS(nsDNSService, nsIDNSService, nsPIDNSService, nsIObserver, static StaticRefPtr gDNSService; already_AddRefed nsDNSService::GetXPCOMSingleton() { + if (nsIOService::UseSocketProcess()) { + if (XRE_IsSocketProcess()) { + return GetSingleton(); + } + + if (XRE_IsContentProcess() || XRE_IsParentProcess()) { + return ChildDNSService::GetSingleton(); + } + + return nullptr; + } + if (XRE_IsParentProcess()) { return GetSingleton(); } @@ -557,14 +571,31 @@ already_AddRefed nsDNSService::GetXPCOMSingleton() { } already_AddRefed nsDNSService::GetSingleton() { - NS_ASSERTION(XRE_IsParentProcess(), "not a parent process"); + MOZ_ASSERT_IF(nsIOService::UseSocketProcess(), XRE_IsSocketProcess()); + MOZ_ASSERT_IF(!nsIOService::UseSocketProcess(), XRE_IsParentProcess()); if (!gDNSService) { - gDNSService = new nsDNSService(); - if (NS_SUCCEEDED(gDNSService->Init())) { - ClearOnShutdown(&gDNSService); + auto initTask = []() { + gDNSService = new nsDNSService(); + if (NS_SUCCEEDED(gDNSService->Init())) { + ClearOnShutdown(&gDNSService); + } else { + gDNSService = nullptr; + } + }; + + if (!NS_IsMainThread()) { + // Forward to the main thread synchronously. + RefPtr mainThread = do_GetMainThread(); + if (!mainThread) { + return nullptr; + } + + SyncRunnable::DispatchToThread(mainThread, + new SyncRunnable(NS_NewRunnableFunction( + "nsDNSService::Init", initTask))); } else { - gDNSService = nullptr; + initTask(); } } diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 0bbfce141c35..a56093190c66 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -615,7 +615,8 @@ bool NeckoParent::DeallocPUDPSocketParent(PUDPSocketParent* actor) { already_AddRefed NeckoParent::AllocPDNSRequestParent( const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType, const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { - RefPtr actor = new DNSRequestParent(); + RefPtr handler = new DNSRequestHandler(); + RefPtr actor = new DNSRequestParent(handler); return actor.forget(); } @@ -623,8 +624,10 @@ mozilla::ipc::IPCResult NeckoParent::RecvPDNSRequestConstructor( PDNSRequestParent* aActor, const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType, const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { - static_cast(aActor)->DoAsyncResolve( - aHost, aTrrServer, aType, aOriginAttributes, aFlags); + RefPtr actor = static_cast(aActor); + RefPtr handler = + actor->GetDNSRequest()->AsDNSRequestHandler(); + handler->DoAsyncResolve(aHost, aTrrServer, aType, aOriginAttributes, aFlags); return IPC_OK(); } diff --git a/netwerk/ipc/PSocketProcess.ipdl b/netwerk/ipc/PSocketProcess.ipdl index eaa06473bfc6..ef156fefbb8b 100644 --- a/netwerk/ipc/PSocketProcess.ipdl +++ b/netwerk/ipc/PSocketProcess.ipdl @@ -63,8 +63,6 @@ parent: /* tabId is only required for web-proxy support, which isn't always needed */ async PWebrtcTCPSocket(TabId? tabId); - async PDNSRequest(nsCString hostName, nsCString trrServer, uint16_t type, - OriginAttributes originAttributes, uint32_t flags); async PChildToParentStream(); async ObserveHttpActivity(HttpActivityArgs aActivityArgs, uint32_t aActivityType, @@ -100,6 +98,8 @@ child: both: async PFileDescriptorSet(FileDescriptor fd); + async PDNSRequest(nsCString hostName, nsCString trrServer, uint16_t type, + OriginAttributes originAttributes, uint32_t flags); }; } // namespace net diff --git a/netwerk/ipc/SocketProcessChild.cpp b/netwerk/ipc/SocketProcessChild.cpp index 7286fa504966..bf0c0cb2b85b 100644 --- a/netwerk/ipc/SocketProcessChild.cpp +++ b/netwerk/ipc/SocketProcessChild.cpp @@ -19,10 +19,14 @@ #include "mozilla/ipc/ProcessChild.h" #include "mozilla/net/AltSvcTransactionChild.h" #include "mozilla/net/DNSRequestChild.h" +#include "mozilla/net/DNSRequestParent.h" #include "mozilla/ipc/PChildToParentStreamChild.h" #include "mozilla/ipc/PParentToChildStreamChild.h" #include "mozilla/Preferences.h" +#include "mozilla/Telemetry.h" #include "nsDebugImpl.h" +#include "nsHttpConnectionInfo.h" +#include "nsHttpHandler.h" #include "nsIDNSService.h" #include "nsIHttpActivityObserver.h" #include "nsThreadManager.h" @@ -352,5 +356,24 @@ SocketProcessChild::AllocPAltSvcTransactionChild( return child.forget(); } +already_AddRefed SocketProcessChild::AllocPDNSRequestChild( + const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType, + const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { + RefPtr handler = new DNSRequestHandler(); + RefPtr actor = new DNSRequestChild(handler); + return actor.forget(); +} + +mozilla::ipc::IPCResult SocketProcessChild::RecvPDNSRequestConstructor( + PDNSRequestChild* aActor, const nsCString& aHost, + const nsCString& aTrrServer, const uint16_t& aType, + const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { + RefPtr actor = static_cast(aActor); + RefPtr handler = + actor->GetDNSRequest()->AsDNSRequestHandler(); + handler->DoAsyncResolve(aHost, aTrrServer, aType, aOriginAttributes, aFlags); + return IPC_OK(); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/ipc/SocketProcessChild.h b/netwerk/ipc/SocketProcessChild.h index e5895d288f28..35f69c7c6681 100644 --- a/netwerk/ipc/SocketProcessChild.h +++ b/netwerk/ipc/SocketProcessChild.h @@ -86,6 +86,16 @@ class SocketProcessChild final bool IsShuttingDown() { return mShuttingDown; } + already_AddRefed AllocPDNSRequestChild( + const nsCString& aHost, const nsCString& aTrrServer, + const uint16_t& aType, const OriginAttributes& aOriginAttributes, + const uint32_t& aFlags); + mozilla::ipc::IPCResult RecvPDNSRequestConstructor( + PDNSRequestChild* aActor, const nsCString& aHost, + const nsCString& aTrrServer, const uint16_t& aType, + const OriginAttributes& aOriginAttributes, + const uint32_t& aFlags) override; + protected: friend class SocketProcessImpl; ~SocketProcessChild(); diff --git a/netwerk/ipc/SocketProcessHost.cpp b/netwerk/ipc/SocketProcessHost.cpp index 678801ab612e..a6b63572d289 100644 --- a/netwerk/ipc/SocketProcessHost.cpp +++ b/netwerk/ipc/SocketProcessHost.cpp @@ -7,6 +7,7 @@ #include "nsAppRunner.h" #include "nsIObserverService.h" +#include "nsIOService.h" #include "SocketProcessParent.h" #if defined(XP_LINUX) && defined(MOZ_SANDBOX) diff --git a/netwerk/ipc/SocketProcessImpl.cpp b/netwerk/ipc/SocketProcessImpl.cpp index e63d822ffdba..3d7cdb956b68 100644 --- a/netwerk/ipc/SocketProcessImpl.cpp +++ b/netwerk/ipc/SocketProcessImpl.cpp @@ -16,6 +16,10 @@ # include "mozilla/sandboxTarget.h" #endif +#ifdef OS_POSIX +# include // For sleep(). +#endif + using mozilla::ipc::IOThreadChild; namespace mozilla { diff --git a/netwerk/ipc/SocketProcessParent.cpp b/netwerk/ipc/SocketProcessParent.cpp index 46d9068f0c1f..b104f90f5775 100644 --- a/netwerk/ipc/SocketProcessParent.cpp +++ b/netwerk/ipc/SocketProcessParent.cpp @@ -153,7 +153,8 @@ bool SocketProcessParent::DeallocPWebrtcTCPSocketParent( already_AddRefed SocketProcessParent::AllocPDNSRequestParent( const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType, const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { - RefPtr actor = new DNSRequestParent(); + RefPtr handler = new DNSRequestHandler(); + RefPtr actor = new DNSRequestParent(handler); return actor.forget(); } @@ -161,8 +162,10 @@ mozilla::ipc::IPCResult SocketProcessParent::RecvPDNSRequestConstructor( PDNSRequestParent* aActor, const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType, const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { - static_cast(aActor)->DoAsyncResolve( - aHost, aTrrServer, aType, aOriginAttributes, aFlags); + RefPtr actor = static_cast(aActor); + RefPtr handler = + actor->GetDNSRequest()->AsDNSRequestHandler(); + handler->DoAsyncResolve(aHost, aTrrServer, aType, aOriginAttributes, aFlags); return IPC_OK(); } diff --git a/netwerk/test/unit/socks_client_subprocess.js b/netwerk/test/unit/socks_client_subprocess.js index 1f858737aacd..9aa600b530d2 100644 --- a/netwerk/test/unit/socks_client_subprocess.js +++ b/netwerk/test/unit/socks_client_subprocess.js @@ -4,6 +4,8 @@ var CC = Components.Constructor; +var dns = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService); + const BinaryInputStream = CC( "@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream",