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