summaryrefslogtreecommitdiffstats
path: root/netwerk/ipc/SocketProcessBridgeChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--netwerk/ipc/SocketProcessBridgeChild.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/netwerk/ipc/SocketProcessBridgeChild.cpp b/netwerk/ipc/SocketProcessBridgeChild.cpp
new file mode 100644
index 0000000000..4fb5a0990c
--- /dev/null
+++ b/netwerk/ipc/SocketProcessBridgeChild.cpp
@@ -0,0 +1,196 @@
+/* -*- 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 "SocketProcessBridgeChild.h"
+#include "SocketProcessLogging.h"
+
+#include "mozilla/AppShutdown.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/ipc/BackgroundChild.h"
+#include "mozilla/ipc/Endpoint.h"
+#include "mozilla/net/NeckoChild.h"
+#include "nsIObserverService.h"
+#include "nsThreadUtils.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/StaticPrefs_network.h"
+
+namespace mozilla {
+
+using dom::ContentChild;
+
+namespace net {
+
+StaticRefPtr<SocketProcessBridgeChild>
+ SocketProcessBridgeChild::sSocketProcessBridgeChild;
+
+NS_IMPL_ISUPPORTS(SocketProcessBridgeChild, nsIObserver)
+
+// static
+bool SocketProcessBridgeChild::Create(
+ Endpoint<PSocketProcessBridgeChild>&& aEndpoint) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ sSocketProcessBridgeChild =
+ new SocketProcessBridgeChild(std::move(aEndpoint));
+ if (sSocketProcessBridgeChild->Inited()) {
+ mozilla::ipc::BackgroundChild::InitSocketBridgeStarter(
+ sSocketProcessBridgeChild);
+ return true;
+ }
+
+ sSocketProcessBridgeChild = nullptr;
+ return false;
+}
+
+// static
+already_AddRefed<SocketProcessBridgeChild>
+SocketProcessBridgeChild::GetSingleton() {
+ RefPtr<SocketProcessBridgeChild> child = sSocketProcessBridgeChild;
+ return child.forget();
+}
+
+// static
+RefPtr<SocketProcessBridgeChild::GetPromise>
+SocketProcessBridgeChild::GetSocketProcessBridge() {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!StaticPrefs::network_process_enabled()) {
+ return GetPromise::CreateAndReject(nsCString("Socket process disabled!"),
+ __func__);
+ }
+
+ if (!gNeckoChild) {
+ return GetPromise::CreateAndReject(nsCString("No NeckoChild!"), __func__);
+ }
+
+ // ContentChild is shutting down, we should not try to create
+ // SocketProcessBridgeChild.
+ ContentChild* content = ContentChild::GetSingleton();
+ if (!content || content->IsShuttingDown()) {
+ return GetPromise::CreateAndReject(
+ nsCString("ContentChild is shutting down."), __func__);
+ }
+
+ if (sSocketProcessBridgeChild) {
+ return GetPromise::CreateAndResolve(sSocketProcessBridgeChild, __func__);
+ }
+
+ return gNeckoChild->SendInitSocketProcessBridge()->Then(
+ GetMainThreadSerialEventTarget(), __func__,
+ [](NeckoChild::InitSocketProcessBridgePromise::ResolveOrRejectValue&&
+ aResult) {
+ ContentChild* content = ContentChild::GetSingleton();
+ if (!content || content->IsShuttingDown()) {
+ return GetPromise::CreateAndReject(
+ nsCString("ContentChild is shutting down."), __func__);
+ }
+ if (!sSocketProcessBridgeChild) {
+ if (aResult.IsReject()) {
+ return GetPromise::CreateAndReject(
+ nsCString("SendInitSocketProcessBridge failed"), __func__);
+ }
+
+ if (!aResult.ResolveValue().IsValid()) {
+ return GetPromise::CreateAndReject(
+ nsCString(
+ "SendInitSocketProcessBridge resolved with an invalid "
+ "endpoint!"),
+ __func__);
+ }
+
+ if (!SocketProcessBridgeChild::Create(
+ std::move(aResult.ResolveValue()))) {
+ return GetPromise::CreateAndReject(
+ nsCString("SendInitSocketProcessBridge resolved with a valid "
+ "endpoint, "
+ "but SocketProcessBridgeChild::Create failed!"),
+ __func__);
+ }
+ }
+
+ return GetPromise::CreateAndResolve(sSocketProcessBridgeChild,
+ __func__);
+ });
+}
+
+SocketProcessBridgeChild::SocketProcessBridgeChild(
+ Endpoint<PSocketProcessBridgeChild>&& aEndpoint)
+ : mShuttingDown(false) {
+ LOG(("CONSTRUCT SocketProcessBridgeChild::SocketProcessBridgeChild\n"));
+
+ mInited = aEndpoint.Bind(this);
+ if (!mInited) {
+ MOZ_ASSERT(false, "Bind failed!");
+ return;
+ }
+
+ nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+ if (os) {
+ os->AddObserver(this, "content-child-shutdown", false);
+ }
+
+ mSocketProcessPid = aEndpoint.OtherPid();
+}
+
+SocketProcessBridgeChild::~SocketProcessBridgeChild() {
+ LOG(("DESTRUCT SocketProcessBridgeChild::SocketProcessBridgeChild\n"));
+}
+
+mozilla::ipc::IPCResult SocketProcessBridgeChild::RecvTest() {
+ LOG(("SocketProcessBridgeChild::RecvTest\n"));
+ return IPC_OK();
+}
+
+void SocketProcessBridgeChild::ActorDestroy(ActorDestroyReason aWhy) {
+ LOG(("SocketProcessBridgeChild::ActorDestroy\n"));
+ if (AbnormalShutdown == aWhy) {
+ if (gNeckoChild &&
+ !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
+ // Let NeckoParent know that the socket process connections must be
+ // rebuilt.
+ gNeckoChild->SendResetSocketProcessBridge();
+ }
+
+ nsresult res;
+ nsCOMPtr<nsISerialEventTarget> mSTSThread =
+ do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res);
+ if (NS_SUCCEEDED(res) && mSTSThread) {
+ // This must be called off the main thread. If we don't make this call
+ // ipc::BackgroundChild::GetOrCreateSocketActorForCurrentThread() will
+ // return the previous actor that is no longer able to send. This causes
+ // rebuilding the socket process connections to fail.
+ MOZ_ALWAYS_SUCCEEDS(mSTSThread->Dispatch(NS_NewRunnableFunction(
+ "net::SocketProcessBridgeChild::ActorDestroy",
+ []() { ipc::BackgroundChild::CloseForCurrentThread(); })));
+ }
+ }
+
+ nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+ if (os) {
+ os->RemoveObserver(this, "content-child-shutdown");
+ }
+ GetCurrentSerialEventTarget()->Dispatch(
+ NewRunnableMethod("net::SocketProcessBridgeChild::DeferredDestroy", this,
+ &SocketProcessBridgeChild::DeferredDestroy));
+ mShuttingDown = true;
+}
+
+NS_IMETHODIMP
+SocketProcessBridgeChild::Observe(nsISupports* aSubject, const char* aTopic,
+ const char16_t* aData) {
+ if (!strcmp(aTopic, "content-child-shutdown")) {
+ PSocketProcessBridgeChild::Close();
+ }
+ return NS_OK;
+}
+
+void SocketProcessBridgeChild::DeferredDestroy() {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ sSocketProcessBridgeChild = nullptr;
+}
+
+} // namespace net
+} // namespace mozilla