1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: sw=4 ts=4 et :
3 : */
4 : /* ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Plugin App.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Chris Jones <jones.chris.g@gmail.com>
21 : * Portions created by the Initial Developer are Copyright (C) 2009
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef ipc_glue_AsyncChannel_h
41 : #define ipc_glue_AsyncChannel_h 1
42 :
43 : #include "base/basictypes.h"
44 : #include "base/message_loop.h"
45 :
46 : #include "mozilla/Monitor.h"
47 : #include "mozilla/ipc/Transport.h"
48 :
49 : //-----------------------------------------------------------------------------
50 :
51 : namespace mozilla {
52 : namespace ipc {
53 :
54 : struct HasResultCodes
55 3 : {
56 : enum Result {
57 : MsgProcessed,
58 : MsgDropped,
59 : MsgNotKnown,
60 : MsgNotAllowed,
61 : MsgPayloadError,
62 : MsgProcessingError,
63 : MsgRouteError,
64 : MsgValueError
65 : };
66 : };
67 :
68 :
69 : class RefCountedMonitor : public Monitor
70 0 : {
71 : public:
72 0 : RefCountedMonitor()
73 0 : : Monitor("mozilla.ipc.AsyncChannel.mMonitor")
74 0 : {}
75 :
76 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMonitor)
77 : };
78 :
79 : class AsyncChannel : protected HasResultCodes
80 : {
81 : protected:
82 : typedef mozilla::Monitor Monitor;
83 :
84 : enum ChannelState {
85 : ChannelClosed,
86 : ChannelOpening,
87 : ChannelConnected,
88 : ChannelTimeout,
89 : ChannelClosing,
90 : ChannelError
91 : };
92 :
93 : public:
94 : typedef IPC::Message Message;
95 : typedef mozilla::ipc::Transport Transport;
96 :
97 : class /*NS_INTERFACE_CLASS*/ AsyncListener: protected HasResultCodes
98 2 : {
99 : public:
100 2 : virtual ~AsyncListener() { }
101 :
102 : virtual void OnChannelClose() = 0;
103 : virtual void OnChannelError() = 0;
104 : virtual Result OnMessageReceived(const Message& aMessage) = 0;
105 : virtual void OnProcessingError(Result aError) = 0;
106 0 : virtual void OnChannelConnected(int32 peer_pid) {};
107 : };
108 :
109 : enum Side { Parent, Child, Unknown };
110 :
111 : public:
112 : //
113 : // These methods are called on the "worker" thread
114 : //
115 : AsyncChannel(AsyncListener* aListener);
116 : virtual ~AsyncChannel();
117 :
118 : // "Open" from the perspective of the transport layer; the underlying
119 : // socketpair/pipe should already be created.
120 : //
121 : // Returns true iff the transport layer was successfully connected,
122 : // i.e., mChannelState == ChannelConnected.
123 : bool Open(Transport* aTransport, MessageLoop* aIOLoop=0, Side aSide=Unknown);
124 :
125 : // "Open" a connection to another thread in the same process.
126 : //
127 : // Returns true iff the transport layer was successfully connected,
128 : // i.e., mChannelState == ChannelConnected.
129 : //
130 : // For more details on the process of opening a channel between
131 : // threads, see the extended comment on this function
132 : // in AsyncChannel.cpp.
133 : bool Open(AsyncChannel *aTargetChan, MessageLoop *aTargetLoop, Side aSide);
134 :
135 : // Close the underlying transport channel.
136 : void Close();
137 :
138 : // Asynchronously send a message to the other side of the channel
139 : virtual bool Send(Message* msg);
140 :
141 : // Asynchronously deliver a message back to this side of the
142 : // channel
143 : virtual bool Echo(Message* msg);
144 :
145 : // Send OnChannelConnected notification to listeners.
146 : void DispatchOnChannelConnected(int32 peer_pid);
147 :
148 : //
149 : // Each AsyncChannel is associated with either a ProcessLink or a
150 : // ThreadLink via the field mLink. The type of link is determined
151 : // by whether this AsyncChannel is communicating with another
152 : // process or another thread. In the former case, file
153 : // descriptors or a socket are used via the I/O queue. In the
154 : // latter case, messages are enqueued directly onto the target
155 : // thread's work queue.
156 : //
157 :
158 : class Link {
159 : protected:
160 : AsyncChannel *mChan;
161 :
162 : public:
163 : Link(AsyncChannel *aChan);
164 : virtual ~Link();
165 :
166 : // n.b.: These methods all require that the channel monitor is
167 : // held when they are invoked.
168 : virtual void EchoMessage(Message *msg) = 0;
169 : virtual void SendMessage(Message *msg) = 0;
170 : virtual void SendClose() = 0;
171 : };
172 :
173 : class ProcessLink : public Link, public Transport::Listener {
174 : protected:
175 : Transport* mTransport;
176 : MessageLoop* mIOLoop; // thread where IO happens
177 : Transport::Listener* mExistingListener; // channel's previous listener
178 :
179 : void OnCloseChannel();
180 : void OnChannelOpened();
181 : void OnEchoMessage(Message* msg);
182 :
183 0 : void AssertIOThread() const
184 : {
185 0 : NS_ABORT_IF_FALSE(mIOLoop == MessageLoop::current(),
186 : "not on I/O thread!");
187 0 : }
188 :
189 : public:
190 : ProcessLink(AsyncChannel *chan);
191 : virtual ~ProcessLink();
192 : void Open(Transport* aTransport, MessageLoop *aIOLoop, Side aSide);
193 :
194 : // Run on the I/O thread, only when using inter-process link.
195 : // These methods acquire the monitor and forward to the
196 : // similarly named methods in AsyncChannel below
197 : // (OnMessageReceivedFromLink(), etc)
198 : NS_OVERRIDE virtual void OnMessageReceived(const Message& msg);
199 : NS_OVERRIDE virtual void OnChannelConnected(int32 peer_pid);
200 : NS_OVERRIDE virtual void OnChannelError();
201 :
202 : NS_OVERRIDE virtual void EchoMessage(Message *msg);
203 : NS_OVERRIDE virtual void SendMessage(Message *msg);
204 : NS_OVERRIDE virtual void SendClose();
205 : };
206 :
207 : class ThreadLink : public Link {
208 : protected:
209 : AsyncChannel* mTargetChan;
210 :
211 : public:
212 : ThreadLink(AsyncChannel *aChan, AsyncChannel *aTargetChan);
213 : virtual ~ThreadLink();
214 :
215 : NS_OVERRIDE virtual void EchoMessage(Message *msg);
216 : NS_OVERRIDE virtual void SendMessage(Message *msg);
217 : NS_OVERRIDE virtual void SendClose();
218 : };
219 :
220 : protected:
221 : // The "link" thread is either the I/O thread (ProcessLink) or the
222 : // other actor's work thread (ThreadLink). In either case, it is
223 : // NOT our worker thread.
224 0 : void AssertLinkThread() const
225 : {
226 0 : NS_ABORT_IF_FALSE(mWorkerLoop != MessageLoop::current(),
227 : "on worker thread but should not be!");
228 0 : }
229 :
230 : // Can be run on either thread
231 0 : void AssertWorkerThread() const
232 : {
233 0 : NS_ABORT_IF_FALSE(mWorkerLoop == MessageLoop::current(),
234 : "not on worker thread!");
235 0 : }
236 :
237 0 : bool Connected() const {
238 0 : mMonitor->AssertCurrentThreadOwns();
239 0 : return ChannelConnected == mChannelState;
240 : }
241 :
242 : // Return true if |msg| is a special message targeted at the IO
243 : // thread, in which case it shouldn't be delivered to the worker.
244 : virtual bool MaybeInterceptSpecialIOMessage(const Message& msg);
245 : void ProcessGoodbyeMessage();
246 :
247 : // Runs on the link thread. Invoked either from the I/O thread methods above
248 : // or directly from the other actor if using a thread-based link.
249 : //
250 : // n.b.: mMonitor is always held when these methods are invoked.
251 : // In the case of a ProcessLink, it is acquired by the ProcessLink.
252 : // In the case of a ThreadLink, it is acquired by the other actor,
253 : // which then invokes these methods directly.
254 : virtual void OnMessageReceivedFromLink(const Message& msg);
255 : virtual void OnChannelErrorFromLink();
256 : void PostErrorNotifyTask();
257 :
258 : // Run on the worker thread
259 : void OnDispatchMessage(const Message& aMsg);
260 : virtual bool OnSpecialMessage(uint16 id, const Message& msg);
261 : void SendSpecialMessage(Message* msg) const;
262 :
263 : // Tell the IO thread to close the channel and wait for it to ACK.
264 : void SynchronouslyClose();
265 :
266 : bool MaybeHandleError(Result code, const char* channelName);
267 : void ReportConnectionError(const char* channelName) const;
268 :
269 : // Run on the worker thread
270 :
271 : void OnNotifyMaybeChannelError();
272 0 : virtual bool ShouldDeferNotifyMaybeError() const {
273 0 : return false;
274 : }
275 : void NotifyChannelClosed();
276 : void NotifyMaybeChannelError();
277 : void OnOpenAsSlave(AsyncChannel *aTargetChan, Side aSide);
278 : void CommonThreadOpenInit(AsyncChannel *aTargetChan, Side aSide);
279 :
280 : virtual void Clear();
281 :
282 : AsyncListener* mListener;
283 : ChannelState mChannelState;
284 : nsRefPtr<RefCountedMonitor> mMonitor;
285 : MessageLoop* mWorkerLoop; // thread where work is done
286 : bool mChild; // am I the child or parent?
287 : CancelableTask* mChannelErrorTask; // NotifyMaybeChannelError runnable
288 : Link *mLink; // link to other thread/process
289 : };
290 :
291 : } // namespace ipc
292 : } // namespace mozilla
293 : #endif // ifndef ipc_glue_AsyncChannel_h
|