// Copyright 2015 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 BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_

#include <stddef.h>

#include "build/build_config.h"

#if defined(OS_WIN)
#include <windows.h>
#include "base/process/process_handle.h"
#elif defined(OS_MACOSX) && !defined(OS_IOS)
#include <mach/mach.h>
#include <sys/types.h>
#include "base/base_export.h"
#include "base/file_descriptor_posix.h"
#include "base/macros.h"
#include "base/process/process_handle.h"
#elif defined(OS_POSIX)
#include <sys/types.h>
#include "base/file_descriptor_posix.h"
#endif

namespace base {

class Pickle;

// SharedMemoryHandle is a platform specific type which represents
// the underlying OS handle to a shared memory segment.
#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
typedef FileDescriptor SharedMemoryHandle;
#elif defined(OS_WIN)
class BASE_EXPORT SharedMemoryHandle {
 public:
  // The default constructor returns an invalid SharedMemoryHandle.
  SharedMemoryHandle();
  SharedMemoryHandle(HANDLE h, base::ProcessId pid);

  // Standard copy constructor. The new instance shares the underlying OS
  // primitives.
  SharedMemoryHandle(const SharedMemoryHandle& handle);

  // Standard assignment operator. The updated instance shares the underlying
  // OS primitives.
  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);

  // Comparison operators.
  bool operator==(const SharedMemoryHandle& handle) const;
  bool operator!=(const SharedMemoryHandle& handle) const;

  // Closes the underlying OS resources.
  void Close() const;

  // Whether the underlying OS primitive is valid.
  bool IsValid() const;

  // Whether |pid_| is the same as the current process's id.
  bool BelongsToCurrentProcess() const;

  // Whether handle_ needs to be duplicated into the destination process when
  // an instance of this class is passed over a Chrome IPC channel.
  bool NeedsBrokering() const;

  void SetOwnershipPassesToIPC(bool ownership_passes);
  bool OwnershipPassesToIPC() const;

  HANDLE GetHandle() const;
  base::ProcessId GetPID() const;

 private:
  HANDLE handle_;

  // The process in which |handle_| is valid and can be used. If |handle_| is
  // invalid, this will be kNullProcessId.
  base::ProcessId pid_;

  // Whether passing this object as a parameter to an IPC message passes
  // ownership of |handle_| to the IPC stack. This is meant to mimic the
  // behavior of the |auto_close| parameter of FileDescriptor. This member only
  // affects attachment-brokered SharedMemoryHandles.
  // Defaults to |false|.
  bool ownership_passes_to_ipc_;
};
#else
class BASE_EXPORT SharedMemoryHandle {
 public:
  // The values of these enums must not change, as they are used by the
  // histogram OSX.SharedMemory.Mechanism.
  enum Type {
    // The SharedMemoryHandle is backed by a POSIX fd.
    POSIX,
    // The SharedMemoryHandle is backed by the Mach primitive "memory object".
    MACH,
  };
  static const int TypeMax = 2;

  // The format that should be used to transmit |Type| over the wire.
  typedef int TypeWireFormat;

  // The default constructor returns an invalid SharedMemoryHandle.
  SharedMemoryHandle();

  // Constructs a SharedMemoryHandle backed by the components of a
  // FileDescriptor. The newly created instance has the same ownership semantics
  // as base::FileDescriptor. This typically means that the SharedMemoryHandle
  // takes ownership of the |fd| if |auto_close| is true. Unfortunately, it's
  // common for existing code to make shallow copies of SharedMemoryHandle, and
  // the one that is finally passed into a base::SharedMemory is the one that
  // "consumes" the fd.
  explicit SharedMemoryHandle(const base::FileDescriptor& file_descriptor);
  SharedMemoryHandle(int fd, bool auto_close);

  // Makes a Mach-based SharedMemoryHandle of the given size. On error,
  // subsequent calls to IsValid() return false.
  explicit SharedMemoryHandle(mach_vm_size_t size);

  // Makes a Mach-based SharedMemoryHandle from |memory_object|, a named entry
  // in the task with process id |pid|. The memory region has size |size|.
  SharedMemoryHandle(mach_port_t memory_object,
                     mach_vm_size_t size,
                     base::ProcessId pid);

  // Standard copy constructor. The new instance shares the underlying OS
  // primitives.
  SharedMemoryHandle(const SharedMemoryHandle& handle);

  // Standard assignment operator. The updated instance shares the underlying
  // OS primitives.
  SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);

  // Duplicates the underlying OS resources.
  SharedMemoryHandle Duplicate() const;

  // Comparison operators.
  bool operator==(const SharedMemoryHandle& handle) const;
  bool operator!=(const SharedMemoryHandle& handle) const;

  // Returns the type.
  Type GetType() const;

  // Whether the underlying OS primitive is valid. Once the SharedMemoryHandle
  // is backed by a valid OS primitive, it becomes immutable.
  bool IsValid() const;

  // Sets the POSIX fd backing the SharedMemoryHandle. Requires that the
  // SharedMemoryHandle be backed by a POSIX fd.
  void SetFileHandle(int fd, bool auto_close);

  // This method assumes that the SharedMemoryHandle is backed by a POSIX fd.
  // This is eventually no longer going to be true, so please avoid adding new
  // uses of this method.
  const FileDescriptor GetFileDescriptor() const;

  // Exposed so that the SharedMemoryHandle can be transported between
  // processes.
  mach_port_t GetMemoryObject() const;

  // Returns false on a failure to determine the size. On success, populates the
  // output variable |size|.
  bool GetSize(size_t* size) const;

  // The SharedMemoryHandle must be valid.
  // Returns whether the SharedMemoryHandle was successfully mapped into memory.
  // On success, |memory| is an output variable that contains the start of the
  // mapped memory.
  bool MapAt(off_t offset, size_t bytes, void** memory, bool read_only);

  // Closes the underlying OS primitive.
  void Close() const;

  void SetOwnershipPassesToIPC(bool ownership_passes);
  bool OwnershipPassesToIPC() const;

 private:
  // Shared code between copy constructor and operator=.
  void CopyRelevantData(const SharedMemoryHandle& handle);

  Type type_;

  // Each instance of a SharedMemoryHandle is backed either by a POSIX fd or a
  // mach port. |type_| determines the backing member.
  union {
    FileDescriptor file_descriptor_;

    struct {
      mach_port_t memory_object_;

      // The size of the shared memory region when |type_| is MACH. Only
      // relevant if |memory_object_| is not |MACH_PORT_NULL|.
      mach_vm_size_t size_;

      // The pid of the process in which |memory_object_| is usable. Only
      // relevant if |memory_object_| is not |MACH_PORT_NULL|.
      base::ProcessId pid_;

      // Whether passing this object as a parameter to an IPC message passes
      // ownership of |memory_object_| to the IPC stack. This is meant to mimic
      // the behavior of the |auto_close| parameter of FileDescriptor.
      // Defaults to |false|.
      bool ownership_passes_to_ipc_;
    };
  };
};
#endif

}  // namespace base

#endif  // BASE_MEMORY_SHARED_MEMORY_HANDLE_H_