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/system/invitation.h"
6
7 #include "base/numerics/safe_conversions.h"
8 #include "build/build_config.h"
9 #include "mojo/public/c/system/invitation.h"
10 #include "mojo/public/c/system/platform_handle.h"
11 #include "mojo/public/cpp/system/platform_handle.h"
12
13 namespace mojo {
14
15 namespace {
16
17 static constexpr base::StringPiece kIsolatedPipeName = {"\0\0\0\0", 4};
18
ProcessHandleToMojoProcessHandle(base::ProcessHandle target_process,MojoPlatformProcessHandle * handle)19 void ProcessHandleToMojoProcessHandle(base::ProcessHandle target_process,
20 MojoPlatformProcessHandle* handle) {
21 handle->struct_size = sizeof(*handle);
22 #if defined(OS_WIN)
23 handle->value =
24 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(target_process));
25 #else
26 handle->value = static_cast<uint64_t>(target_process);
27 #endif
28 }
29
PlatformHandleToTransportEndpoint(PlatformHandle platform_handle,MojoPlatformHandle * endpoint_handle,MojoInvitationTransportEndpoint * endpoint)30 void PlatformHandleToTransportEndpoint(
31 PlatformHandle platform_handle,
32 MojoPlatformHandle* endpoint_handle,
33 MojoInvitationTransportEndpoint* endpoint) {
34 PlatformHandle::ToMojoPlatformHandle(std::move(platform_handle),
35 endpoint_handle);
36 CHECK_NE(endpoint_handle->type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
37
38 endpoint->struct_size = sizeof(*endpoint);
39 endpoint->num_platform_handles = 1;
40 endpoint->platform_handles = endpoint_handle;
41 }
42
RunErrorCallback(uintptr_t context,const MojoProcessErrorDetails * details)43 void RunErrorCallback(uintptr_t context,
44 const MojoProcessErrorDetails* details) {
45 auto* callback = reinterpret_cast<ProcessErrorCallback*>(context);
46 std::string error_message;
47 if (details->error_message) {
48 error_message =
49 std::string(details->error_message, details->error_message_length);
50 callback->Run(error_message);
51 } else if (details->flags & MOJO_PROCESS_ERROR_FLAG_DISCONNECTED) {
52 delete callback;
53 }
54 }
55
SendInvitation(ScopedInvitationHandle invitation,base::ProcessHandle target_process,PlatformHandle endpoint_handle,MojoInvitationTransportType transport_type,MojoSendInvitationFlags flags,const ProcessErrorCallback & error_callback,base::StringPiece isolated_connection_name)56 void SendInvitation(ScopedInvitationHandle invitation,
57 base::ProcessHandle target_process,
58 PlatformHandle endpoint_handle,
59 MojoInvitationTransportType transport_type,
60 MojoSendInvitationFlags flags,
61 const ProcessErrorCallback& error_callback,
62 base::StringPiece isolated_connection_name) {
63 MojoPlatformProcessHandle process_handle;
64 ProcessHandleToMojoProcessHandle(target_process, &process_handle);
65
66 MojoPlatformHandle platform_handle;
67 MojoInvitationTransportEndpoint endpoint;
68 PlatformHandleToTransportEndpoint(std::move(endpoint_handle),
69 &platform_handle, &endpoint);
70 endpoint.type = transport_type;
71
72 MojoProcessErrorHandler error_handler = nullptr;
73 uintptr_t error_handler_context = 0;
74 if (error_callback) {
75 error_handler = &RunErrorCallback;
76
77 // NOTE: The allocated callback is effectively owned by the error handler,
78 // which will delete it on the final invocation for this context (i.e.
79 // process disconnection).
80 error_handler_context =
81 reinterpret_cast<uintptr_t>(new ProcessErrorCallback(error_callback));
82 }
83
84 MojoSendInvitationOptions options;
85 options.struct_size = sizeof(options);
86 options.flags = flags;
87 if (flags & MOJO_SEND_INVITATION_FLAG_ISOLATED) {
88 options.isolated_connection_name = isolated_connection_name.data();
89 options.isolated_connection_name_length =
90 static_cast<uint32_t>(isolated_connection_name.size());
91 }
92 MojoResult result =
93 MojoSendInvitation(invitation.get().value(), &process_handle, &endpoint,
94 error_handler, error_handler_context, &options);
95 // If successful, the invitation handle is already closed for us.
96 if (result == MOJO_RESULT_OK)
97 ignore_result(invitation.release());
98 }
99
100 } // namespace
101
OutgoingInvitation()102 OutgoingInvitation::OutgoingInvitation() {
103 MojoHandle invitation_handle;
104 MojoResult result = MojoCreateInvitation(nullptr, &invitation_handle);
105 DCHECK_EQ(result, MOJO_RESULT_OK);
106
107 handle_.reset(InvitationHandle(invitation_handle));
108 }
109
110 OutgoingInvitation::OutgoingInvitation(OutgoingInvitation&& other) = default;
111
112 OutgoingInvitation::~OutgoingInvitation() = default;
113
114 OutgoingInvitation& OutgoingInvitation::operator=(OutgoingInvitation&& other) =
115 default;
116
AttachMessagePipe(base::StringPiece name)117 ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(
118 base::StringPiece name) {
119 DCHECK(!name.empty());
120 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
121 MojoHandle message_pipe_handle;
122 MojoResult result = MojoAttachMessagePipeToInvitation(
123 handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
124 nullptr, &message_pipe_handle);
125 DCHECK_EQ(MOJO_RESULT_OK, result);
126 return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
127 }
128
AttachMessagePipe(uint64_t name)129 ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(uint64_t name) {
130 return AttachMessagePipe(
131 base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
132 }
133
ExtractMessagePipe(base::StringPiece name)134 ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(
135 base::StringPiece name) {
136 DCHECK(!name.empty());
137 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
138 MojoHandle message_pipe_handle;
139 MojoResult result = MojoExtractMessagePipeFromInvitation(
140 handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
141 nullptr, &message_pipe_handle);
142 DCHECK_EQ(MOJO_RESULT_OK, result);
143 return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
144 }
145
ExtractMessagePipe(uint64_t name)146 ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(uint64_t name) {
147 return ExtractMessagePipe(
148 base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
149 }
150
151 // static
Send(OutgoingInvitation invitation,base::ProcessHandle target_process,PlatformChannelEndpoint channel_endpoint,const ProcessErrorCallback & error_callback)152 void OutgoingInvitation::Send(OutgoingInvitation invitation,
153 base::ProcessHandle target_process,
154 PlatformChannelEndpoint channel_endpoint,
155 const ProcessErrorCallback& error_callback) {
156 SendInvitation(std::move(invitation.handle_), target_process,
157 channel_endpoint.TakePlatformHandle(),
158 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
159 MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
160 }
161
162 // static
Send(OutgoingInvitation invitation,base::ProcessHandle target_process,PlatformChannelServerEndpoint server_endpoint,const ProcessErrorCallback & error_callback)163 void OutgoingInvitation::Send(OutgoingInvitation invitation,
164 base::ProcessHandle target_process,
165 PlatformChannelServerEndpoint server_endpoint,
166 const ProcessErrorCallback& error_callback) {
167 SendInvitation(std::move(invitation.handle_), target_process,
168 server_endpoint.TakePlatformHandle(),
169 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
170 MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
171 }
172
173 // static
SendAsync(OutgoingInvitation invitation,base::ProcessHandle target_process,PlatformChannelEndpoint channel_endpoint,const ProcessErrorCallback & error_callback)174 void OutgoingInvitation::SendAsync(OutgoingInvitation invitation,
175 base::ProcessHandle target_process,
176 PlatformChannelEndpoint channel_endpoint,
177 const ProcessErrorCallback& error_callback) {
178 SendInvitation(std::move(invitation.handle_), target_process,
179 channel_endpoint.TakePlatformHandle(),
180 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC,
181 MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
182 }
183
184 // static
SendIsolated(PlatformChannelEndpoint channel_endpoint,base::StringPiece connection_name)185 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
186 PlatformChannelEndpoint channel_endpoint,
187 base::StringPiece connection_name) {
188 mojo::OutgoingInvitation invitation;
189 ScopedMessagePipeHandle pipe =
190 invitation.AttachMessagePipe(kIsolatedPipeName);
191 SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
192 channel_endpoint.TakePlatformHandle(),
193 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
194 MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
195 connection_name);
196 return pipe;
197 }
198
199 // static
SendIsolated(PlatformChannelServerEndpoint server_endpoint,base::StringPiece connection_name)200 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
201 PlatformChannelServerEndpoint server_endpoint,
202 base::StringPiece connection_name) {
203 mojo::OutgoingInvitation invitation;
204 ScopedMessagePipeHandle pipe =
205 invitation.AttachMessagePipe(kIsolatedPipeName);
206 SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
207 server_endpoint.TakePlatformHandle(),
208 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
209 MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
210 connection_name);
211 return pipe;
212 }
213
214 IncomingInvitation::IncomingInvitation() = default;
215
216 IncomingInvitation::IncomingInvitation(IncomingInvitation&& other) = default;
217
IncomingInvitation(ScopedInvitationHandle handle)218 IncomingInvitation::IncomingInvitation(ScopedInvitationHandle handle)
219 : handle_(std::move(handle)) {}
220
221 IncomingInvitation::~IncomingInvitation() = default;
222
223 IncomingInvitation& IncomingInvitation::operator=(IncomingInvitation&& other) =
224 default;
225
226 // static
Accept(PlatformChannelEndpoint channel_endpoint,MojoAcceptInvitationFlags flags)227 IncomingInvitation IncomingInvitation::Accept(
228 PlatformChannelEndpoint channel_endpoint,
229 MojoAcceptInvitationFlags flags) {
230 MojoPlatformHandle endpoint_handle;
231 PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
232 &endpoint_handle);
233 CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
234
235 MojoInvitationTransportEndpoint transport_endpoint;
236 transport_endpoint.struct_size = sizeof(transport_endpoint);
237 transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
238 transport_endpoint.num_platform_handles = 1;
239 transport_endpoint.platform_handles = &endpoint_handle;
240
241 MojoAcceptInvitationOptions options;
242 options.struct_size = sizeof(options);
243 options.flags = flags;
244
245 MojoHandle invitation_handle;
246 MojoResult result =
247 MojoAcceptInvitation(&transport_endpoint, &options, &invitation_handle);
248 if (result != MOJO_RESULT_OK)
249 return IncomingInvitation();
250
251 return IncomingInvitation(
252 ScopedInvitationHandle(InvitationHandle(invitation_handle)));
253 }
254
255 // static
AcceptAsync(PlatformChannelEndpoint channel_endpoint)256 IncomingInvitation IncomingInvitation::AcceptAsync(
257 PlatformChannelEndpoint channel_endpoint) {
258 MojoPlatformHandle endpoint_handle;
259 PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
260 &endpoint_handle);
261 CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
262
263 MojoInvitationTransportEndpoint transport_endpoint;
264 transport_endpoint.struct_size = sizeof(transport_endpoint);
265 transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_ASYNC;
266 transport_endpoint.num_platform_handles = 1;
267 transport_endpoint.platform_handles = &endpoint_handle;
268
269 MojoHandle invitation_handle;
270 MojoResult result =
271 MojoAcceptInvitation(&transport_endpoint, nullptr, &invitation_handle);
272 if (result != MOJO_RESULT_OK)
273 return IncomingInvitation();
274
275 return IncomingInvitation(
276 ScopedInvitationHandle(InvitationHandle(invitation_handle)));
277 }
278
279 // static
AcceptIsolated(PlatformChannelEndpoint channel_endpoint)280 ScopedMessagePipeHandle IncomingInvitation::AcceptIsolated(
281 PlatformChannelEndpoint channel_endpoint) {
282 MojoPlatformHandle endpoint_handle;
283 PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
284 &endpoint_handle);
285 CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
286
287 MojoInvitationTransportEndpoint transport_endpoint;
288 transport_endpoint.struct_size = sizeof(transport_endpoint);
289 transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
290 transport_endpoint.num_platform_handles = 1;
291 transport_endpoint.platform_handles = &endpoint_handle;
292
293 MojoAcceptInvitationOptions options;
294 options.struct_size = sizeof(options);
295 options.flags = MOJO_ACCEPT_INVITATION_FLAG_ISOLATED;
296
297 MojoHandle invitation_handle;
298 MojoResult result =
299 MojoAcceptInvitation(&transport_endpoint, &options, &invitation_handle);
300 if (result != MOJO_RESULT_OK)
301 return ScopedMessagePipeHandle();
302
303 IncomingInvitation invitation{
304 ScopedInvitationHandle(InvitationHandle(invitation_handle))};
305 return invitation.ExtractMessagePipe(kIsolatedPipeName);
306 }
307
ExtractMessagePipe(base::StringPiece name)308 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(
309 base::StringPiece name) {
310 DCHECK(!name.empty());
311 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
312 DCHECK(handle_.is_valid());
313 MojoHandle message_pipe_handle;
314 MojoResult result = MojoExtractMessagePipeFromInvitation(
315 handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
316 nullptr, &message_pipe_handle);
317 DCHECK_EQ(MOJO_RESULT_OK, result);
318 return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
319 }
320
ExtractMessagePipe(uint64_t name)321 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(uint64_t name) {
322 return ExtractMessagePipe(
323 base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
324 }
325
326 } // namespace mojo
327