• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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