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