summaryrefslogtreecommitdiffstats
path: root/ipc/glue/Endpoint.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/glue/Endpoint.cpp')
-rw-r--r--ipc/glue/Endpoint.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/ipc/glue/Endpoint.cpp b/ipc/glue/Endpoint.cpp
new file mode 100644
index 0000000000..3391f8b359
--- /dev/null
+++ b/ipc/glue/Endpoint.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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/. */
+
+#include "mozilla/ipc/Endpoint.h"
+#include "chrome/common/ipc_message.h"
+#include "mozilla/ipc/IPDLParamTraits.h"
+#include "nsThreadUtils.h"
+#include "mozilla/ipc/ProtocolMessageUtils.h"
+
+namespace mozilla::ipc {
+
+UntypedManagedEndpoint::UntypedManagedEndpoint(IProtocol* aActor)
+ : mInner(Some(Inner{
+ /* mOtherSide */ aActor->GetWeakLifecycleProxy(),
+ /* mToplevel */ nullptr,
+ aActor->Id(),
+ aActor->GetProtocolId(),
+ aActor->Manager()->Id(),
+ aActor->Manager()->GetProtocolId(),
+ })) {}
+
+UntypedManagedEndpoint::~UntypedManagedEndpoint() {
+ if (!IsValid()) {
+ return;
+ }
+
+ if (mInner->mOtherSide) {
+ // If this ManagedEndpoint was never sent over IPC, deliver a fake
+ // MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE message directly to the other side
+ // actor.
+ mInner->mOtherSide->ActorEventTarget()->Dispatch(NS_NewRunnableFunction(
+ "~ManagedEndpoint (Local)",
+ [otherSide = mInner->mOtherSide, id = mInner->mId] {
+ if (IProtocol* actor = otherSide->Get(); actor && actor->CanRecv()) {
+ MOZ_DIAGNOSTIC_ASSERT(actor->Id() == id, "Wrong Actor?");
+ RefPtr<ActorLifecycleProxy> strongProxy(actor->GetLifecycleProxy());
+ strongProxy->Get()->OnMessageReceived(
+ IPC::Message(id, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE));
+ }
+ }));
+ } else if (mInner->mToplevel) {
+ // If it was sent over IPC, we'll need to send the message to the sending
+ // side. Let's send the message async.
+ mInner->mToplevel->ActorEventTarget()->Dispatch(NS_NewRunnableFunction(
+ "~ManagedEndpoint (Remote)",
+ [toplevel = mInner->mToplevel, id = mInner->mId] {
+ if (IProtocol* actor = toplevel->Get();
+ actor && actor->CanSend() && actor->GetIPCChannel()) {
+ actor->GetIPCChannel()->Send(MakeUnique<IPC::Message>(
+ id, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE));
+ }
+ }));
+ }
+}
+
+bool UntypedManagedEndpoint::BindCommon(IProtocol* aActor,
+ IProtocol* aManager) {
+ MOZ_ASSERT(aManager);
+ if (!mInner) {
+ NS_WARNING("Cannot bind to invalid endpoint");
+ return false;
+ }
+
+ // Perform thread assertions.
+ if (mInner->mToplevel) {
+ MOZ_DIAGNOSTIC_ASSERT(
+ mInner->mToplevel->ActorEventTarget()->IsOnCurrentThread());
+ MOZ_DIAGNOSTIC_ASSERT(aManager->ToplevelProtocol() ==
+ mInner->mToplevel->Get());
+ }
+
+ if (NS_WARN_IF(aManager->Id() != mInner->mManagerId) ||
+ NS_WARN_IF(aManager->GetProtocolId() != mInner->mManagerType) ||
+ NS_WARN_IF(aActor->GetProtocolId() != mInner->mType)) {
+ MOZ_ASSERT_UNREACHABLE("Actor and manager do not match Endpoint");
+ return false;
+ }
+
+ if (!aManager->CanSend() || !aManager->GetIPCChannel()) {
+ NS_WARNING("Manager cannot send");
+ return false;
+ }
+
+ int32_t id = mInner->mId;
+ mInner.reset();
+
+ // Our typed caller will insert the actor into the managed container.
+ aActor->SetManagerAndRegister(aManager, id);
+
+ aManager->GetIPCChannel()->Send(
+ MakeUnique<IPC::Message>(id, MANAGED_ENDPOINT_BOUND_MESSAGE_TYPE));
+ return true;
+}
+
+/* static */
+void IPDLParamTraits<UntypedManagedEndpoint>::Write(IPC::MessageWriter* aWriter,
+ IProtocol* aActor,
+ paramType&& aParam) {
+ bool isValid = aParam.mInner.isSome();
+ WriteIPDLParam(aWriter, aActor, isValid);
+ if (!isValid) {
+ return;
+ }
+
+ auto inner = std::move(*aParam.mInner);
+ aParam.mInner.reset();
+
+ MOZ_RELEASE_ASSERT(inner.mOtherSide, "Has not been sent over IPC yet");
+ MOZ_RELEASE_ASSERT(inner.mOtherSide->ActorEventTarget()->IsOnCurrentThread(),
+ "Must be being sent from the correct thread");
+ MOZ_RELEASE_ASSERT(
+ inner.mOtherSide->Get() && inner.mOtherSide->Get()->ToplevelProtocol() ==
+ aActor->ToplevelProtocol(),
+ "Must be being sent over the same toplevel protocol");
+
+ WriteIPDLParam(aWriter, aActor, inner.mId);
+ WriteIPDLParam(aWriter, aActor, inner.mType);
+ WriteIPDLParam(aWriter, aActor, inner.mManagerId);
+ WriteIPDLParam(aWriter, aActor, inner.mManagerType);
+}
+
+/* static */
+bool IPDLParamTraits<UntypedManagedEndpoint>::Read(IPC::MessageReader* aReader,
+ IProtocol* aActor,
+ paramType* aResult) {
+ *aResult = UntypedManagedEndpoint{};
+ bool isValid = false;
+ if (!aActor || !ReadIPDLParam(aReader, aActor, &isValid)) {
+ return false;
+ }
+ if (!isValid) {
+ return true;
+ }
+
+ aResult->mInner.emplace();
+ auto& inner = *aResult->mInner;
+ inner.mToplevel = aActor->ToplevelProtocol()->GetWeakLifecycleProxy();
+ return ReadIPDLParam(aReader, aActor, &inner.mId) &&
+ ReadIPDLParam(aReader, aActor, &inner.mType) &&
+ ReadIPDLParam(aReader, aActor, &inner.mManagerId) &&
+ ReadIPDLParam(aReader, aActor, &inner.mManagerType);
+}
+
+} // namespace mozilla::ipc
+
+namespace IPC {
+
+void ParamTraits<mozilla::ipc::UntypedEndpoint>::Write(MessageWriter* aWriter,
+ paramType&& aParam) {
+ IPC::WriteParam(aWriter, std::move(aParam.mPort));
+ IPC::WriteParam(aWriter, aParam.mMessageChannelId);
+ IPC::WriteParam(aWriter, aParam.mMyPid);
+ IPC::WriteParam(aWriter, aParam.mOtherPid);
+}
+
+bool ParamTraits<mozilla::ipc::UntypedEndpoint>::Read(MessageReader* aReader,
+ paramType* aResult) {
+ return IPC::ReadParam(aReader, &aResult->mPort) &&
+ IPC::ReadParam(aReader, &aResult->mMessageChannelId) &&
+ IPC::ReadParam(aReader, &aResult->mMyPid) &&
+ IPC::ReadParam(aReader, &aResult->mOtherPid);
+}
+
+} // namespace IPC