/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_plugins_MiniShmBase_h #define mozilla_plugins_MiniShmBase_h #include "base/basictypes.h" #include "nsDebug.h" #include namespace mozilla { namespace plugins { /** * This class is used to provide RAII semantics for mapped views. * @see ScopedHandle */ class ScopedMappedFileView { public: explicit ScopedMappedFileView(LPVOID aView) : mView(aView) { } ~ScopedMappedFileView() { Close(); } void Close() { if (mView) { ::UnmapViewOfFile(mView); mView = nullptr; } } void Set(LPVOID aView) { Close(); mView = aView; } LPVOID Get() const { return mView; } LPVOID Take() { LPVOID result = mView; mView = nullptr; return result; } operator LPVOID() { return mView; } bool IsValid() const { return (mView); } private: DISALLOW_COPY_AND_ASSIGN(ScopedMappedFileView); LPVOID mView; }; class MiniShmBase; class MiniShmObserver { public: /** * This function is called whenever there is a new shared memory request. * @param aMiniShmObj MiniShmBase object that may be used to read and * write from shared memory. */ virtual void OnMiniShmEvent(MiniShmBase *aMiniShmObj) = 0; /** * This function is called once when a MiniShmParent and a MiniShmChild * object have successfully negotiated a connection. * * @param aMiniShmObj MiniShmBase object that may be used to read and * write from shared memory. */ virtual void OnMiniShmConnect(MiniShmBase *aMiniShmObj) { } }; /** * Base class for MiniShm connections. This class defines the common * interfaces and code between parent and child. */ class MiniShmBase { public: /** * Obtains a writable pointer into shared memory of type T. * typename T must be plain-old-data and contain an unsigned integral * member T::identifier that uniquely identifies T with respect to * other types used by the protocol being implemented. * * @param aPtr Pointer to receive the shared memory address. * This value is set if and only if the function * succeeded. * @return NS_OK if and only if aPtr was successfully obtained. * NS_ERROR_ILLEGAL_VALUE if type T is not valid for MiniShm. * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. * NS_ERROR_NOT_AVAILABLE if the memory is not safe to write. */ template nsresult GetWritePtr(T*& aPtr) { if (!mWriteHeader || !mGuard) { return NS_ERROR_NOT_INITIALIZED; } if (sizeof(T) > mPayloadMaxLen || T::identifier <= RESERVED_CODE_LAST) { return NS_ERROR_ILLEGAL_VALUE; } if (::WaitForSingleObject(mGuard, mTimeout) != WAIT_OBJECT_0) { return NS_ERROR_NOT_AVAILABLE; } mWriteHeader->mId = T::identifier; mWriteHeader->mPayloadLen = sizeof(T); aPtr = reinterpret_cast(mWriteHeader + 1); return NS_OK; } /** * Obtains a readable pointer into shared memory of type T. * typename T must be plain-old-data and contain an unsigned integral * member T::identifier that uniquely identifies T with respect to * other types used by the protocol being implemented. * * @param aPtr Pointer to receive the shared memory address. * This value is set if and only if the function * succeeded. * @return NS_OK if and only if aPtr was successfully obtained. * NS_ERROR_ILLEGAL_VALUE if type T is not valid for MiniShm or if * type T does not match the type of the data * stored in shared memory. * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. */ template nsresult GetReadPtr(const T*& aPtr) { if (!mReadHeader) { return NS_ERROR_NOT_INITIALIZED; } if (mReadHeader->mId != T::identifier || sizeof(T) != mReadHeader->mPayloadLen) { return NS_ERROR_ILLEGAL_VALUE; } aPtr = reinterpret_cast(mReadHeader + 1); return NS_OK; } /** * Fires the peer's event causing its request handler to execute. * * @return Should return NS_OK if the send was successful. */ virtual nsresult Send() = 0; protected: /** * MiniShm reserves some identifier codes for its own use. Any * identifiers used by MiniShm protocol implementations must be * greater than RESERVED_CODE_LAST. */ enum ReservedCodes { RESERVED_CODE_INIT = 0, RESERVED_CODE_INIT_COMPLETE = 1, RESERVED_CODE_LAST = RESERVED_CODE_INIT_COMPLETE }; struct MiniShmHeader { unsigned int mId; unsigned int mPayloadLen; }; struct MiniShmInit { enum identifier_t { identifier = RESERVED_CODE_INIT }; HANDLE mParentEvent; HANDLE mParentGuard; HANDLE mChildEvent; HANDLE mChildGuard; }; struct MiniShmInitComplete { enum identifier_t { identifier = RESERVED_CODE_INIT_COMPLETE }; bool mSucceeded; }; MiniShmBase() : mObserver(nullptr), mWriteHeader(nullptr), mReadHeader(nullptr), mPayloadMaxLen(0), mGuard(nullptr), mTimeout(INFINITE) { } virtual ~MiniShmBase() { } virtual void OnEvent() { if (mObserver) { mObserver->OnMiniShmEvent(this); } } virtual void OnConnect() { if (mObserver) { mObserver->OnMiniShmConnect(this); } } nsresult SetView(LPVOID aView, const unsigned int aSize, bool aIsChild) { if (!aView || aSize <= 2 * sizeof(MiniShmHeader)) { return NS_ERROR_ILLEGAL_VALUE; } // Divide the region into halves for parent and child if (aIsChild) { mReadHeader = static_cast(aView); mWriteHeader = reinterpret_cast(static_cast(aView) + aSize / 2U); } else { mWriteHeader = static_cast(aView); mReadHeader = reinterpret_cast(static_cast(aView) + aSize / 2U); } mPayloadMaxLen = aSize / 2U - sizeof(MiniShmHeader); return NS_OK; } nsresult SetGuard(HANDLE aGuard, DWORD aTimeout) { if (!aGuard || !aTimeout) { return NS_ERROR_ILLEGAL_VALUE; } mGuard = aGuard; mTimeout = aTimeout; return NS_OK; } inline void SetObserver(MiniShmObserver *aObserver) { mObserver = aObserver; } /** * Obtains a writable pointer into shared memory of type T. This version * differs from GetWritePtr in that it allows typename T to be one of * the private data structures declared in MiniShmBase. * * @param aPtr Pointer to receive the shared memory address. * This value is set if and only if the function * succeeded. * @return NS_OK if and only if aPtr was successfully obtained. * NS_ERROR_ILLEGAL_VALUE if type T not an internal MiniShm struct. * NS_ERROR_NOT_INITIALIZED if there is no valid MiniShm connection. */ template nsresult GetWritePtrInternal(T*& aPtr) { if (!mWriteHeader) { return NS_ERROR_NOT_INITIALIZED; } if (sizeof(T) > mPayloadMaxLen || T::identifier > RESERVED_CODE_LAST) { return NS_ERROR_ILLEGAL_VALUE; } mWriteHeader->mId = T::identifier; mWriteHeader->mPayloadLen = sizeof(T); aPtr = reinterpret_cast(mWriteHeader + 1); return NS_OK; } static VOID CALLBACK SOnEvent(PVOID aContext, BOOLEAN aIsTimer) { MiniShmBase* object = static_cast(aContext); object->OnEvent(); } private: MiniShmObserver* mObserver; MiniShmHeader* mWriteHeader; MiniShmHeader* mReadHeader; unsigned int mPayloadMaxLen; HANDLE mGuard; DWORD mTimeout; DISALLOW_COPY_AND_ASSIGN(MiniShmBase); }; } // namespace plugins } // namespace mozilla #endif // mozilla_plugins_MiniShmBase_h