| // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef PPAPI_PROXY_SERIALIZED_HANDLES_H_ | |
| #define PPAPI_PROXY_SERIALIZED_HANDLES_H_ | |
| #include <stdint.h> | |
| #include <string> | |
| #include <vector> | |
| #include "base/atomicops.h" | |
| #include "base/logging.h" | |
| #include "base/memory/platform_shared_memory_region.h" | |
| #include "base/memory/ref_counted.h" | |
| #include "base/memory/shared_memory.h" | |
| #include "build/build_config.h" | |
| #include "ipc/ipc_platform_file.h" | |
| #include "ppapi/c/pp_resource.h" | |
| #include "ppapi/proxy/ppapi_proxy_export.h" | |
| namespace base { | |
| class Pickle; | |
| } | |
| namespace ppapi { | |
| namespace proxy { | |
| // SerializedHandle is a unified structure for holding a handle (e.g., a shared | |
| // memory handle, socket descriptor, etc). This is useful for passing handles in | |
| // resource messages and also makes it easier to translate handles in | |
| // NaClIPCAdapter for use in NaCl. | |
| class PPAPI_PROXY_EXPORT SerializedHandle { | |
| public: | |
| // TODO(https://crbug.com/845985): Remove SHARED_MEMORY type after all clients | |
| // will be converted to the SHARED_MEMORY_REGION. | |
| enum Type { INVALID, SHARED_MEMORY, SHARED_MEMORY_REGION, SOCKET, FILE }; | |
| // Header contains the fields that we send in IPC messages, apart from the | |
| // actual handle. See comments on the SerializedHandle fields below. | |
| struct Header { | |
| Header() : type(INVALID), size(0), open_flags(0) {} | |
| Header(Type type_arg, | |
| uint32_t size_arg, | |
| int32_t open_flags_arg, | |
| PP_Resource file_io_arg) | |
| : type(type_arg), | |
| size(size_arg), | |
| open_flags(open_flags_arg), | |
| file_io(file_io_arg) {} | |
| Type type; | |
| uint32_t size; | |
| int32_t open_flags; | |
| PP_Resource file_io; | |
| }; | |
| SerializedHandle(); | |
| // Move operations are allowed. | |
| SerializedHandle(SerializedHandle&&); | |
| SerializedHandle& operator=(SerializedHandle&&); | |
| // Create an invalid handle of the given type. | |
| explicit SerializedHandle(Type type); | |
| // Create a shared memory handle. | |
| SerializedHandle(const base::SharedMemoryHandle& handle, uint32_t size); | |
| // Create a shared memory region handle. | |
| explicit SerializedHandle(base::subtle::PlatformSharedMemoryRegion region); | |
| // Create a socket or file handle. | |
| SerializedHandle(const Type type, | |
| const IPC::PlatformFileForTransit& descriptor); | |
| Type type() const { return type_; } | |
| bool is_shmem() const { return type_ == SHARED_MEMORY; } | |
| bool is_shmem_region() const { return type_ == SHARED_MEMORY_REGION; } | |
| bool is_socket() const { return type_ == SOCKET; } | |
| bool is_file() const { return type_ == FILE; } | |
| const base::SharedMemoryHandle& shmem() const { | |
| DCHECK(is_shmem()); | |
| return shm_handle_; | |
| } | |
| uint32_t size() const { | |
| DCHECK(is_shmem()); | |
| return size_; | |
| } | |
| const base::subtle::PlatformSharedMemoryRegion& shmem_region() const { | |
| DCHECK(is_shmem_region()); | |
| return shm_region_; | |
| } | |
| base::subtle::PlatformSharedMemoryRegion TakeSharedMemoryRegion() { | |
| DCHECK(is_shmem_region()); | |
| return std::move(shm_region_); | |
| } | |
| const IPC::PlatformFileForTransit& descriptor() const { | |
| DCHECK(is_socket() || is_file()); | |
| return descriptor_; | |
| } | |
| int32_t open_flags() const { return open_flags_; } | |
| PP_Resource file_io() const { | |
| return file_io_; | |
| } | |
| void set_shmem(const base::SharedMemoryHandle& handle, uint32_t size) { | |
| type_ = SHARED_MEMORY; | |
| shm_handle_ = handle; | |
| size_ = size; | |
| descriptor_ = IPC::InvalidPlatformFileForTransit(); | |
| shm_region_ = base::subtle::PlatformSharedMemoryRegion(); | |
| } | |
| void set_shmem_region(base::subtle::PlatformSharedMemoryRegion region) { | |
| type_ = SHARED_MEMORY_REGION; | |
| shm_region_ = std::move(region); | |
| // Writable regions are not supported. | |
| DCHECK_NE(shm_region_.GetMode(), | |
| base::subtle::PlatformSharedMemoryRegion::Mode::kWritable); | |
| descriptor_ = IPC::InvalidPlatformFileForTransit(); | |
| shm_handle_ = base::SharedMemoryHandle(); | |
| size_ = 0; | |
| } | |
| void set_socket(const IPC::PlatformFileForTransit& socket) { | |
| type_ = SOCKET; | |
| descriptor_ = socket; | |
| shm_region_ = base::subtle::PlatformSharedMemoryRegion(); | |
| shm_handle_ = base::SharedMemoryHandle(); | |
| size_ = 0; | |
| } | |
| void set_file_handle(const IPC::PlatformFileForTransit& descriptor, | |
| int32_t open_flags, | |
| PP_Resource file_io) { | |
| type_ = FILE; | |
| descriptor_ = descriptor; | |
| shm_region_ = base::subtle::PlatformSharedMemoryRegion(); | |
| shm_handle_ = base::SharedMemoryHandle(); | |
| size_ = 0; | |
| open_flags_ = open_flags; | |
| file_io_ = file_io; | |
| } | |
| void set_null() { | |
| type_ = INVALID; | |
| shm_handle_ = base::SharedMemoryHandle(); | |
| shm_region_ = base::subtle::PlatformSharedMemoryRegion(); | |
| size_ = 0; | |
| descriptor_ = IPC::InvalidPlatformFileForTransit(); | |
| } | |
| void set_null_shmem() { set_shmem(base::SharedMemoryHandle(), 0); } | |
| void set_null_shmem_region() { | |
| set_shmem_region(base::subtle::PlatformSharedMemoryRegion()); | |
| } | |
| void set_null_socket() { | |
| set_socket(IPC::InvalidPlatformFileForTransit()); | |
| } | |
| void set_null_file_handle() { | |
| set_file_handle(IPC::InvalidPlatformFileForTransit(), 0, 0); | |
| } | |
| bool IsHandleValid() const; | |
| Header header() const { | |
| return Header(type_, size_, open_flags_, file_io_); | |
| } | |
| // Closes the handle and sets it to invalid. | |
| void Close(); | |
| // Write/Read a Header, which contains all the data except the handle. This | |
| // allows us to write the handle in a platform-specific way, as is necessary | |
| // in NaClIPCAdapter to share handles with NaCl from Windows. | |
| static void WriteHeader(const Header& hdr, base::Pickle* pickle); | |
| static bool ReadHeader(base::PickleIterator* iter, Header* hdr); | |
| private: | |
| // The kind of handle we're holding. | |
| Type type_; | |
| // We hold more members than we really need; we can't easily use a union, | |
| // because we hold non-POD types. But these types are pretty light-weight. If | |
| // we add more complex things later, we should come up with a more memory- | |
| // efficient strategy. | |
| // These are valid if type == SHARED_MEMORY. | |
| base::SharedMemoryHandle shm_handle_; | |
| uint32_t size_; | |
| // This is valid if type == SHARED_MEMORY_REGION. | |
| base::subtle::PlatformSharedMemoryRegion shm_region_; | |
| // This is valid if type == SOCKET || type == FILE. | |
| IPC::PlatformFileForTransit descriptor_; | |
| // The following fields are valid if type == FILE. | |
| int32_t open_flags_; | |
| // This is non-zero if file writes require quota checking. | |
| PP_Resource file_io_; | |
| DISALLOW_COPY_AND_ASSIGN(SerializedHandle); | |
| }; | |
| } // namespace proxy | |
| } // namespace ppapi | |
| #endif // PPAPI_PROXY_SERIALIZED_HANDLES_H_ |