MessagePort.h (8052B)
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 #ifndef mozilla_dom_MessagePort_h 8 #define mozilla_dom_MessagePort_h 9 10 #include "mozilla/DOMEventTargetHelper.h" 11 #include "mozilla/UniquePtr.h" 12 #include "mozilla/dom/DOMTypes.h" 13 #include "nsTArray.h" 14 15 #ifdef XP_WIN 16 # undef PostMessage 17 #endif 18 19 class nsIGlobalObject; 20 21 namespace mozilla::dom { 22 23 class MessageData; 24 class MessagePortChild; 25 class PostMessageRunnable; 26 class RefMessageBodyService; 27 class SharedMessageBody; 28 class StrongWorkerRef; 29 struct StructuredSerializeOptions; 30 31 // A class to hold a MessagePortIdentifier from 32 // MessagePort::CloneAndDistentangle() and close if neither passed to 33 // MessagePort::Create() nor release()ed to send via IPC. 34 // When the `neutered` field of the MessagePortIdentifier is false, a close is 35 // required. 36 // This does not derive from MessagePortIdentifier because 37 // MessagePortIdentifier is final and because use of UniqueMessagePortId as a 38 // MessagePortIdentifier is intentionally prevented without release of 39 // ownership. 40 class UniqueMessagePortId final { 41 public: 42 UniqueMessagePortId() { mIdentifier.neutered() = true; } 43 explicit UniqueMessagePortId(const MessagePortIdentifier& aIdentifier) 44 : mIdentifier(aIdentifier) {} 45 UniqueMessagePortId(UniqueMessagePortId&& aOther) noexcept 46 : mIdentifier(aOther.mIdentifier) { 47 aOther.mIdentifier.neutered() = true; 48 } 49 ~UniqueMessagePortId() { ForceClose(); }; 50 void ForceClose(); 51 52 [[nodiscard]] MessagePortIdentifier release() { 53 MessagePortIdentifier id = mIdentifier; 54 mIdentifier.neutered() = true; 55 return id; 56 } 57 // const member accessors are not required because a const 58 // UniqueMessagePortId is not useful. 59 nsID& uuid() { return mIdentifier.uuid(); } 60 nsID& destinationUuid() { return mIdentifier.destinationUuid(); } 61 uint32_t& sequenceId() { return mIdentifier.sequenceId(); } 62 bool& neutered() { return mIdentifier.neutered(); } 63 64 UniqueMessagePortId(const UniqueMessagePortId& aOther) = delete; 65 void operator=(const UniqueMessagePortId& aOther) = delete; 66 67 private: 68 MessagePortIdentifier mIdentifier; 69 }; 70 71 class MessagePort final : public DOMEventTargetHelper { 72 friend class PostMessageRunnable; 73 74 public: 75 NS_DECL_ISUPPORTS_INHERITED 76 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, DOMEventTargetHelper) 77 78 static already_AddRefed<MessagePort> Create(nsIGlobalObject* aGlobal, 79 const nsID& aUUID, 80 const nsID& aDestinationUUID, 81 ErrorResult& aRv); 82 83 static already_AddRefed<MessagePort> Create(nsIGlobalObject* aGlobal, 84 UniqueMessagePortId& aIdentifier, 85 ErrorResult& aRv); 86 87 // For IPC. 88 static void ForceClose(const MessagePortIdentifier& aIdentifier); 89 90 virtual JSObject* WrapObject(JSContext* aCx, 91 JS::Handle<JSObject*> aGivenProto) override; 92 93 void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, 94 const Sequence<JSObject*>& aTransferable, ErrorResult& aRv); 95 96 void PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage, 97 const StructuredSerializeOptions& aOptions, 98 ErrorResult& aRv); 99 100 void Start(); 101 102 void Close(); 103 104 EventHandlerNonNull* GetOnmessage(); 105 106 void SetOnmessage(EventHandlerNonNull* aCallback); 107 108 IMPL_EVENT_HANDLER(messageerror) 109 110 // Non WebIDL methods 111 112 void UnshippedEntangle(RefPtr<MessagePort>& aEntangledPort); 113 114 bool CanBeCloned() const { return !mHasBeenTransferredOrClosed; } 115 116 void CloneAndDisentangle(UniqueMessagePortId& aIdentifier); 117 118 void CloseForced(); 119 120 // These methods are useful for MessagePortChild 121 122 void Entangled(nsTArray<MessageData>& aMessages); 123 void MessagesReceived(nsTArray<MessageData>& aMessages); 124 void StopSendingDataConfirmed(); 125 void Closed(); 126 127 private: 128 enum State { 129 // The plan is to be eStateUnshippedEntangled once we are told about our 130 // unshipped entangled counterpart. 131 eStateInitializingUnshippedEntangled, 132 133 // When a port is created by a MessageChannel it is entangled with the 134 // other. They both run on the same thread, same event loop and the 135 // messages are added to the queues without using PBackground actors. 136 // When one of the port is shipped, the state is changed to 137 // StateEntangling. 138 eStateUnshippedEntangled, 139 140 // If the port is closed or cloned when we are in this state, we go in one 141 // of the following 2 steps. EntanglingForClose or ForDisentangle. 142 eStateEntangling, 143 144 // We are not fully entangled yet but are already disentangled. 145 eStateEntanglingForDisentangle, 146 147 // We are not fully entangled yet but are already closed. 148 eStateEntanglingForClose, 149 150 // When entangled() is received we send all the messages in the 151 // mMessagesForTheOtherPort to the actor and we change the state to 152 // StateEntangled. At this point the port is entangled with the other. We 153 // send and receive messages. 154 // If the port queue is not enabled, the received messages are stored in 155 // the mMessages. 156 eStateEntangled, 157 158 // When the port is cloned or disentangled we want to stop receiving 159 // messages. We call 'SendStopSendingData' to the actor and we wait for an 160 // answer. All the messages received between now and the 161 // 'StopSendingDataComfirmed are queued in the mMessages but not 162 // dispatched. 163 eStateDisentangling, 164 165 // When 'StopSendingDataConfirmed' is received, we can disentangle the port 166 // calling SendDisentangle in the actor because we are 100% sure that we 167 // don't receive any other message, so nothing will be lost. 168 // Disentangling the port we send all the messages from the mMessages 169 // though the actor. 170 eStateDisentangled, 171 172 // We are here if Close() has been called. We are disentangled but we can 173 // still send pending messages. 174 eStateDisentangledForClose 175 }; 176 177 explicit MessagePort(nsIGlobalObject* aGlobal, State aState); 178 ~MessagePort(); 179 180 void DisconnectFromOwner() override; 181 182 void Initialize(const nsID& aUUID, const nsID& aDestinationUUID, 183 uint32_t aSequenceID, bool aNeutered, ErrorResult& aRv); 184 185 bool ConnectToPBackground(); 186 187 // Dispatch events from the Message Queue using a nsRunnable. 188 void Dispatch(); 189 190 void DispatchError(); 191 192 void StartDisentangling(); 193 void Disentangle(); 194 195 void RemoveDocFromBFCache(); 196 197 void CloseInternal(bool aSoftly); 198 199 // This method is meant to keep alive the MessagePort when this object is 200 // creating the actor and until the actor is entangled. 201 // We release the object when the port is closed or disentangled. 202 void UpdateMustKeepAlive(); 203 204 bool IsCertainlyAliveForCC() const override { return mIsKeptAlive; } 205 206 RefPtr<StrongWorkerRef> mWorkerRef; 207 208 RefPtr<PostMessageRunnable> mPostMessageRunnable; 209 210 RefPtr<MessagePortChild> mActor; 211 212 RefPtr<MessagePort> mUnshippedEntangledPort; 213 214 RefPtr<RefMessageBodyService> mRefMessageBodyService; 215 216 nsTArray<RefPtr<SharedMessageBody>> mMessages; 217 nsTArray<RefPtr<SharedMessageBody>> mMessagesForTheOtherPort; 218 219 UniquePtr<MessagePortIdentifier> mIdentifier; 220 221 State mState; 222 223 bool mMessageQueueEnabled; 224 225 bool mIsKeptAlive; 226 227 // mHasBeenTransferredOrClosed is used to know if this port has been manually 228 // closed or transferred via postMessage. Note that if the entangled port is 229 // closed, this port is closed as well (see mState) but, just because close() 230 // has not been called directly, by spec, this port can still be transferred. 231 bool mHasBeenTransferredOrClosed; 232 }; 233 234 } // namespace mozilla::dom 235 236 #endif // mozilla_dom_MessagePort_h