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