287 lines
11 KiB
C++
287 lines
11 KiB
C++
// Copyright 2018 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "mojo/public/cpp/system/invitation.h"
|
|
|
|
#include "base/numerics/safe_conversions.h"
|
|
#include "build/build_config.h"
|
|
#include "mojo/public/c/system/invitation.h"
|
|
#include "mojo/public/c/system/platform_handle.h"
|
|
#include "mojo/public/cpp/system/platform_handle.h"
|
|
|
|
namespace mojo {
|
|
|
|
namespace {
|
|
|
|
static constexpr base::StringPiece kIsolatedPipeName = {"\0\0\0\0", 4};
|
|
|
|
void ProcessHandleToMojoProcessHandle(base::ProcessHandle target_process,
|
|
MojoPlatformProcessHandle* handle) {
|
|
handle->struct_size = sizeof(*handle);
|
|
#if defined(OS_WIN)
|
|
handle->value =
|
|
static_cast<uint64_t>(reinterpret_cast<uintptr_t>(target_process));
|
|
#else
|
|
handle->value = static_cast<uint64_t>(target_process);
|
|
#endif
|
|
}
|
|
|
|
void PlatformHandleToTransportEndpoint(
|
|
PlatformHandle platform_handle,
|
|
MojoPlatformHandle* endpoint_handle,
|
|
MojoInvitationTransportEndpoint* endpoint) {
|
|
PlatformHandle::ToMojoPlatformHandle(std::move(platform_handle),
|
|
endpoint_handle);
|
|
CHECK_NE(endpoint_handle->type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
|
|
|
|
endpoint->struct_size = sizeof(*endpoint);
|
|
endpoint->num_platform_handles = 1;
|
|
endpoint->platform_handles = endpoint_handle;
|
|
}
|
|
|
|
void RunErrorCallback(uintptr_t context,
|
|
const MojoProcessErrorDetails* details) {
|
|
auto* callback = reinterpret_cast<ProcessErrorCallback*>(context);
|
|
std::string error_message;
|
|
if (details->error_message) {
|
|
error_message =
|
|
std::string(details->error_message, details->error_message_length - 1);
|
|
callback->Run(error_message);
|
|
} else if (details->flags & MOJO_PROCESS_ERROR_FLAG_DISCONNECTED) {
|
|
delete callback;
|
|
}
|
|
}
|
|
|
|
void SendInvitation(ScopedInvitationHandle invitation,
|
|
base::ProcessHandle target_process,
|
|
PlatformHandle endpoint_handle,
|
|
MojoInvitationTransportType transport_type,
|
|
MojoSendInvitationFlags flags,
|
|
const ProcessErrorCallback& error_callback,
|
|
base::StringPiece isolated_connection_name) {
|
|
MojoPlatformProcessHandle process_handle;
|
|
ProcessHandleToMojoProcessHandle(target_process, &process_handle);
|
|
|
|
MojoPlatformHandle platform_handle;
|
|
MojoInvitationTransportEndpoint endpoint;
|
|
PlatformHandleToTransportEndpoint(std::move(endpoint_handle),
|
|
&platform_handle, &endpoint);
|
|
endpoint.type = transport_type;
|
|
|
|
MojoProcessErrorHandler error_handler = nullptr;
|
|
uintptr_t error_handler_context = 0;
|
|
if (error_callback) {
|
|
error_handler = &RunErrorCallback;
|
|
|
|
// NOTE: The allocated callback is effectively owned by the error handler,
|
|
// which will delete it on the final invocation for this context (i.e.
|
|
// process disconnection).
|
|
error_handler_context =
|
|
reinterpret_cast<uintptr_t>(new ProcessErrorCallback(error_callback));
|
|
}
|
|
|
|
MojoSendInvitationOptions options;
|
|
options.struct_size = sizeof(options);
|
|
options.flags = flags;
|
|
if (flags & MOJO_SEND_INVITATION_FLAG_ISOLATED) {
|
|
options.isolated_connection_name = isolated_connection_name.data();
|
|
options.isolated_connection_name_length =
|
|
static_cast<uint32_t>(isolated_connection_name.size());
|
|
}
|
|
MojoResult result =
|
|
MojoSendInvitation(invitation.get().value(), &process_handle, &endpoint,
|
|
error_handler, error_handler_context, &options);
|
|
// If successful, the invitation handle is already closed for us.
|
|
if (result == MOJO_RESULT_OK)
|
|
ignore_result(invitation.release());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
OutgoingInvitation::OutgoingInvitation() {
|
|
MojoHandle invitation_handle;
|
|
MojoResult result = MojoCreateInvitation(nullptr, &invitation_handle);
|
|
DCHECK_EQ(result, MOJO_RESULT_OK);
|
|
|
|
handle_.reset(InvitationHandle(invitation_handle));
|
|
}
|
|
|
|
OutgoingInvitation::OutgoingInvitation(OutgoingInvitation&& other) = default;
|
|
|
|
OutgoingInvitation::~OutgoingInvitation() = default;
|
|
|
|
OutgoingInvitation& OutgoingInvitation::operator=(OutgoingInvitation&& other) =
|
|
default;
|
|
|
|
ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(
|
|
base::StringPiece name) {
|
|
DCHECK(!name.empty());
|
|
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
|
|
MojoHandle message_pipe_handle;
|
|
MojoResult result = MojoAttachMessagePipeToInvitation(
|
|
handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
|
|
nullptr, &message_pipe_handle);
|
|
DCHECK_EQ(MOJO_RESULT_OK, result);
|
|
return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
|
|
}
|
|
|
|
ScopedMessagePipeHandle OutgoingInvitation::AttachMessagePipe(uint64_t name) {
|
|
return AttachMessagePipe(
|
|
base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
|
|
}
|
|
|
|
ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(
|
|
base::StringPiece name) {
|
|
DCHECK(!name.empty());
|
|
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
|
|
MojoHandle message_pipe_handle;
|
|
MojoResult result = MojoExtractMessagePipeFromInvitation(
|
|
handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
|
|
nullptr, &message_pipe_handle);
|
|
DCHECK_EQ(MOJO_RESULT_OK, result);
|
|
return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
|
|
}
|
|
|
|
ScopedMessagePipeHandle OutgoingInvitation::ExtractMessagePipe(uint64_t name) {
|
|
return ExtractMessagePipe(
|
|
base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
|
|
}
|
|
|
|
// static
|
|
void OutgoingInvitation::Send(OutgoingInvitation invitation,
|
|
base::ProcessHandle target_process,
|
|
PlatformChannelEndpoint channel_endpoint,
|
|
const ProcessErrorCallback& error_callback) {
|
|
SendInvitation(std::move(invitation.handle_), target_process,
|
|
channel_endpoint.TakePlatformHandle(),
|
|
MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
|
|
MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
|
|
}
|
|
|
|
// static
|
|
void OutgoingInvitation::Send(OutgoingInvitation invitation,
|
|
base::ProcessHandle target_process,
|
|
PlatformChannelServerEndpoint server_endpoint,
|
|
const ProcessErrorCallback& error_callback) {
|
|
SendInvitation(std::move(invitation.handle_), target_process,
|
|
server_endpoint.TakePlatformHandle(),
|
|
MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
|
|
MOJO_SEND_INVITATION_FLAG_NONE, error_callback, "");
|
|
}
|
|
|
|
// static
|
|
ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
|
|
PlatformChannelEndpoint channel_endpoint,
|
|
base::StringPiece connection_name) {
|
|
mojo::OutgoingInvitation invitation;
|
|
ScopedMessagePipeHandle pipe =
|
|
invitation.AttachMessagePipe(kIsolatedPipeName);
|
|
SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
|
|
channel_endpoint.TakePlatformHandle(),
|
|
MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
|
|
MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
|
|
connection_name);
|
|
return pipe;
|
|
}
|
|
|
|
// static
|
|
ScopedMessagePipeHandle OutgoingInvitation::SendIsolated(
|
|
PlatformChannelServerEndpoint server_endpoint,
|
|
base::StringPiece connection_name) {
|
|
mojo::OutgoingInvitation invitation;
|
|
ScopedMessagePipeHandle pipe =
|
|
invitation.AttachMessagePipe(kIsolatedPipeName);
|
|
SendInvitation(std::move(invitation.handle_), base::kNullProcessHandle,
|
|
server_endpoint.TakePlatformHandle(),
|
|
MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER,
|
|
MOJO_SEND_INVITATION_FLAG_ISOLATED, ProcessErrorCallback(),
|
|
connection_name);
|
|
return pipe;
|
|
}
|
|
|
|
IncomingInvitation::IncomingInvitation() = default;
|
|
|
|
IncomingInvitation::IncomingInvitation(IncomingInvitation&& other) = default;
|
|
|
|
IncomingInvitation::IncomingInvitation(ScopedInvitationHandle handle)
|
|
: handle_(std::move(handle)) {}
|
|
|
|
IncomingInvitation::~IncomingInvitation() = default;
|
|
|
|
IncomingInvitation& IncomingInvitation::operator=(IncomingInvitation&& other) =
|
|
default;
|
|
|
|
// static
|
|
IncomingInvitation IncomingInvitation::Accept(
|
|
PlatformChannelEndpoint channel_endpoint) {
|
|
MojoPlatformHandle endpoint_handle;
|
|
PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
|
|
&endpoint_handle);
|
|
CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
|
|
|
|
MojoInvitationTransportEndpoint transport_endpoint;
|
|
transport_endpoint.struct_size = sizeof(transport_endpoint);
|
|
transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
|
|
transport_endpoint.num_platform_handles = 1;
|
|
transport_endpoint.platform_handles = &endpoint_handle;
|
|
|
|
MojoHandle invitation_handle;
|
|
MojoResult result =
|
|
MojoAcceptInvitation(&transport_endpoint, nullptr, &invitation_handle);
|
|
if (result != MOJO_RESULT_OK)
|
|
return IncomingInvitation();
|
|
|
|
return IncomingInvitation(
|
|
ScopedInvitationHandle(InvitationHandle(invitation_handle)));
|
|
}
|
|
|
|
// static
|
|
ScopedMessagePipeHandle IncomingInvitation::AcceptIsolated(
|
|
PlatformChannelEndpoint channel_endpoint) {
|
|
MojoPlatformHandle endpoint_handle;
|
|
PlatformHandle::ToMojoPlatformHandle(channel_endpoint.TakePlatformHandle(),
|
|
&endpoint_handle);
|
|
CHECK_NE(endpoint_handle.type, MOJO_PLATFORM_HANDLE_TYPE_INVALID);
|
|
|
|
MojoInvitationTransportEndpoint transport_endpoint;
|
|
transport_endpoint.struct_size = sizeof(transport_endpoint);
|
|
transport_endpoint.type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL;
|
|
transport_endpoint.num_platform_handles = 1;
|
|
transport_endpoint.platform_handles = &endpoint_handle;
|
|
|
|
MojoAcceptInvitationOptions options;
|
|
options.struct_size = sizeof(options);
|
|
options.flags = MOJO_ACCEPT_INVITATION_FLAG_ISOLATED;
|
|
|
|
MojoHandle invitation_handle;
|
|
MojoResult result =
|
|
MojoAcceptInvitation(&transport_endpoint, &options, &invitation_handle);
|
|
if (result != MOJO_RESULT_OK)
|
|
return ScopedMessagePipeHandle();
|
|
|
|
IncomingInvitation invitation{
|
|
ScopedInvitationHandle(InvitationHandle(invitation_handle))};
|
|
return invitation.ExtractMessagePipe(kIsolatedPipeName);
|
|
}
|
|
|
|
ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(
|
|
base::StringPiece name) {
|
|
DCHECK(!name.empty());
|
|
DCHECK(base::IsValueInRangeForNumericType<uint32_t>(name.size()));
|
|
DCHECK(handle_.is_valid());
|
|
MojoHandle message_pipe_handle;
|
|
MojoResult result = MojoExtractMessagePipeFromInvitation(
|
|
handle_.get().value(), name.data(), static_cast<uint32_t>(name.size()),
|
|
nullptr, &message_pipe_handle);
|
|
DCHECK_EQ(MOJO_RESULT_OK, result);
|
|
return ScopedMessagePipeHandle(MessagePipeHandle(message_pipe_handle));
|
|
}
|
|
|
|
ScopedMessagePipeHandle IncomingInvitation::ExtractMessagePipe(uint64_t name) {
|
|
return ExtractMessagePipe(
|
|
base::StringPiece(reinterpret_cast<const char*>(&name), sizeof(name)));
|
|
}
|
|
|
|
} // namespace mojo
|