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 #ifndef MOJO_PUBLIC_CPP_PLATFORM_PLATFORM_HANDLE_H_
6 #define MOJO_PUBLIC_CPP_PLATFORM_PLATFORM_HANDLE_H_
7 
8 #include "base/component_export.h"
9 #include "base/files/platform_file.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "build/build_config.h"
13 #include "mojo/public/c/system/platform_handle.h"
14 
15 #if defined(OS_WIN)
16 #include "base/win/scoped_handle.h"
17 #elif defined(OS_FUCHSIA)
18 #include <lib/zx/handle.h>
19 #elif defined(OS_MACOSX) && !defined(OS_IOS)
20 #include "base/mac/scoped_mach_port.h"
21 #endif
22 
23 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
24 #include "base/files/scoped_file.h"
25 #endif
26 
27 namespace mojo {
28 
29 // A PlatformHandle is a generic wrapper around a platform-specific system
30 // handle type, e.g. a POSIX file descriptor, Windows HANDLE, or macOS Mach
31 // port. This can wrap any of various such types depending on the host platform
32 // for which it's compiled.
33 //
34 // This is useful primarily for two reasons:
35 //
36 // - Interacting with the Mojo invitation API, which use OS primitives to
37 //   bootstrap Mojo IPC connections.
38 // - Interacting with Mojo platform handle wrapping and unwrapping API, which
39 //   allows handles to OS primitives to be transmitted over Mojo IPC with a
40 //   stable wire representation via Mojo handles.
41 //
42 // NOTE: This assumes ownership if the handle it represents.
COMPONENT_EXPORT(MOJO_CPP_PLATFORM)43 class COMPONENT_EXPORT(MOJO_CPP_PLATFORM) PlatformHandle {
44  public:
45   enum class Type {
46     kNone,
47 #if defined(OS_WIN) || defined(OS_FUCHSIA)
48     kHandle,
49 #elif defined(OS_MACOSX) && !defined(OS_IOS)
50     kMachSend,
51     kMachReceive,
52 #endif
53 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
54     kFd,
55 #endif
56   };
57 
58   PlatformHandle();
59   PlatformHandle(PlatformHandle&& other);
60 
61 #if defined(OS_WIN)
62   explicit PlatformHandle(base::win::ScopedHandle handle);
63 #elif defined(OS_FUCHSIA)
64   explicit PlatformHandle(zx::handle handle);
65 #elif defined(OS_MACOSX) && !defined(OS_IOS)
66   explicit PlatformHandle(base::mac::ScopedMachSendRight mach_port);
67   explicit PlatformHandle(base::mac::ScopedMachReceiveRight mach_port);
68 #endif
69 
70 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
71   explicit PlatformHandle(base::ScopedFD fd);
72 #endif
73 
74   ~PlatformHandle();
75 
76   PlatformHandle& operator=(PlatformHandle&& other);
77 
78   // Takes ownership of |handle|'s underlying platform handle and fills in
79   // |mojo_handle| with a representation of it. The caller assumes ownership of
80   // the platform handle.
81   static void ToMojoPlatformHandle(PlatformHandle handle,
82                                    MojoPlatformHandle* mojo_handle);
83 
84   // Closes the underlying platform handle.
85   // Assumes ownership of the platform handle described by |handle|, and returns
86   // it as a new PlatformHandle.
87   static PlatformHandle FromMojoPlatformHandle(
88       const MojoPlatformHandle* handle);
89 
90   Type type() const { return type_; }
91 
92   void reset();
93 
94   // Relinquishes ownership of the underlying handle, regardless of type, and
95   // discards its value. To release and obtain the underlying handle value, use
96   // one of the specific |Release*()| methods below.
97   void release();
98 
99   // Duplicates the underlying platform handle, returning a new PlatformHandle
100   // which owns it.
101   PlatformHandle Clone() const;
102 
103 #if defined(OS_WIN)
104   bool is_valid() const { return is_valid_handle(); }
105   bool is_valid_handle() const { return handle_.IsValid(); }
106   bool is_handle() const { return type_ == Type::kHandle; }
107   const base::win::ScopedHandle& GetHandle() const { return handle_; }
108   base::win::ScopedHandle TakeHandle() {
109     DCHECK_EQ(type_, Type::kHandle);
110     type_ = Type::kNone;
111     return std::move(handle_);
112   }
113   HANDLE ReleaseHandle() WARN_UNUSED_RESULT {
114     DCHECK_EQ(type_, Type::kHandle);
115     type_ = Type::kNone;
116     return handle_.Take();
117   }
118 #elif defined(OS_FUCHSIA)
119   bool is_valid() const { return is_valid_fd() || is_valid_handle(); }
120   bool is_valid_handle() const { return handle_.is_valid(); }
121   bool is_handle() const { return type_ == Type::kHandle; }
122   const zx::handle& GetHandle() const { return handle_; }
123   zx::handle TakeHandle() {
124     if (type_ == Type::kHandle)
125       type_ = Type::kNone;
126     return std::move(handle_);
127   }
128   zx_handle_t ReleaseHandle() WARN_UNUSED_RESULT {
129     if (type_ == Type::kHandle)
130       type_ = Type::kNone;
131     return handle_.release();
132   }
133 #elif defined(OS_MACOSX) && !defined(OS_IOS)
134   bool is_valid() const { return is_valid_fd() || is_valid_mach_port(); }
135   bool is_valid_mach_port() const {
136     return is_valid_mach_send() || is_valid_mach_receive();
137   }
138 
139   bool is_valid_mach_send() const { return mach_send_.is_valid(); }
140   bool is_mach_send() const { return type_ == Type::kMachSend; }
141   const base::mac::ScopedMachSendRight& GetMachSendRight() const {
142     return mach_send_;
143   }
144   base::mac::ScopedMachSendRight TakeMachSendRight() {
145     if (type_ == Type::kMachSend)
146       type_ = Type::kNone;
147     return std::move(mach_send_);
148   }
149   mach_port_t ReleaseMachSendRight() WARN_UNUSED_RESULT {
150     return TakeMachSendRight().release();
151   }
152 
153   bool is_valid_mach_receive() const { return mach_receive_.is_valid(); }
154   bool is_mach_receive() const { return type_ == Type::kMachReceive; }
155   const base::mac::ScopedMachReceiveRight& GetMachReceiveRight() const {
156     return mach_receive_;
157   }
158   base::mac::ScopedMachReceiveRight TakeMachReceiveRight() {
159     if (type_ == Type::kMachReceive)
160       type_ = Type::kNone;
161     return std::move(mach_receive_);
162   }
163   mach_port_t ReleaseMachReceiveRight() WARN_UNUSED_RESULT {
164     return TakeMachReceiveRight().release();
165   }
166 #elif defined(OS_POSIX)
167   bool is_valid() const { return is_valid_fd(); }
168 #else
169 #error "Unsupported platform."
170 #endif
171 
172 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
173   bool is_valid_fd() const { return fd_.is_valid(); }
174   bool is_fd() const { return type_ == Type::kFd; }
175   const base::ScopedFD& GetFD() const { return fd_; }
176   base::ScopedFD TakeFD() {
177     if (type_ == Type::kFd)
178       type_ = Type::kNone;
179     return std::move(fd_);
180   }
181   int ReleaseFD() WARN_UNUSED_RESULT {
182     if (type_ == Type::kFd)
183       type_ = Type::kNone;
184     return fd_.release();
185   }
186 #endif
187 
188   bool is_valid_platform_file() const {
189 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
190     return is_valid_fd();
191 #elif defined(OS_WIN)
192     return is_valid_handle();
193 #else
194 #error "Unsupported platform"
195 #endif
196   }
197   base::ScopedPlatformFile TakePlatformFile() {
198 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
199     return TakeFD();
200 #elif defined(OS_WIN)
201     return TakeHandle();
202 #else
203 #error "Unsupported platform"
204 #endif
205   }
206   base::PlatformFile ReleasePlatformFile() WARN_UNUSED_RESULT {
207 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
208     return ReleaseFD();
209 #elif defined(OS_WIN)
210     return ReleaseHandle();
211 #else
212 #error "Unsupported platform"
213 #endif
214   }
215 
216  private:
217   Type type_ = Type::kNone;
218 
219 #if defined(OS_WIN)
220   base::win::ScopedHandle handle_;
221 #elif defined(OS_FUCHSIA)
222   zx::handle handle_;
223 #elif defined(OS_MACOSX) && !defined(OS_IOS)
224   base::mac::ScopedMachSendRight mach_send_;
225   base::mac::ScopedMachReceiveRight mach_receive_;
226 #endif
227 
228 #if defined(OS_POSIX) || defined(OS_FUCHSIA)
229   base::ScopedFD fd_;
230 #endif
231 
232   DISALLOW_COPY_AND_ASSIGN(PlatformHandle);
233 };
234 
235 }  // namespace mojo
236 
237 #endif  // MOJO_PUBLIC_CPP_PLATFORM_PLATFORM_HANDLE_H_
238