1 // Copyright (c) 2015 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 "ipc/ipc_message_attachment.h" 6 7 #include "base/files/scoped_file.h" 8 #include "base/logging.h" 9 #include "ipc/ipc_mojo_handle_attachment.h" 10 #include "mojo/public/cpp/system/platform_handle.h" 11 12 #if defined(OS_POSIX) || defined(OS_FUCHSIA) 13 #include "base/posix/eintr_wrapper.h" 14 #include "ipc/ipc_platform_file_attachment_posix.h" 15 #endif 16 17 #if defined(OS_MACOSX) && !defined(OS_IOS) 18 #include "ipc/mach_port_attachment_mac.h" 19 #endif 20 21 #if defined(OS_WIN) 22 #include "ipc/handle_attachment_win.h" 23 #endif 24 25 #if defined(OS_FUCHSIA) 26 #include "ipc/handle_attachment_fuchsia.h" 27 #endif 28 29 namespace IPC { 30 31 namespace { 32 33 #if defined(OS_POSIX) || defined(OS_FUCHSIA) 34 base::ScopedFD TakeOrDupFile(internal::PlatformFileAttachment* attachment) { 35 return attachment->Owns() 36 ? base::ScopedFD(attachment->TakePlatformFile()) 37 : base::ScopedFD(HANDLE_EINTR(dup(attachment->file()))); 38 } 39 #endif // defined(OS_POSIX) || defined(OS_FUCHSIA) 40 41 } // namespace 42 43 MessageAttachment::MessageAttachment() = default; 44 45 MessageAttachment::~MessageAttachment() = default; 46 47 mojo::ScopedHandle MessageAttachment::TakeMojoHandle() { 48 switch (GetType()) { 49 case Type::MOJO_HANDLE: 50 return static_cast<internal::MojoHandleAttachment*>(this)->TakeHandle(); 51 52 #if defined(OS_POSIX) || defined(OS_FUCHSIA) 53 case Type::PLATFORM_FILE: { 54 // We dup() the handles in IPC::Message to transmit. 55 // IPC::MessageAttachmentSet has intricate lifetime semantics for FDs, so 56 // just to dup()-and-own them is the safest option. 57 base::ScopedFD file = 58 TakeOrDupFile(static_cast<internal::PlatformFileAttachment*>(this)); 59 if (!file.is_valid()) { 60 DPLOG(WARNING) << "Failed to dup FD to transmit."; 61 return mojo::ScopedHandle(); 62 } 63 return mojo::WrapPlatformFile(file.release()); 64 } 65 #endif // defined(OS_POSIX) || defined(OS_FUCHSIA) 66 67 #if defined(OS_MACOSX) && !defined(OS_IOS) 68 case Type::MACH_PORT: { 69 auto* attachment = static_cast<internal::MachPortAttachmentMac*>(this); 70 MojoPlatformHandle platform_handle = { 71 sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT, 72 static_cast<uint64_t>(attachment->get_mach_port())}; 73 MojoHandle wrapped_handle; 74 if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) != 75 MOJO_RESULT_OK) { 76 return mojo::ScopedHandle(); 77 } 78 attachment->reset_mach_port_ownership(); 79 return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle)); 80 } 81 #elif defined(OS_FUCHSIA) 82 case Type::FUCHSIA_HANDLE: { 83 auto* attachment = static_cast<internal::HandleAttachmentFuchsia*>(this); 84 MojoPlatformHandle platform_handle = { 85 sizeof(platform_handle), MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE, 86 static_cast<uint64_t>(attachment->Take())}; 87 MojoHandle wrapped_handle; 88 if (MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle) != 89 MOJO_RESULT_OK) { 90 return mojo::ScopedHandle(); 91 } 92 return mojo::MakeScopedHandle(mojo::Handle(wrapped_handle)); 93 } 94 #elif defined(OS_WIN) 95 case Type::WIN_HANDLE: 96 return mojo::WrapPlatformFile( 97 static_cast<internal::HandleAttachmentWin*>(this)->Take()); 98 #endif 99 default: 100 break; 101 } 102 NOTREACHED(); 103 return mojo::ScopedHandle(); 104 } 105 106 // static 107 scoped_refptr<MessageAttachment> MessageAttachment::CreateFromMojoHandle( 108 mojo::ScopedHandle handle, 109 Type type) { 110 if (type == Type::MOJO_HANDLE) 111 return new internal::MojoHandleAttachment(std::move(handle)); 112 113 MojoPlatformHandle platform_handle = {sizeof(platform_handle), 0, 0}; 114 MojoResult unwrap_result = MojoUnwrapPlatformHandle( 115 handle.release().value(), nullptr, &platform_handle); 116 if (unwrap_result != MOJO_RESULT_OK) 117 return nullptr; 118 119 #if defined(OS_POSIX) || defined(OS_FUCHSIA) 120 if (type == Type::PLATFORM_FILE) { 121 base::PlatformFile file = base::kInvalidPlatformFile; 122 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR) 123 file = static_cast<base::PlatformFile>(platform_handle.value); 124 return new internal::PlatformFileAttachment(file); 125 } 126 #endif // defined(OS_POSIX) || defined(OS_FUCHSIA) 127 128 #if defined(OS_MACOSX) && !defined(OS_IOS) 129 if (type == Type::MACH_PORT) { 130 mach_port_t mach_port = MACH_PORT_NULL; 131 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT) 132 mach_port = static_cast<mach_port_t>(platform_handle.value); 133 return new internal::MachPortAttachmentMac( 134 mach_port, internal::MachPortAttachmentMac::FROM_WIRE); 135 } 136 #elif defined(OS_FUCHSIA) 137 if (type == Type::FUCHSIA_HANDLE) { 138 zx::handle handle; 139 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE) 140 handle.reset(static_cast<zx_handle_t>(platform_handle.value)); 141 return new internal::HandleAttachmentFuchsia(std::move(handle)); 142 } 143 #elif defined(OS_WIN) 144 if (type == Type::WIN_HANDLE) { 145 base::PlatformFile handle = base::kInvalidPlatformFile; 146 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE) 147 handle = reinterpret_cast<base::PlatformFile>(platform_handle.value); 148 return new internal::HandleAttachmentWin( 149 handle, internal::HandleAttachmentWin::FROM_WIRE); 150 } 151 #endif 152 NOTREACHED(); 153 return nullptr; 154 } 155 156 } // namespace IPC 157