|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=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_plugins_MiniShmBase_h |
|
8 #define mozilla_plugins_MiniShmBase_h |
|
9 |
|
10 #include "base/basictypes.h" |
|
11 |
|
12 #include "nsDebug.h" |
|
13 |
|
14 #include <windows.h> |
|
15 |
|
16 namespace mozilla { |
|
17 namespace plugins { |
|
18 |
|
19 /** |
|
20 * This class is used to provide RAII semantics for mapped views. |
|
21 * @see ScopedHandle |
|
22 */ |
|
23 class ScopedMappedFileView |
|
24 { |
|
25 public: |
|
26 explicit |
|
27 ScopedMappedFileView(LPVOID aView) |
|
28 : mView(aView) |
|
29 { |
|
30 } |
|
31 |
|
32 ~ScopedMappedFileView() |
|
33 { |
|
34 Close(); |
|
35 } |
|
36 |
|
37 void |
|
38 Close() |
|
39 { |
|
40 if (mView) { |
|
41 ::UnmapViewOfFile(mView); |
|
42 mView = nullptr; |
|
43 } |
|
44 } |
|
45 |
|
46 void |
|
47 Set(LPVOID aView) |
|
48 { |
|
49 Close(); |
|
50 mView = aView; |
|
51 } |
|
52 |
|
53 LPVOID |
|
54 Get() const |
|
55 { |
|
56 return mView; |
|
57 } |
|
58 |
|
59 LPVOID |
|
60 Take() |
|
61 { |
|
62 LPVOID result = mView; |
|
63 mView = nullptr; |
|
64 return result; |
|
65 } |
|
66 |
|
67 operator LPVOID() |
|
68 { |
|
69 return mView; |
|
70 } |
|
71 |
|
72 bool |
|
73 IsValid() const |
|
74 { |
|
75 return (mView); |
|
76 } |
|
77 |
|
78 private: |
|
79 DISALLOW_COPY_AND_ASSIGN(ScopedMappedFileView); |
|
80 |
|
81 LPVOID mView; |
|
82 }; |
|
83 |
|
84 class MiniShmBase; |
|
85 |
|
86 class MiniShmObserver |
|
87 { |
|
88 public: |
|
89 /** |
|
90 * This function is called whenever there is a new shared memory request. |
|
91 * @param aMiniShmObj MiniShmBase object that may be used to read and |
|
92 * write from shared memory. |
|
93 */ |
|
94 virtual void OnMiniShmEvent(MiniShmBase *aMiniShmObj) = 0; |
|
95 /** |
|
96 * This function is called once when a MiniShmParent and a MiniShmChild |
|
97 * object have successfully negotiated a connection. |
|
98 * |
|
99 * @param aMiniShmObj MiniShmBase object that may be used to read and |
|
100 * write from shared memory. |
|
101 */ |
|
102 virtual void OnMiniShmConnect(MiniShmBase *aMiniShmObj) { } |
|
103 }; |
|
104 |
|
105 /** |
|
106 * Base class for MiniShm connections. This class defines the common |
|
107 * interfaces and code between parent and child. |
|
108 */ |
|
109 class MiniShmBase |
|
110 { |
|
111 public: |
|
112 /** |
|
113 * Obtains a writable pointer into shared memory of type T. |
|
114 * typename T must be plain-old-data and contain an unsigned integral |
|
115 * member T::identifier that uniquely identifies T with respect to |
|
116 * other types used by the protocol being implemented. |
|
117 * |
|
118 * @param aPtr Pointer to receive the shared memory address. |
|
119 * This value is set if and only if the function |
|
120 * succeeded. |
|
121 * @return NS_OK if and only if aPtr was successfully obtained. |
|
122 * NS_ERROR_ILLEGAL_VALUE if type T is not valid for MiniShm. |
|
123 * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. |
|
124 * NS_ERROR_NOT_AVAILABLE if the memory is not safe to write. |
|
125 */ |
|
126 template<typename T> nsresult |
|
127 GetWritePtr(T*& aPtr) |
|
128 { |
|
129 if (!mWriteHeader || !mGuard) { |
|
130 return NS_ERROR_NOT_INITIALIZED; |
|
131 } |
|
132 if (sizeof(T) > mPayloadMaxLen || |
|
133 T::identifier <= RESERVED_CODE_LAST) { |
|
134 return NS_ERROR_ILLEGAL_VALUE; |
|
135 } |
|
136 if (::WaitForSingleObject(mGuard, mTimeout) != WAIT_OBJECT_0) { |
|
137 return NS_ERROR_NOT_AVAILABLE; |
|
138 } |
|
139 mWriteHeader->mId = T::identifier; |
|
140 mWriteHeader->mPayloadLen = sizeof(T); |
|
141 aPtr = reinterpret_cast<T*>(mWriteHeader + 1); |
|
142 return NS_OK; |
|
143 } |
|
144 |
|
145 /** |
|
146 * Obtains a readable pointer into shared memory of type T. |
|
147 * typename T must be plain-old-data and contain an unsigned integral |
|
148 * member T::identifier that uniquely identifies T with respect to |
|
149 * other types used by the protocol being implemented. |
|
150 * |
|
151 * @param aPtr Pointer to receive the shared memory address. |
|
152 * This value is set if and only if the function |
|
153 * succeeded. |
|
154 * @return NS_OK if and only if aPtr was successfully obtained. |
|
155 * NS_ERROR_ILLEGAL_VALUE if type T is not valid for MiniShm or if |
|
156 * type T does not match the type of the data |
|
157 * stored in shared memory. |
|
158 * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. |
|
159 */ |
|
160 template<typename T> nsresult |
|
161 GetReadPtr(const T*& aPtr) |
|
162 { |
|
163 if (!mReadHeader) { |
|
164 return NS_ERROR_NOT_INITIALIZED; |
|
165 } |
|
166 if (mReadHeader->mId != T::identifier || |
|
167 sizeof(T) != mReadHeader->mPayloadLen) { |
|
168 return NS_ERROR_ILLEGAL_VALUE; |
|
169 } |
|
170 aPtr = reinterpret_cast<const T*>(mReadHeader + 1); |
|
171 return NS_OK; |
|
172 } |
|
173 |
|
174 /** |
|
175 * Fires the peer's event causing its request handler to execute. |
|
176 * |
|
177 * @return Should return NS_OK if the send was successful. |
|
178 */ |
|
179 virtual nsresult |
|
180 Send() = 0; |
|
181 |
|
182 protected: |
|
183 /** |
|
184 * MiniShm reserves some identifier codes for its own use. Any |
|
185 * identifiers used by MiniShm protocol implementations must be |
|
186 * greater than RESERVED_CODE_LAST. |
|
187 */ |
|
188 enum ReservedCodes |
|
189 { |
|
190 RESERVED_CODE_INIT = 0, |
|
191 RESERVED_CODE_INIT_COMPLETE = 1, |
|
192 RESERVED_CODE_LAST = RESERVED_CODE_INIT_COMPLETE |
|
193 }; |
|
194 |
|
195 struct MiniShmHeader |
|
196 { |
|
197 unsigned int mId; |
|
198 unsigned int mPayloadLen; |
|
199 }; |
|
200 |
|
201 struct MiniShmInit |
|
202 { |
|
203 enum identifier_t |
|
204 { |
|
205 identifier = RESERVED_CODE_INIT |
|
206 }; |
|
207 HANDLE mParentEvent; |
|
208 HANDLE mParentGuard; |
|
209 HANDLE mChildEvent; |
|
210 HANDLE mChildGuard; |
|
211 }; |
|
212 |
|
213 struct MiniShmInitComplete |
|
214 { |
|
215 enum identifier_t |
|
216 { |
|
217 identifier = RESERVED_CODE_INIT_COMPLETE |
|
218 }; |
|
219 bool mSucceeded; |
|
220 }; |
|
221 |
|
222 MiniShmBase() |
|
223 : mObserver(nullptr), |
|
224 mWriteHeader(nullptr), |
|
225 mReadHeader(nullptr), |
|
226 mPayloadMaxLen(0), |
|
227 mGuard(nullptr), |
|
228 mTimeout(INFINITE) |
|
229 { |
|
230 } |
|
231 virtual ~MiniShmBase() |
|
232 { } |
|
233 |
|
234 virtual void |
|
235 OnEvent() |
|
236 { |
|
237 if (mObserver) { |
|
238 mObserver->OnMiniShmEvent(this); |
|
239 } |
|
240 } |
|
241 |
|
242 virtual void |
|
243 OnConnect() |
|
244 { |
|
245 if (mObserver) { |
|
246 mObserver->OnMiniShmConnect(this); |
|
247 } |
|
248 } |
|
249 |
|
250 nsresult |
|
251 SetView(LPVOID aView, const unsigned int aSize, bool aIsChild) |
|
252 { |
|
253 if (!aView || aSize <= 2 * sizeof(MiniShmHeader)) { |
|
254 return NS_ERROR_ILLEGAL_VALUE; |
|
255 } |
|
256 // Divide the region into halves for parent and child |
|
257 if (aIsChild) { |
|
258 mReadHeader = static_cast<MiniShmHeader*>(aView); |
|
259 mWriteHeader = reinterpret_cast<MiniShmHeader*>(static_cast<char*>(aView) |
|
260 + aSize / 2U); |
|
261 } else { |
|
262 mWriteHeader = static_cast<MiniShmHeader*>(aView); |
|
263 mReadHeader = reinterpret_cast<MiniShmHeader*>(static_cast<char*>(aView) |
|
264 + aSize / 2U); |
|
265 } |
|
266 mPayloadMaxLen = aSize / 2U - sizeof(MiniShmHeader); |
|
267 return NS_OK; |
|
268 } |
|
269 |
|
270 nsresult |
|
271 SetGuard(HANDLE aGuard, DWORD aTimeout) |
|
272 { |
|
273 if (!aGuard || !aTimeout) { |
|
274 return NS_ERROR_ILLEGAL_VALUE; |
|
275 } |
|
276 mGuard = aGuard; |
|
277 mTimeout = aTimeout; |
|
278 return NS_OK; |
|
279 } |
|
280 |
|
281 inline void |
|
282 SetObserver(MiniShmObserver *aObserver) { mObserver = aObserver; } |
|
283 |
|
284 /** |
|
285 * Obtains a writable pointer into shared memory of type T. This version |
|
286 * differs from GetWritePtr in that it allows typename T to be one of |
|
287 * the private data structures declared in MiniShmBase. |
|
288 * |
|
289 * @param aPtr Pointer to receive the shared memory address. |
|
290 * This value is set if and only if the function |
|
291 * succeeded. |
|
292 * @return NS_OK if and only if aPtr was successfully obtained. |
|
293 * NS_ERROR_ILLEGAL_VALUE if type T not an internal MiniShm struct. |
|
294 * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. |
|
295 */ |
|
296 template<typename T> nsresult |
|
297 GetWritePtrInternal(T*& aPtr) |
|
298 { |
|
299 if (!mWriteHeader) { |
|
300 return NS_ERROR_NOT_INITIALIZED; |
|
301 } |
|
302 if (sizeof(T) > mPayloadMaxLen || |
|
303 T::identifier > RESERVED_CODE_LAST) { |
|
304 return NS_ERROR_ILLEGAL_VALUE; |
|
305 } |
|
306 mWriteHeader->mId = T::identifier; |
|
307 mWriteHeader->mPayloadLen = sizeof(T); |
|
308 aPtr = reinterpret_cast<T*>(mWriteHeader + 1); |
|
309 return NS_OK; |
|
310 } |
|
311 |
|
312 static VOID CALLBACK |
|
313 SOnEvent(PVOID aContext, BOOLEAN aIsTimer) |
|
314 { |
|
315 MiniShmBase* object = static_cast<MiniShmBase*>(aContext); |
|
316 object->OnEvent(); |
|
317 } |
|
318 |
|
319 private: |
|
320 MiniShmObserver* mObserver; |
|
321 MiniShmHeader* mWriteHeader; |
|
322 MiniShmHeader* mReadHeader; |
|
323 unsigned int mPayloadMaxLen; |
|
324 HANDLE mGuard; |
|
325 DWORD mTimeout; |
|
326 |
|
327 DISALLOW_COPY_AND_ASSIGN(MiniShmBase); |
|
328 }; |
|
329 |
|
330 } // namespace plugins |
|
331 } // namespace mozilla |
|
332 |
|
333 #endif // mozilla_plugins_MiniShmBase_h |
|
334 |