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