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/. */
6
7 #include "MessagePortParent.h"
8 #include "MessagePortService.h"
9 #include "SharedMessagePortMessage.h"
10 #include "mozilla/Unused.h"
11
12 namespace mozilla {
13 namespace dom {
14
MessagePortParent(const nsID & aUUID)15 MessagePortParent::MessagePortParent(const nsID& aUUID)
16 : mService(MessagePortService::GetOrCreate()),
17 mUUID(aUUID),
18 mEntangled(false),
19 mCanSendData(true) {
20 MOZ_ASSERT(mService);
21 }
22
~MessagePortParent()23 MessagePortParent::~MessagePortParent() {
24 MOZ_ASSERT(!mService);
25 MOZ_ASSERT(!mEntangled);
26 }
27
Entangle(const nsID & aDestinationUUID,const uint32_t & aSequenceID)28 bool MessagePortParent::Entangle(const nsID& aDestinationUUID,
29 const uint32_t& aSequenceID) {
30 if (!mService) {
31 NS_WARNING("Entangle is called after a shutdown!");
32 return false;
33 }
34
35 MOZ_ASSERT(!mEntangled);
36
37 return mService->RequestEntangling(this, aDestinationUUID, aSequenceID);
38 }
39
RecvPostMessages(nsTArray<ClonedMessageData> && aMessages)40 mozilla::ipc::IPCResult MessagePortParent::RecvPostMessages(
41 nsTArray<ClonedMessageData>&& aMessages) {
42 // This converts the object in a data struct where we have BlobImpls.
43 FallibleTArray<RefPtr<SharedMessagePortMessage>> messages;
44 if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedParent(
45 aMessages, messages))) {
46 return IPC_FAIL_NO_REASON(this);
47 }
48
49 if (!mEntangled) {
50 return IPC_FAIL_NO_REASON(this);
51 }
52
53 if (!mService) {
54 NS_WARNING("Entangle is called after a shutdown!");
55 return IPC_FAIL_NO_REASON(this);
56 }
57
58 if (messages.IsEmpty()) {
59 return IPC_FAIL_NO_REASON(this);
60 }
61
62 if (!mService->PostMessages(this, messages)) {
63 return IPC_FAIL_NO_REASON(this);
64 }
65 return IPC_OK();
66 }
67
RecvDisentangle(nsTArray<ClonedMessageData> && aMessages)68 mozilla::ipc::IPCResult MessagePortParent::RecvDisentangle(
69 nsTArray<ClonedMessageData>&& aMessages) {
70 // This converts the object in a data struct where we have BlobImpls.
71 FallibleTArray<RefPtr<SharedMessagePortMessage>> messages;
72 if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedParent(
73 aMessages, messages))) {
74 return IPC_FAIL_NO_REASON(this);
75 }
76
77 if (!mEntangled) {
78 return IPC_FAIL_NO_REASON(this);
79 }
80
81 if (!mService) {
82 NS_WARNING("Entangle is called after a shutdown!");
83 return IPC_FAIL_NO_REASON(this);
84 }
85
86 if (!mService->DisentanglePort(this, messages)) {
87 return IPC_FAIL_NO_REASON(this);
88 }
89
90 CloseAndDelete();
91 return IPC_OK();
92 }
93
RecvStopSendingData()94 mozilla::ipc::IPCResult MessagePortParent::RecvStopSendingData() {
95 if (!mEntangled) {
96 return IPC_OK();
97 }
98
99 mCanSendData = false;
100 Unused << SendStopSendingDataConfirmed();
101 return IPC_OK();
102 }
103
RecvClose()104 mozilla::ipc::IPCResult MessagePortParent::RecvClose() {
105 if (mService) {
106 MOZ_ASSERT(mEntangled);
107
108 if (!mService->ClosePort(this)) {
109 return IPC_FAIL_NO_REASON(this);
110 }
111
112 Close();
113 }
114
115 MOZ_ASSERT(!mEntangled);
116
117 Unused << Send__delete__(this);
118 return IPC_OK();
119 }
120
ActorDestroy(ActorDestroyReason aWhy)121 void MessagePortParent::ActorDestroy(ActorDestroyReason aWhy) {
122 if (mService && mEntangled) {
123 // When the last parent is deleted, this service is freed but this cannot
124 // be done when the hashtables are written by CloseAll.
125 RefPtr<MessagePortService> kungFuDeathGrip = mService;
126 kungFuDeathGrip->ParentDestroy(this);
127 }
128 }
129
Entangled(const nsTArray<ClonedMessageData> & aMessages)130 bool MessagePortParent::Entangled(
131 const nsTArray<ClonedMessageData>& aMessages) {
132 MOZ_ASSERT(!mEntangled);
133 mEntangled = true;
134 return SendEntangled(aMessages);
135 }
136
CloseAndDelete()137 void MessagePortParent::CloseAndDelete() {
138 Close();
139 Unused << Send__delete__(this);
140 }
141
Close()142 void MessagePortParent::Close() {
143 mService = nullptr;
144 mEntangled = false;
145 }
146
ForceClose(const nsID & aUUID,const nsID & aDestinationUUID,const uint32_t & aSequenceID)147 /* static */ bool MessagePortParent::ForceClose(const nsID& aUUID,
148 const nsID& aDestinationUUID,
149 const uint32_t& aSequenceID) {
150 MessagePortService* service = MessagePortService::Get();
151 if (!service) {
152 NS_WARNING(
153 "The service must exist if we want to close an existing MessagePort.");
154 return false;
155 }
156
157 return service->ForceClose(aUUID, aDestinationUUID, aSequenceID);
158 }
159
160 } // namespace dom
161 } // namespace mozilla
162