// 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