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 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 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 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 - 1); 50 callback->Run(error_message); 51 } else if (details->flags & MOJO_PROCESS_ERROR_FLAG_DISCONNECTED) { 52 delete callback; 53 } 54 } 55 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 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 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 129 ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(uint64_t name) { 130 return AttachMessagePipe( 131 base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name))); 132 } 133 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 146 ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(uint64_t name) { 147 return ExtractMessagePipe( 148 base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name))); 149 } 150 151 // static 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 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 174 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated( 175 PlatformChannelEndpoint channel_endpoint, 176 base::StringPiece connection_name) { 177 mojo::OutgoingInvitation invitation; 178 ScopedMessagePipeHandle pipe = 179 invitation.AttachMessagePipe(kIsolatedPipeName); 180 SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle, 181 channel_endpoint.TakePlatformHandle(), 182 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL, 183 MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(), 184 connection_name); 185 return pipe; 186 } 187 188 // static 189 ScopedMessagePipeHandle OutgoingInvitation::SendIsolated( 190 PlatformChannelServerEndpoint server_endpoint, 191 base::StringPiece connection_name) { 192 mojo::OutgoingInvitation invitation; 193 ScopedMessagePipeHandle pipe = 194 invitation.AttachMessagePipe(kIsolatedPipeName); 195 SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle, 196 server_endpoint.TakePlatformHandle(), 197 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER, 198 MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(), 199 connection_name); 200 return pipe; 201 } 202 203 IncomingInvitation::IncomingInvitation() = default; 204 205 IncomingInvitation::IncomingInvitation(IncomingInvitation&& other) = default; 206 207 IncomingInvitation::IncomingInvitation(ScopedInvitationHandle handle) 208 : handle_(std::move(handle)) {} 209 210 IncomingInvitation::~IncomingInvitation() = default; 211 212 IncomingInvitation& IncomingInvitation::operator=(IncomingInvitation&& other) = 213 default; 214 215 // static 216 IncomingInvitation IncomingInvitation::Accept( 217 PlatformChannelEndpoint channel_endpoint) { 218 MojoPlatformHandle endpoint_handle; 219 PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(), 220 &endpoint_handle); 221 CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID); 222 223 MojoInvitationTransportEndpoint transport_endpoint; 224 transport_endpoint.struct_size = sizeof(transport_endpoint); 225 transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL; 226 transport_endpoint.num_platform_handles = 1; 227 transport_endpoint.platform_handles = &endpoint_handle; 228 229 MojoHandle invitation_handle; 230 MojoResult result = 231 MojoAcceptInvitation(&transport_endpoint, nullptr, &invitation_handle); 232 if (result != MOJO_RESULT_OK) 233 return IncomingInvitation(); 234 235 return IncomingInvitation( 236 ScopedInvitationHandle(InvitationHandle(invitation_handle))); 237 } 238 239 // static 240 ScopedMessagePipeHandle IncomingInvitation::AcceptIsolated( 241 PlatformChannelEndpoint channel_endpoint) { 242 MojoPlatformHandle endpoint_handle; 243 PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(), 244 &endpoint_handle); 245 CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID); 246 247 MojoInvitationTransportEndpoint transport_endpoint; 248 transport_endpoint.struct_size = sizeof(transport_endpoint); 249 transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL; 250 transport_endpoint.num_platform_handles = 1; 251 transport_endpoint.platform_handles = &endpoint_handle; 252 253 MojoAcceptInvitationOptions options; 254 options.struct_size = sizeof(options); 255 options.flags = MOJO_ACCEPT_INVITATION_FLAG_ISOLATED; 256 257 MojoHandle invitation_handle; 258 MojoResult result = 259 MojoAcceptInvitation(&transport_endpoint, &options, &invitation_handle); 260 if (result != MOJO_RESULT_OK) 261 return ScopedMessagePipeHandle(); 262 263 IncomingInvitation invitation{ 264 ScopedInvitationHandle(InvitationHandle(invitation_handle))}; 265 return invitation.ExtractMessagePipe(kIsolatedPipeName); 266 } 267 268 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe( 269 base::StringPiece name) { 270 DCHECK(!name.empty()); 271 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size())); 272 DCHECK(handle_.is_valid()); 273 MojoHandle message_pipe_handle; 274 MojoResult result = MojoExtractMessagePipeFromInvitation( 275 handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()), 276 nullptr, &message_pipe_handle); 277 DCHECK_EQ(MOJO_RESULT_OK, result); 278 return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle)); 279 } 280 281 ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(uint64_t name) { 282 return ExtractMessagePipe( 283 base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name))); 284 } 285 286 } // namespace mojo 287