Home | History | Annotate | Download | only in platform
      1 // Copyright 2018 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/public/cpp/platform/platform_handle.h"
      6 
      7 #include "base/logging.h"
      8 #include "build/build_config.h"
      9 
     10 #if defined(OS_WIN)
     11 #include <windows.h>
     12 
     13 #include "base/win/scoped_handle.h"
     14 #elif defined(OS_FUCHSIA)
     15 #include <lib/fdio/limits.h>
     16 #include <unistd.h>
     17 #include <zircon/status.h>
     18 
     19 #include "base/fuchsia/fuchsia_logging.h"
     20 #elif defined(OS_MACOSX) && !defined(OS_IOS)
     21 #include <mach/mach_vm.h>
     22 
     23 #include "base/mac/mach_logging.h"
     24 #include "base/mac/scoped_mach_port.h"
     25 #endif
     26 
     27 #if defined(OS_POSIX)
     28 #include <unistd.h>
     29 
     30 #include "base/files/scoped_file.h"
     31 #endif
     32 
     33 namespace mojo {
     34 
     35 namespace {
     36 
     37 #if defined(OS_WIN)
     38 base::win::ScopedHandle CloneHandle(const base::win::ScopedHandle& handle) {
     39   DCHECK(handle.IsValid());
     40 
     41   HANDLE dupe;
     42   BOOL result = ::DuplicateHandle(::GetCurrentProcess(), handle.Get(),
     43                                   ::GetCurrentProcess(), &dupe, 0, FALSE,
     44                                   DUPLICATE_SAME_ACCESS);
     45   if (!result)
     46     return base::win::ScopedHandle();
     47   DCHECK_NE(dupe, INVALID_HANDLE_VALUE);
     48   return base::win::ScopedHandle(dupe);
     49 }
     50 #elif defined(OS_FUCHSIA)
     51 zx::handle CloneHandle(const zx::handle& handle) {
     52   DCHECK(handle.is_valid());
     53 
     54   zx::handle dupe;
     55   zx_status_t result = handle.duplicate(ZX_RIGHT_SAME_RIGHTS, &dupe);
     56   if (result != ZX_OK)
     57     ZX_DLOG(ERROR, result) << "zx_duplicate_handle";
     58   return std::move(dupe);
     59 }
     60 #elif defined(OS_MACOSX) && !defined(OS_IOS)
     61 base::mac::ScopedMachSendRight CloneMachPort(
     62     const base::mac::ScopedMachSendRight& mach_port) {
     63   DCHECK(mach_port.is_valid());
     64 
     65   kern_return_t kr = mach_port_mod_refs(mach_task_self(), mach_port.get(),
     66                                         MACH_PORT_RIGHT_SEND, 1);
     67   if (kr != KERN_SUCCESS) {
     68     MACH_DLOG(ERROR, kr) << "mach_port_mod_refs";
     69     return base::mac::ScopedMachSendRight();
     70   }
     71   return base::mac::ScopedMachSendRight(mach_port.get());
     72 }
     73 #endif
     74 
     75 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
     76 base::ScopedFD CloneFD(const base::ScopedFD& fd) {
     77   DCHECK(fd.is_valid());
     78   return base::ScopedFD(dup(fd.get()));
     79 }
     80 #endif
     81 
     82 }  // namespace
     83 
     84 PlatformHandle::PlatformHandle() = default;
     85 
     86 PlatformHandle::PlatformHandle(PlatformHandle&& other) {
     87   *this = std::move(other);
     88 }
     89 
     90 #if defined(OS_WIN)
     91 PlatformHandle::PlatformHandle(base::win::ScopedHandle handle)
     92     : type_(Type::kHandle), handle_(std::move(handle)) {}
     93 #elif defined(OS_FUCHSIA)
     94 PlatformHandle::PlatformHandle(zx::handle handle)
     95     : type_(Type::kHandle), handle_(std::move(handle)) {}
     96 #elif defined(OS_MACOSX) && !defined(OS_IOS)
     97 PlatformHandle::PlatformHandle(base::mac::ScopedMachSendRight mach_port)
     98     : type_(Type::kMachPort), mach_port_(std::move(mach_port)) {}
     99 #endif
    100 
    101 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
    102 PlatformHandle::PlatformHandle(base::ScopedFD fd)
    103     : type_(Type::kFd), fd_(std::move(fd)) {
    104 #if defined(OS_FUCHSIA)
    105   DCHECK_LT(fd_.get(), FDIO_MAX_FD);
    106 #endif
    107 }
    108 #endif
    109 
    110 PlatformHandle::~PlatformHandle() = default;
    111 
    112 PlatformHandle& PlatformHandle::operator=(PlatformHandle&& other) {
    113   type_ = other.type_;
    114   other.type_ = Type::kNone;
    115 
    116 #if defined(OS_WIN)
    117   handle_ = std::move(other.handle_);
    118 #elif defined(OS_FUCHSIA)
    119   handle_ = std::move(other.handle_);
    120 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    121   mach_port_ = std::move(other.mach_port_);
    122 #endif
    123 
    124 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
    125   fd_ = std::move(other.fd_);
    126 #endif
    127 
    128   return *this;
    129 }
    130 
    131 // static
    132 void PlatformHandle::ToMojoPlatformHandle(PlatformHandle handle,
    133                                           MojoPlatformHandle* out_handle) {
    134   DCHECK(out_handle);
    135   out_handle->struct_size = sizeof(MojoPlatformHandle);
    136   if (handle.type_ == Type::kNone) {
    137     out_handle->type = MOJO_PLATFORM_HANDLE_TYPE_INVALID;
    138     out_handle->value = 0;
    139     return;
    140   }
    141 
    142   do {
    143 #if defined(OS_WIN)
    144     out_handle->type = MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE;
    145     out_handle->value =
    146         static_cast<uint64_t>(HandleToLong(handle.TakeHandle().Take()));
    147     break;
    148 #elif defined(OS_FUCHSIA)
    149     if (handle.is_handle()) {
    150       out_handle->type = MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE;
    151       out_handle->value = handle.TakeHandle().release();
    152       break;
    153     }
    154 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    155     if (handle.is_mach_port()) {
    156       out_handle->type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
    157       out_handle->value =
    158           static_cast<uint64_t>(handle.TakeMachPort().release());
    159       break;
    160     }
    161 #endif
    162 
    163 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
    164     DCHECK(handle.is_fd());
    165     out_handle->type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
    166     out_handle->value = static_cast<uint64_t>(handle.TakeFD().release());
    167 #endif
    168   } while (false);
    169 
    170   // One of the above cases must take ownership of |handle|.
    171   DCHECK(!handle.is_valid());
    172 }
    173 
    174 // static
    175 PlatformHandle PlatformHandle::FromMojoPlatformHandle(
    176     const MojoPlatformHandle* handle) {
    177   if (handle->struct_size < sizeof(*handle) ||
    178       handle->type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) {
    179     return PlatformHandle();
    180   }
    181 
    182 #if defined(OS_WIN)
    183   if (handle->type != MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE)
    184     return PlatformHandle();
    185   return PlatformHandle(
    186       base::win::ScopedHandle(LongToHandle(static_cast<long>(handle->value))));
    187 #elif defined(OS_FUCHSIA)
    188   if (handle->type == MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE)
    189     return PlatformHandle(zx::handle(handle->value));
    190 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    191   if (handle->type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT) {
    192     return PlatformHandle(base::mac::ScopedMachSendRight(
    193         static_cast<mach_port_t>(handle->value)));
    194   }
    195 #endif
    196 
    197 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
    198   if (handle->type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
    199     return PlatformHandle();
    200   return PlatformHandle(base::ScopedFD(static_cast<int>(handle->value)));
    201 #endif
    202 }
    203 
    204 void PlatformHandle::reset() {
    205   type_ = Type::kNone;
    206 
    207 #if defined(OS_WIN)
    208   handle_.Close();
    209 #elif defined(OS_FUCHSIA)
    210   handle_.reset();
    211 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    212   mach_port_.reset();
    213 #endif
    214 
    215 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
    216   fd_.reset();
    217 #endif
    218 }
    219 
    220 void PlatformHandle::release() {
    221   type_ = Type::kNone;
    222 
    223 #if defined(OS_WIN)
    224   ignore_result(handle_.Take());
    225 #elif defined(OS_FUCHSIA)
    226   ignore_result(handle_.release());
    227 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    228   ignore_result(mach_port_.release());
    229 #endif
    230 
    231 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
    232   ignore_result(fd_.release());
    233 #endif
    234 }
    235 
    236 PlatformHandle PlatformHandle::Clone() const {
    237 #if defined(OS_WIN)
    238   return PlatformHandle(CloneHandle(handle_));
    239 #elif defined(OS_FUCHSIA)
    240   if (is_valid_handle())
    241     return PlatformHandle(CloneHandle(handle_));
    242   return PlatformHandle(CloneFD(fd_));
    243 #elif defined(OS_MACOSX) && !defined(OS_IOS)
    244   if (is_valid_mach_port())
    245     return PlatformHandle(CloneMachPort(mach_port_));
    246   return PlatformHandle(CloneFD(fd_));
    247 #elif defined(OS_POSIX)
    248   return PlatformHandle(CloneFD(fd_));
    249 #endif
    250 }
    251 
    252 }  // namespace mojo
    253