1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 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/. */
7 #include "mozilla/ipc/Endpoint.h"
8 #include "chrome/common/ipc_message.h"
9 #include "mozilla/ipc/IPDLParamTraits.h"
10 #include "nsThreadUtils.h"
11 #include "mozilla/ipc/ProtocolMessageUtils.h"
13 namespace mozilla::ipc
{
15 UntypedManagedEndpoint::UntypedManagedEndpoint(IProtocol
* aActor
)
17 /* mOtherSide */ aActor
->GetWeakLifecycleProxy(),
18 /* mToplevel */ nullptr,
20 aActor
->GetProtocolId(),
21 aActor
->Manager()->Id(),
22 aActor
->Manager()->GetProtocolId(),
25 UntypedManagedEndpoint::~UntypedManagedEndpoint() {
30 if (mInner
->mOtherSide
) {
31 // If this ManagedEndpoint was never sent over IPC, deliver a fake
32 // MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE message directly to the other side
34 mInner
->mOtherSide
->ActorEventTarget()->Dispatch(NS_NewRunnableFunction(
35 "~ManagedEndpoint (Local)",
36 [otherSide
= mInner
->mOtherSide
, id
= mInner
->mId
] {
37 if (IProtocol
* actor
= otherSide
->Get(); actor
&& actor
->CanRecv()) {
38 MOZ_DIAGNOSTIC_ASSERT(actor
->Id() == id
, "Wrong Actor?");
39 RefPtr
<ActorLifecycleProxy
> strongProxy(actor
->GetLifecycleProxy());
40 strongProxy
->Get()->OnMessageReceived(
41 IPC::Message(id
, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE
));
44 } else if (mInner
->mToplevel
) {
45 // If it was sent over IPC, we'll need to send the message to the sending
46 // side. Let's send the message async.
47 mInner
->mToplevel
->ActorEventTarget()->Dispatch(NS_NewRunnableFunction(
48 "~ManagedEndpoint (Remote)",
49 [toplevel
= mInner
->mToplevel
, id
= mInner
->mId
] {
50 if (IProtocol
* actor
= toplevel
->Get();
51 actor
&& actor
->CanSend() && actor
->GetIPCChannel()) {
52 actor
->GetIPCChannel()->Send(MakeUnique
<IPC::Message
>(
53 id
, MANAGED_ENDPOINT_DROPPED_MESSAGE_TYPE
));
59 bool UntypedManagedEndpoint::BindCommon(IProtocol
* aActor
,
60 IProtocol
* aManager
) {
63 NS_WARNING("Cannot bind to invalid endpoint");
67 // Perform thread assertions.
68 if (mInner
->mToplevel
) {
69 MOZ_DIAGNOSTIC_ASSERT(
70 mInner
->mToplevel
->ActorEventTarget()->IsOnCurrentThread());
71 MOZ_DIAGNOSTIC_ASSERT(aManager
->ToplevelProtocol() ==
72 mInner
->mToplevel
->Get());
75 if (NS_WARN_IF(aManager
->Id() != mInner
->mManagerId
) ||
76 NS_WARN_IF(aManager
->GetProtocolId() != mInner
->mManagerType
) ||
77 NS_WARN_IF(aActor
->GetProtocolId() != mInner
->mType
)) {
78 MOZ_ASSERT_UNREACHABLE("Actor and manager do not match Endpoint");
82 if (!aManager
->CanSend() || !aManager
->GetIPCChannel()) {
83 NS_WARNING("Manager cannot send");
87 int32_t id
= mInner
->mId
;
90 // Our typed caller will insert the actor into the managed container.
91 aActor
->SetManagerAndRegister(aManager
, id
);
93 aManager
->GetIPCChannel()->Send(
94 MakeUnique
<IPC::Message
>(id
, MANAGED_ENDPOINT_BOUND_MESSAGE_TYPE
));
99 void IPDLParamTraits
<UntypedManagedEndpoint
>::Write(IPC::MessageWriter
* aWriter
,
101 paramType
&& aParam
) {
102 bool isValid
= aParam
.mInner
.isSome();
103 WriteIPDLParam(aWriter
, aActor
, isValid
);
108 auto inner
= std::move(*aParam
.mInner
);
109 aParam
.mInner
.reset();
111 MOZ_RELEASE_ASSERT(inner
.mOtherSide
, "Has not been sent over IPC yet");
112 MOZ_RELEASE_ASSERT(inner
.mOtherSide
->ActorEventTarget()->IsOnCurrentThread(),
113 "Must be being sent from the correct thread");
115 inner
.mOtherSide
->Get() && inner
.mOtherSide
->Get()->ToplevelProtocol() ==
116 aActor
->ToplevelProtocol(),
117 "Must be being sent over the same toplevel protocol");
119 WriteIPDLParam(aWriter
, aActor
, inner
.mId
);
120 WriteIPDLParam(aWriter
, aActor
, inner
.mType
);
121 WriteIPDLParam(aWriter
, aActor
, inner
.mManagerId
);
122 WriteIPDLParam(aWriter
, aActor
, inner
.mManagerType
);
126 bool IPDLParamTraits
<UntypedManagedEndpoint
>::Read(IPC::MessageReader
* aReader
,
128 paramType
* aResult
) {
129 *aResult
= UntypedManagedEndpoint
{};
130 bool isValid
= false;
131 if (!aActor
|| !ReadIPDLParam(aReader
, aActor
, &isValid
)) {
138 aResult
->mInner
.emplace();
139 auto& inner
= *aResult
->mInner
;
140 inner
.mToplevel
= aActor
->ToplevelProtocol()->GetWeakLifecycleProxy();
141 return ReadIPDLParam(aReader
, aActor
, &inner
.mId
) &&
142 ReadIPDLParam(aReader
, aActor
, &inner
.mType
) &&
143 ReadIPDLParam(aReader
, aActor
, &inner
.mManagerId
) &&
144 ReadIPDLParam(aReader
, aActor
, &inner
.mManagerType
);
147 } // namespace mozilla::ipc
151 void ParamTraits
<mozilla::ipc::UntypedEndpoint
>::Write(MessageWriter
* aWriter
,
152 paramType
&& aParam
) {
153 IPC::WriteParam(aWriter
, std::move(aParam
.mPort
));
154 IPC::WriteParam(aWriter
, aParam
.mMessageChannelId
);
155 IPC::WriteParam(aWriter
, aParam
.mMyPid
);
156 IPC::WriteParam(aWriter
, aParam
.mOtherPid
);
159 bool ParamTraits
<mozilla::ipc::UntypedEndpoint
>::Read(MessageReader
* aReader
,
160 paramType
* aResult
) {
161 return IPC::ReadParam(aReader
, &aResult
->mPort
) &&
162 IPC::ReadParam(aReader
, &aResult
->mMessageChannelId
) &&
163 IPC::ReadParam(aReader
, &aResult
->mMyPid
) &&
164 IPC::ReadParam(aReader
, &aResult
->mOtherPid
);