// Copyright (c) 2015 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 "ipc/ipc_message_attachment.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "ipc/ipc_mojo_handle_attachment.h"
#include "mojo/public/cpp/system/platform_handle.h"
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
#include "base/posix/eintr_wrapper.h"
#include "ipc/ipc_platform_file_attachment_posix.h"
#endif
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include "ipc/mach_port_attachment_mac.h"
#endif
#if defined(OS_WIN)
#include "ipc/handle_attachment_win.h"
#endif
#if defined(OS_FUCHSIA)
#include "ipc/handle_attachment_fuchsia.h"
#endif
namespace IPC {
namespace {
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) {
return attachment->Owns()
? base::ScopedFD(attachment->TakePlatformFile())
: base::ScopedFD(HANDLE_EINTR(dup(attachment->file())));
}
#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
} // namespace
MessageAttachment::MessageAttachment() = default;
MessageAttachment::~MessageAttachment() = default;
mojo::ScopedHandle MessageAttachment::TakeMojoHandle() {
switch (GetType()) {
case Type::MOJO_HANDLE:
return static_cast<internal::MojoHandleAttachment*>(this)->TakeHandle();
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
case Type::PLATFORM_FILE: {
// We dup() the handles in IPC::Message to transmit.
// IPC::MessageAttachmentSet has intricate lifetime semantics for FDs, so
// just to dup()-and-own them is the safest option.
base::ScopedFD file =
TakeOrDupFile(static_cast<internal::PlatformFileAttachment*>(this));
if (!file.is_valid()) {
DPLOG(WARNING) << "Failed to dup FD to transmit.";
return mojo::ScopedHandle();
}
return mojo::WrapPlatformFile(file.release());
}
#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
#if defined(OS_MACOSX) && !defined(OS_IOS)
case Type::MACH_PORT: {
auto* attachment = static_cast<internal::MachPortAttachmentMac*>(this);
MojoPlatformHandle platform_handle = {
sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT,
static_cast<uint64_t>(attachment->get_mach_port())};
MojoHandle wrapped_handle;
if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) !=
MOJO_RESULT_OK) {
return mojo::ScopedHandle();
}
attachment->reset_mach_port_ownership();
return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
}
#elif defined(OS_FUCHSIA)
case Type::FUCHSIA_HANDLE: {
auto* attachment = static_cast<internal::HandleAttachmentFuchsia*>(this);
MojoPlatformHandle platform_handle = {
sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE,
static_cast<uint64_t>(attachment->Take())};
MojoHandle wrapped_handle;
if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) !=
MOJO_RESULT_OK) {
return mojo::ScopedHandle();
}
return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle));
}
#elif defined(OS_WIN)
case Type::WIN_HANDLE:
return mojo::WrapPlatformFile(
static_cast<internal::HandleAttachmentWin*>(this)->Take());
#endif
default:
break;
}
NOTREACHED();
return mojo::ScopedHandle();
}
// static
scoped_refptr<MessageAttachment> MessageAttachment::CreateFromMojoHandle(
mojo::ScopedHandle handle,
Type type) {
if (type == Type::MOJO_HANDLE)
return new internal::MojoHandleAttachment(std::move(handle));
MojoPlatformHandle platform_handle = {sizeof(platform_handle), 0, 0};
MojoResult unwrap_result = MojoUnwrapPlatformHandle(
handle.release().value(), nullptr, &platform_handle);
if (unwrap_result != MOJO_RESULT_OK)
return nullptr;
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
if (type == Type::PLATFORM_FILE) {
base::PlatformFile file = base::kInvalidPlatformFile;
if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
file = static_cast<base::PlatformFile>(platform_handle.value);
return new internal::PlatformFileAttachment(file);
}
#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
#if defined(OS_MACOSX) && !defined(OS_IOS)
if (type == Type::MACH_PORT) {
mach_port_t mach_port = MACH_PORT_NULL;
if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT)
mach_port = static_cast<mach_port_t>(platform_handle.value);
return new internal::MachPortAttachmentMac(
mach_port, internal::MachPortAttachmentMac::FROM_WIRE);
}
#elif defined(OS_FUCHSIA)
if (type == Type::FUCHSIA_HANDLE) {
zx::handle handle;
if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE)
handle.reset(static_cast<zx_handle_t>(platform_handle.value));
return new internal::HandleAttachmentFuchsia(std::move(handle));
}
#elif defined(OS_WIN)
if (type == Type::WIN_HANDLE) {
base::PlatformFile handle = base::kInvalidPlatformFile;
if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE)
handle = reinterpret_cast<base::PlatformFile>(platform_handle.value);
return new internal::HandleAttachmentWin(
handle, internal::HandleAttachmentWin::FROM_WIRE);
}
#endif
NOTREACHED();
return nullptr;
}
} // namespace IPC