diff options
Diffstat (limited to 'netwerk/ipc/SocketProcessParent.cpp')
-rw-r--r-- | netwerk/ipc/SocketProcessParent.cpp | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/netwerk/ipc/SocketProcessParent.cpp b/netwerk/ipc/SocketProcessParent.cpp new file mode 100644 index 0000000000..7e3e0ac63c --- /dev/null +++ b/netwerk/ipc/SocketProcessParent.cpp @@ -0,0 +1,429 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include "SocketProcessParent.h" +#include "SocketProcessLogging.h" + +#include "AltServiceParent.h" +#include "CachePushChecker.h" +#include "HttpTransactionParent.h" +#include "SocketProcessHost.h" +#include "mozilla/dom/MemoryReportRequest.h" +#include "mozilla/ipc/FileDescriptorSetParent.h" +#include "mozilla/ipc/IPCStreamAlloc.h" +#include "mozilla/ipc/PChildToParentStreamParent.h" +#include "mozilla/ipc/PParentToChildStreamParent.h" +#include "mozilla/net/DNSRequestParent.h" +#include "mozilla/net/ProxyConfigLookupParent.h" +#include "mozilla/RemoteLazyInputStreamParent.h" +#include "mozilla/Telemetry.h" +#include "mozilla/TelemetryIPC.h" +#include "nsIAppStartup.h" +#include "nsIHttpActivityObserver.h" +#include "nsNSSIOLayer.h" +#include "PSMIPCCommon.h" +#include "secerr.h" +#ifdef MOZ_WEBRTC +# include "mozilla/dom/ContentProcessManager.h" +# include "mozilla/dom/BrowserParent.h" +# include "mozilla/net/WebrtcTCPSocketParent.h" +#endif +#if defined(MOZ_WIDGET_ANDROID) +# include "mozilla/java/GeckoProcessManagerWrappers.h" +# include "mozilla/java/GeckoProcessTypeWrappers.h" +#endif // defined(MOZ_WIDGET_ANDROID) + +namespace mozilla { +namespace net { + +static SocketProcessParent* sSocketProcessParent; + +SocketProcessParent::SocketProcessParent(SocketProcessHost* aHost) + : mHost(aHost) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mHost); + + MOZ_COUNT_CTOR(SocketProcessParent); + sSocketProcessParent = this; +} + +SocketProcessParent::~SocketProcessParent() { + MOZ_ASSERT(NS_IsMainThread()); + + MOZ_COUNT_DTOR(SocketProcessParent); + sSocketProcessParent = nullptr; +} + +/* static */ +SocketProcessParent* SocketProcessParent::GetSingleton() { + MOZ_ASSERT(NS_IsMainThread()); + + return sSocketProcessParent; +} + +void SocketProcessParent::ActorDestroy(ActorDestroyReason aWhy) { +#if defined(MOZ_WIDGET_ANDROID) + nsCOMPtr<nsIEventTarget> launcherThread(ipc::GetIPCLauncher()); + MOZ_ASSERT(launcherThread); + + auto procType = java::GeckoProcessType::SOCKET(); + auto selector = + java::GeckoProcessManager::Selector::New(procType, OtherPid()); + + launcherThread->Dispatch(NS_NewRunnableFunction( + "SocketProcessParent::ActorDestroy", + [selector = java::GeckoProcessManager::Selector::GlobalRef(selector)]() { + java::GeckoProcessManager::ShutdownProcess(selector); + })); +#endif // defined(MOZ_WIDGET_ANDROID) + + if (aWhy == AbnormalShutdown) { + GenerateCrashReport(OtherPid()); + + if (PR_GetEnv("MOZ_CRASHREPORTER_SHUTDOWN")) { + printf_stderr("Shutting down due to socket process crash.\n"); + nsCOMPtr<nsIAppStartup> appService = + do_GetService("@mozilla.org/toolkit/app-startup;1"); + if (appService) { + bool userAllowedQuit = true; + appService->Quit(nsIAppStartup::eForceQuit, 1, &userAllowedQuit); + } + } + } + + if (mHost) { + mHost->OnChannelClosed(); + } +} + +bool SocketProcessParent::SendRequestMemoryReport( + const uint32_t& aGeneration, const bool& aAnonymize, + const bool& aMinimizeMemoryUsage, + const Maybe<ipc::FileDescriptor>& aDMDFile) { + mMemoryReportRequest = MakeUnique<dom::MemoryReportRequestHost>(aGeneration); + + PSocketProcessParent::SendRequestMemoryReport( + aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, + [&](const uint32_t& aGeneration2) { + MOZ_ASSERT(gIOService); + if (!gIOService->SocketProcess()) { + return; + } + SocketProcessParent* actor = gIOService->SocketProcess()->GetActor(); + if (!actor) { + return; + } + if (actor->mMemoryReportRequest) { + actor->mMemoryReportRequest->Finish(aGeneration2); + actor->mMemoryReportRequest = nullptr; + } + }, + [&](mozilla::ipc::ResponseRejectReason) { + MOZ_ASSERT(gIOService); + if (!gIOService->SocketProcess()) { + return; + } + SocketProcessParent* actor = gIOService->SocketProcess()->GetActor(); + if (!actor) { + return; + } + actor->mMemoryReportRequest = nullptr; + }); + + return true; +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvAddMemoryReport( + const MemoryReport& aReport) { + if (mMemoryReportRequest) { + mMemoryReportRequest->RecvReport(aReport); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvAccumulateChildHistograms( + nsTArray<HistogramAccumulation>&& aAccumulations) { + TelemetryIPC::AccumulateChildHistograms(Telemetry::ProcessID::Socket, + aAccumulations); + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvAccumulateChildKeyedHistograms( + nsTArray<KeyedHistogramAccumulation>&& aAccumulations) { + TelemetryIPC::AccumulateChildKeyedHistograms(Telemetry::ProcessID::Socket, + aAccumulations); + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvUpdateChildScalars( + nsTArray<ScalarAction>&& aScalarActions) { + TelemetryIPC::UpdateChildScalars(Telemetry::ProcessID::Socket, + aScalarActions); + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvUpdateChildKeyedScalars( + nsTArray<KeyedScalarAction>&& aScalarActions) { + TelemetryIPC::UpdateChildKeyedScalars(Telemetry::ProcessID::Socket, + aScalarActions); + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvRecordChildEvents( + nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) { + TelemetryIPC::RecordChildEvents(Telemetry::ProcessID::Socket, aEvents); + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvRecordDiscardedData( + const mozilla::Telemetry::DiscardedData& aDiscardedData) { + TelemetryIPC::RecordDiscardedData(Telemetry::ProcessID::Socket, + aDiscardedData); + return IPC_OK(); +} + +PWebrtcTCPSocketParent* SocketProcessParent::AllocPWebrtcTCPSocketParent( + const Maybe<TabId>& aTabId) { +#ifdef MOZ_WEBRTC + WebrtcTCPSocketParent* parent = new WebrtcTCPSocketParent(aTabId); + parent->AddRef(); + return parent; +#else + return nullptr; +#endif +} + +bool SocketProcessParent::DeallocPWebrtcTCPSocketParent( + PWebrtcTCPSocketParent* aActor) { +#ifdef MOZ_WEBRTC + WebrtcTCPSocketParent* parent = static_cast<WebrtcTCPSocketParent*>(aActor); + parent->Release(); +#endif + return true; +} + +already_AddRefed<PDNSRequestParent> SocketProcessParent::AllocPDNSRequestParent( + const nsCString& aHost, const nsCString& aTrrServer, const uint16_t& aType, + const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { + RefPtr<DNSRequestHandler> handler = new DNSRequestHandler(); + RefPtr<DNSRequestParent> actor = new DNSRequestParent(handler); + return actor.forget(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvPDNSRequestConstructor( + PDNSRequestParent* aActor, const nsCString& aHost, + const nsCString& aTrrServer, const uint16_t& aType, + const OriginAttributes& aOriginAttributes, const uint32_t& aFlags) { + RefPtr<DNSRequestParent> actor = static_cast<DNSRequestParent*>(aActor); + RefPtr<DNSRequestHandler> handler = + actor->GetDNSRequest()->AsDNSRequestHandler(); + handler->DoAsyncResolve(aHost, aTrrServer, aType, aOriginAttributes, aFlags); + return IPC_OK(); +} + +mozilla::ipc::PFileDescriptorSetParent* +SocketProcessParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD) { + return new mozilla::ipc::FileDescriptorSetParent(aFD); +} + +bool SocketProcessParent::DeallocPFileDescriptorSetParent( + PFileDescriptorSetParent* aActor) { + delete static_cast<mozilla::ipc::FileDescriptorSetParent*>(aActor); + return true; +} + +mozilla::ipc::PChildToParentStreamParent* +SocketProcessParent::AllocPChildToParentStreamParent() { + return mozilla::ipc::AllocPChildToParentStreamParent(); +} + +bool SocketProcessParent::DeallocPChildToParentStreamParent( + PChildToParentStreamParent* aActor) { + delete aActor; + return true; +} + +mozilla::ipc::PParentToChildStreamParent* +SocketProcessParent::AllocPParentToChildStreamParent() { + MOZ_CRASH("PParentToChildStreamChild actors should be manually constructed!"); +} + +bool SocketProcessParent::DeallocPParentToChildStreamParent( + PParentToChildStreamParent* aActor) { + delete aActor; + return true; +} + +mozilla::ipc::PParentToChildStreamParent* +SocketProcessParent::SendPParentToChildStreamConstructor( + PParentToChildStreamParent* aActor) { + MOZ_ASSERT(NS_IsMainThread()); + return PSocketProcessParent::SendPParentToChildStreamConstructor(aActor); +} + +mozilla::ipc::PFileDescriptorSetParent* +SocketProcessParent::SendPFileDescriptorSetConstructor( + const FileDescriptor& aFD) { + MOZ_ASSERT(NS_IsMainThread()); + return PSocketProcessParent::SendPFileDescriptorSetConstructor(aFD); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvObserveHttpActivity( + const HttpActivityArgs& aArgs, const uint32_t& aActivityType, + const uint32_t& aActivitySubtype, const PRTime& aTimestamp, + const uint64_t& aExtraSizeData, const nsCString& aExtraStringData) { + nsCOMPtr<nsIHttpActivityDistributor> activityDistributor = + services::GetHttpActivityDistributor(); + MOZ_ASSERT(activityDistributor); + + Unused << activityDistributor->ObserveActivityWithArgs( + aArgs, aActivityType, aActivitySubtype, aTimestamp, aExtraSizeData, + aExtraStringData); + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvInitBackground( + Endpoint<PBackgroundParent>&& aEndpoint) { + LOG(("SocketProcessParent::RecvInitBackground\n")); + if (!ipc::BackgroundParent::Alloc(nullptr, std::move(aEndpoint))) { + return IPC_FAIL(this, "BackgroundParent::Alloc failed"); + } + + return IPC_OK(); +} + +already_AddRefed<PAltServiceParent> +SocketProcessParent::AllocPAltServiceParent() { + RefPtr<AltServiceParent> actor = new AltServiceParent(); + return actor.forget(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvGetTLSClientCert( + const nsCString& aHostName, const OriginAttributes& aOriginAttributes, + const int32_t& aPort, const uint32_t& aProviderFlags, + const uint32_t& aProviderTlsFlags, const ByteArray& aServerCert, + Maybe<ByteArray>&& aClientCert, nsTArray<ByteArray>&& aCollectedCANames, + bool* aSucceeded, ByteArray* aOutCert, ByteArray* aOutKey, + nsTArray<ByteArray>* aBuiltChain) { + *aSucceeded = false; + + SECItem serverCertItem = { + siBuffer, const_cast<uint8_t*>(aServerCert.data().Elements()), + static_cast<unsigned int>(aServerCert.data().Length())}; + UniqueCERTCertificate serverCert(CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &serverCertItem, nullptr, false, true)); + if (!serverCert) { + return IPC_OK(); + } + + RefPtr<nsIX509Cert> clientCert; + if (aClientCert) { + clientCert = nsNSSCertificate::ConstructFromDER( + BitwiseCast<char*, uint8_t*>(aClientCert->data().Elements()), + aClientCert->data().Length()); + if (!clientCert) { + return IPC_OK(); + } + } + + ClientAuthInfo info(aHostName, aOriginAttributes, aPort, aProviderFlags, + aProviderTlsFlags, clientCert); + nsTArray<nsTArray<uint8_t>> collectedCANames; + for (auto& name : aCollectedCANames) { + collectedCANames.AppendElement(std::move(name.data())); + } + + UniqueCERTCertificate cert; + UniqueSECKEYPrivateKey key; + UniqueCERTCertList builtChain; + SECStatus status = + DoGetClientAuthData(std::move(info), serverCert, + std::move(collectedCANames), cert, key, builtChain); + if (status != SECSuccess) { + return IPC_OK(); + } + + SerializeClientCertAndKey(cert, key, *aOutCert, *aOutKey); + + if (builtChain) { + for (CERTCertListNode* n = CERT_LIST_HEAD(builtChain); + !CERT_LIST_END(n, builtChain); n = CERT_LIST_NEXT(n)) { + ByteArray array; + array.data().AppendElements(n->cert->derCert.data, n->cert->derCert.len); + aBuiltChain->AppendElement(std::move(array)); + } + } + + *aSucceeded = true; + return IPC_OK(); +} + +already_AddRefed<PProxyConfigLookupParent> +SocketProcessParent::AllocPProxyConfigLookupParent( + nsIURI* aURI, const uint32_t& aProxyResolveFlags) { + RefPtr<ProxyConfigLookupParent> actor = + new ProxyConfigLookupParent(aURI, aProxyResolveFlags); + return actor.forget(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvPProxyConfigLookupConstructor( + PProxyConfigLookupParent* aActor, nsIURI* aURI, + const uint32_t& aProxyResolveFlags) { + static_cast<ProxyConfigLookupParent*>(aActor)->DoProxyLookup(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult SocketProcessParent::RecvCachePushCheck( + nsIURI* aPushedURL, OriginAttributes&& aOriginAttributes, + nsCString&& aRequestString, CachePushCheckResolver&& aResolver) { + RefPtr<CachePushChecker> checker = new CachePushChecker( + aPushedURL, aOriginAttributes, aRequestString, aResolver); + if (NS_FAILED(checker->DoCheck())) { + aResolver(false); + } + return IPC_OK(); +} + +// To ensure that IPDL is finished before SocketParent gets deleted. +class DeferredDeleteSocketProcessParent : public Runnable { + public: + explicit DeferredDeleteSocketProcessParent( + UniquePtr<SocketProcessParent>&& aParent) + : Runnable("net::DeferredDeleteSocketProcessParent"), + mParent(std::move(aParent)) {} + + NS_IMETHODIMP Run() override { return NS_OK; } + + private: + UniquePtr<SocketProcessParent> mParent; +}; + +/* static */ +void SocketProcessParent::Destroy(UniquePtr<SocketProcessParent>&& aParent) { + NS_DispatchToMainThread( + new DeferredDeleteSocketProcessParent(std::move(aParent))); +} + +already_AddRefed<PRemoteLazyInputStreamParent> +SocketProcessParent::AllocPRemoteLazyInputStreamParent(const nsID& aID, + const uint64_t& aSize) { + RefPtr<RemoteLazyInputStreamParent> actor = + RemoteLazyInputStreamParent::Create(aID, aSize, this); + return actor.forget(); +} + +mozilla::ipc::IPCResult +SocketProcessParent::RecvPRemoteLazyInputStreamConstructor( + PRemoteLazyInputStreamParent* aActor, const nsID& aID, + const uint64_t& aSize) { + if (!static_cast<RemoteLazyInputStreamParent*>(aActor)->HasValidStream()) { + return IPC_FAIL_NO_REASON(this); + } + + return IPC_OK(); +} + +} // namespace net +} // namespace mozilla |