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 "nsAutoPtr.h"
13 #include "nsIIPCBackgroundChildCreateCallback.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 MessagePortChild;
26 class MessagePortIdentifier;
27 class MessagePortMessage;
28 class PostMessageRunnable;
29 class SharedMessagePortMessage;
30 
31 namespace workers {
32 class WorkerHolder;
33 } // namespace workers
34 
35 class MessagePort final : public DOMEventTargetHelper
36                         , public nsIIPCBackgroundChildCreateCallback
37                         , public nsIObserver
38 {
39   friend class PostMessageRunnable;
40 
41 public:
42   NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
43   NS_DECL_NSIOBSERVER
44   NS_DECL_ISUPPORTS_INHERITED
45   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
46                                            DOMEventTargetHelper)
47 
48   static already_AddRefed<MessagePort>
49   Create(nsIGlobalObject* aGlobal, const nsID& aUUID,
50          const nsID& aDestinationUUID, ErrorResult& aRv);
51 
52   static already_AddRefed<MessagePort>
53   Create(nsIGlobalObject* aGlobal,
54          const MessagePortIdentifier& aIdentifier,
55          ErrorResult& aRv);
56 
57   // For IPC.
58   static void
59   ForceClose(const MessagePortIdentifier& aIdentifier);
60 
61   virtual JSObject*
62   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
63 
64   void
65   PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
66               const Optional<Sequence<JS::Value>>& aTransferable,
67               ErrorResult& aRv);
68 
69   void Start();
70 
71   void Close();
72 
73   EventHandlerNonNull* GetOnmessage();
74 
75   void SetOnmessage(EventHandlerNonNull* aCallback);
76 
77   // Non WebIDL methods
78 
79   void UnshippedEntangle(MessagePort* aEntangledPort);
80 
81   void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
82 
83   void CloseForced();
84 
85   // These methods are useful for MessagePortChild
86 
87   void Entangled(nsTArray<MessagePortMessage>& aMessages);
88   void MessagesReceived(nsTArray<MessagePortMessage>& aMessages);
89   void StopSendingDataConfirmed();
90   void Closed();
91 
92 private:
93   explicit MessagePort(nsIGlobalObject* aGlobal);
94   ~MessagePort();
95 
96   enum State {
97     // When a port is created by a MessageChannel it is entangled with the
98     // other. They both run on the same thread, same event loop and the
99     // messages are added to the queues without using PBackground actors.
100     // When one of the port is shipped, the state is changed to
101     // StateEntangling.
102     eStateUnshippedEntangled,
103 
104     // If the port is closed or cloned when we are in this state, we go in one
105     // of the following 2 steps. EntanglingForClose or ForDisentangle.
106     eStateEntangling,
107 
108     // We are not fully entangled yet but are already disentangled.
109     eStateEntanglingForDisentangle,
110 
111     // We are not fully entangled yet but are already closed.
112     eStateEntanglingForClose,
113 
114     // When entangled() is received we send all the messages in the
115     // mMessagesForTheOtherPort to the actor and we change the state to
116     // StateEntangled. At this point the port is entangled with the other. We
117     // send and receive messages.
118     // If the port queue is not enabled, the received messages are stored in
119     // the mMessages.
120     eStateEntangled,
121 
122     // When the port is cloned or disentangled we want to stop receiving
123     // messages. We call 'SendStopSendingData' to the actor and we wait for an
124     // answer. All the messages received between now and the
125     // 'StopSendingDataComfirmed are queued in the mMessages but not
126     // dispatched.
127     eStateDisentangling,
128 
129     // When 'StopSendingDataConfirmed' is received, we can disentangle the port
130     // calling SendDisentangle in the actor because we are 100% sure that we
131     // don't receive any other message, so nothing will be lost.
132     // Disentangling the port we send all the messages from the mMessages
133     // though the actor.
134     eStateDisentangled,
135 
136     // We are here if Close() has been called. We are disentangled but we can
137     // still send pending messages.
138     eStateDisentangledForClose
139   };
140 
141   void Initialize(const nsID& aUUID, const nsID& aDestinationUUID,
142                   uint32_t aSequenceID, bool mNeutered, State aState,
143                   ErrorResult& aRv);
144 
145   void ConnectToPBackground();
146 
147   // Dispatch events from the Message Queue using a nsRunnable.
148   void Dispatch();
149 
150   void StartDisentangling();
151   void Disentangle();
152 
153   void RemoveDocFromBFCache();
154 
155   void CloseInternal(bool aSoftly);
156 
157   // This method is meant to keep alive the MessagePort when this object is
158   // creating the actor and until the actor is entangled.
159   // We release the object when the port is closed or disentangled.
160   void UpdateMustKeepAlive();
161 
IsCertainlyAliveForCC()162   bool IsCertainlyAliveForCC() const override
163   {
164     return mIsKeptAlive;
165   }
166 
167   nsAutoPtr<workers::WorkerHolder> mWorkerHolder;
168 
169   RefPtr<PostMessageRunnable> mPostMessageRunnable;
170 
171   RefPtr<MessagePortChild> mActor;
172 
173   RefPtr<MessagePort> mUnshippedEntangledPort;
174 
175   nsTArray<RefPtr<SharedMessagePortMessage>> mMessages;
176   nsTArray<RefPtr<SharedMessagePortMessage>> mMessagesForTheOtherPort;
177 
178   nsAutoPtr<MessagePortIdentifier> mIdentifier;
179 
180   uint64_t mInnerID;
181 
182   State mState;
183 
184   bool mMessageQueueEnabled;
185 
186   bool mIsKeptAlive;
187 };
188 
189 } // namespace dom
190 } // namespace mozilla
191 
192 #endif // mozilla_dom_MessagePort_h
193