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