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)
CloneHandle(const base::win::ScopedHandle & handle)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)
CloneFD(const base::ScopedFD & fd)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
PlatformHandle(PlatformHandle && other)86 PlatformHandle::PlatformHandle(PlatformHandle&& other) {
87 *this = std::move(other);
88 }
89
90 #if defined(OS_WIN)
PlatformHandle(base::win::ScopedHandle handle)91 PlatformHandle::PlatformHandle(base::win::ScopedHandle handle)
92 : type_(Type::kHandle), handle_(std::move(handle)) {}
93 #elif defined(OS_FUCHSIA)
PlatformHandle(zx::handle handle)94 PlatformHandle::PlatformHandle(zx::handle handle)
95 : type_(Type::kHandle), handle_(std::move(handle)) {}
96 #elif defined(OS_MACOSX) && !defined(OS_IOS)
PlatformHandle(base::mac::ScopedMachSendRight mach_port)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)
PlatformHandle(base::ScopedFD fd)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
operator =(PlatformHandle && other)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
ToMojoPlatformHandle(PlatformHandle handle,MojoPlatformHandle * out_handle)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
FromMojoPlatformHandle(const MojoPlatformHandle * handle)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
reset()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
release()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
Clone() const236 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