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)
TakeOrDupFile(internal::PlatformFileAttachment * attachment)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
TakeMojoHandle()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
CreateFromMojoHandle(mojo::ScopedHandle handle,Type type)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