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