MessagePortParent.cpp (5619B)
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 9 #include "MessagePortService.h" 10 #include "mozilla/dom/RefMessageBodyService.h" 11 #include "mozilla/dom/SharedMessageBody.h" 12 13 namespace mozilla::dom { 14 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 23 MessagePortParent::~MessagePortParent() { 24 MOZ_ASSERT(!mService); 25 MOZ_ASSERT(!mEntangled); 26 } 27 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 40 mozilla::ipc::IPCResult MessagePortParent::RecvPostMessages( 41 nsTArray<MessageData>&& aMessages) { 42 if (!mService) { 43 NS_WARNING("PostMessages is called after a shutdown!"); 44 // This implies most probably that CloseAndDelete() has been already called 45 // such that we have no better option than to silently ignore this call. 46 return IPC_OK(); 47 } 48 49 if (!mEntangled) { 50 // If we were shut down, the above condition already bailed out. So this 51 // should actually never happen and returning a failure is fine. 52 return IPC_FAIL(this, "RecvPostMessages not entangled"); 53 } 54 55 // This converts the object in a data struct where we have BlobImpls. 56 FallibleTArray<RefPtr<SharedMessageBody>> messages; 57 if (NS_WARN_IF(!SharedMessageBody::FromMessagesToSharedParent(aMessages, 58 messages))) { 59 // FromMessagesToSharedParent() returns false only if the array allocation 60 // failed. 61 // See bug 1750497 for further discussion if this is the wanted behavior. 62 return IPC_FAIL(this, "SharedMessageBody::FromMessagesToSharedParent"); 63 } 64 65 if (messages.IsEmpty()) { 66 // An empty payload can be safely ignored. 67 return IPC_OK(); 68 } 69 70 if (!mService->PostMessages(this, std::move(messages))) { 71 // TODO: Verify if all failure conditions of PostMessages() merit an 72 // IPC_FAIL. See bug 1750499. 73 return IPC_FAIL(this, "RecvPostMessages->PostMessages"); 74 } 75 return IPC_OK(); 76 } 77 78 mozilla::ipc::IPCResult MessagePortParent::RecvDisentangle( 79 nsTArray<MessageData>&& aMessages) { 80 if (!mService) { 81 NS_WARNING("Entangle is called after a shutdown!"); 82 // This implies most probably that CloseAndDelete() has been already called 83 // such that we can silently ignore this call. 84 return IPC_OK(); 85 } 86 87 if (!mEntangled) { 88 // If we were shut down, the above condition already bailed out. So this 89 // should actually never happen and returning a failure is fine. 90 return IPC_FAIL(this, "RecvDisentangle not entangled"); 91 } 92 93 // This converts the object in a data struct where we have BlobImpls. 94 FallibleTArray<RefPtr<SharedMessageBody>> messages; 95 if (NS_WARN_IF(!SharedMessageBody::FromMessagesToSharedParent(aMessages, 96 messages))) { 97 // TODO: Verify if failed allocations merit an IPC_FAIL. See bug 1750497. 98 return IPC_FAIL(this, "SharedMessageBody::FromMessagesToSharedParent"); 99 } 100 101 if (!mService->DisentanglePort(this, std::move(messages))) { 102 // TODO: Verify if all failure conditions of DisentanglePort() merit an 103 // IPC_FAIL. See bug 1750501. 104 return IPC_FAIL(this, "RecvDisentangle->DisentanglePort"); 105 } 106 107 CloseAndDelete(); 108 return IPC_OK(); 109 } 110 111 mozilla::ipc::IPCResult MessagePortParent::RecvStopSendingData() { 112 if (!mEntangled) { 113 return IPC_OK(); 114 } 115 116 mCanSendData = false; 117 (void)SendStopSendingDataConfirmed(); 118 return IPC_OK(); 119 } 120 121 mozilla::ipc::IPCResult MessagePortParent::RecvClose() { 122 if (mService) { 123 MOZ_ASSERT(mEntangled); 124 125 if (!mService->ClosePort(this)) { 126 return IPC_FAIL(this, "RecvClose->ClosePort"); 127 } 128 129 Close(); 130 } 131 132 MOZ_ASSERT(!mEntangled); 133 134 (void)Send__delete__(this); 135 return IPC_OK(); 136 } 137 138 void MessagePortParent::ActorDestroy(ActorDestroyReason aWhy) { 139 if (mService && mEntangled) { 140 // When the last parent is deleted, this service is freed but this cannot 141 // be done when the hashtables are written by CloseAll. 142 RefPtr<MessagePortService> kungFuDeathGrip = mService; 143 kungFuDeathGrip->ParentDestroy(this); 144 } 145 } 146 147 bool MessagePortParent::Entangled(nsTArray<MessageData>&& aMessages) { 148 MOZ_ASSERT(!mEntangled); 149 mEntangled = true; 150 return SendEntangled(aMessages); 151 } 152 153 void MessagePortParent::CloseAndDelete() { 154 Close(); 155 (void)Send__delete__(this); 156 } 157 158 void MessagePortParent::Close() { 159 mService = nullptr; 160 mEntangled = false; 161 } 162 163 /* static */ 164 bool MessagePortParent::ForceClose(const nsID& aUUID, 165 const nsID& aDestinationUUID, 166 const uint32_t& aSequenceID) { 167 MessagePortService* service = MessagePortService::Get(); 168 if (!service) { 169 NS_WARNING( 170 "The service must exist if we want to close an existing MessagePort."); 171 // There is nothing to close so we are ok. 172 return true; 173 } 174 175 return service->ForceClose(aUUID, aDestinationUUID, aSequenceID); 176 } 177 178 } // namespace mozilla::dom