michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_ipc_FileDescriptor_h michael@0: #define mozilla_ipc_FileDescriptor_h michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "base/process.h" michael@0: #include "mozilla/DebugOnly.h" michael@0: #include "nscore.h" michael@0: michael@0: #ifdef XP_WIN michael@0: // Need the HANDLE typedef. michael@0: #include michael@0: #else michael@0: #include "base/file_descriptor_posix.h" michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: namespace ipc { michael@0: michael@0: // This class is used by IPDL to share file descriptors across processes. When michael@0: // sending a FileDescriptor IPDL will first duplicate a platform-specific file michael@0: // handle type ('PlatformHandleType') into a handle that is valid in the other michael@0: // process. Then IPDL will convert the duplicated handle into a type suitable michael@0: // for pickling ('PickleType') and then send that through the IPC pipe. In the michael@0: // receiving process the pickled data is converted into a platform-specific file michael@0: // handle and then returned to the receiver. michael@0: // michael@0: // To use this class add 'FileDescriptor' as an argument in the IPDL protocol michael@0: // and then pass a file descriptor from C++ to the Call/Send method. The michael@0: // Answer/Recv method will receive a FileDescriptor& on which PlatformHandle() michael@0: // can be called to return the platform file handle. michael@0: class FileDescriptor michael@0: { michael@0: public: michael@0: typedef base::ProcessHandle ProcessHandle; michael@0: michael@0: #ifdef XP_WIN michael@0: typedef HANDLE PlatformHandleType; michael@0: typedef HANDLE PickleType; michael@0: #else michael@0: typedef int PlatformHandleType; michael@0: typedef base::FileDescriptor PickleType; michael@0: #endif michael@0: michael@0: // This should only ever be created by IPDL. michael@0: struct IPDLPrivate michael@0: {}; michael@0: michael@0: FileDescriptor(); michael@0: michael@0: FileDescriptor(const FileDescriptor& aOther) michael@0: : mHandleCreatedByOtherProcess(false), michael@0: mHandleCreatedByOtherProcessWasUsed(false) michael@0: { michael@0: // Don't use operator= here because that will call michael@0: // CloseCurrentProcessHandle() on this (uninitialized) object. michael@0: Assign(aOther); michael@0: } michael@0: michael@0: FileDescriptor(PlatformHandleType aHandle); michael@0: michael@0: FileDescriptor(const IPDLPrivate&, const PickleType& aPickle) michael@0: #ifdef XP_WIN michael@0: : mHandle(aPickle) michael@0: #else michael@0: : mHandle(aPickle.fd) michael@0: #endif michael@0: , mHandleCreatedByOtherProcess(true) michael@0: , mHandleCreatedByOtherProcessWasUsed(false) michael@0: { } michael@0: michael@0: ~FileDescriptor() michael@0: { michael@0: CloseCurrentProcessHandle(); michael@0: } michael@0: michael@0: FileDescriptor& michael@0: operator=(const FileDescriptor& aOther) michael@0: { michael@0: CloseCurrentProcessHandle(); michael@0: Assign(aOther); michael@0: return *this; michael@0: } michael@0: michael@0: // Performs platform-specific actions to duplicate mHandle in the other michael@0: // process (e.g. dup() on POSIX, DuplicateHandle() on Windows). Returns a michael@0: // pickled value that can be passed to the other process via IPC. michael@0: PickleType michael@0: ShareTo(const IPDLPrivate&, ProcessHandle aOtherProcess) const; michael@0: michael@0: // Tests mHandle against a well-known invalid platform-specific file handle michael@0: // (e.g. -1 on POSIX, INVALID_HANDLE_VALUE on Windows). michael@0: bool michael@0: IsValid() const michael@0: { michael@0: return IsValid(mHandle); michael@0: } michael@0: michael@0: PlatformHandleType michael@0: PlatformHandle() const michael@0: { michael@0: if (mHandleCreatedByOtherProcess) { michael@0: mHandleCreatedByOtherProcessWasUsed = true; michael@0: } michael@0: return mHandle; michael@0: } michael@0: michael@0: bool michael@0: operator==(const FileDescriptor& aOther) const michael@0: { michael@0: return mHandle == aOther.mHandle; michael@0: } michael@0: michael@0: private: michael@0: void michael@0: Assign(const FileDescriptor& aOther) michael@0: { michael@0: if (aOther.mHandleCreatedByOtherProcess) { michael@0: mHandleCreatedByOtherProcess = true; michael@0: mHandleCreatedByOtherProcessWasUsed = michael@0: aOther.mHandleCreatedByOtherProcessWasUsed; michael@0: mHandle = aOther.PlatformHandle(); michael@0: } else { michael@0: DuplicateInCurrentProcess(aOther.PlatformHandle()); michael@0: mHandleCreatedByOtherProcess = false; michael@0: mHandleCreatedByOtherProcessWasUsed = false; michael@0: } michael@0: } michael@0: michael@0: static bool michael@0: IsValid(PlatformHandleType aHandle); michael@0: michael@0: void michael@0: DuplicateInCurrentProcess(PlatformHandleType aHandle); michael@0: michael@0: void michael@0: CloseCurrentProcessHandle(); michael@0: michael@0: PlatformHandleType mHandle; michael@0: michael@0: // If this is true then this instance is created by IPDL to ferry a handle to michael@0: // its eventual consumer and we never close the handle. If this is false then michael@0: // we are a RAII wrapper around the handle and we close the handle on michael@0: // destruction. michael@0: bool mHandleCreatedByOtherProcess; michael@0: michael@0: // This is to ensure that we don't leak the handle (which is only possible michael@0: // when we're in the receiving process). michael@0: mutable DebugOnly mHandleCreatedByOtherProcessWasUsed; michael@0: }; michael@0: michael@0: } // namespace ipc michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_ipc_FileDescriptor_h