• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 <stdint.h>
6 #include <string.h>
7 
8 #include <algorithm>
9 #include <string>
10 #include <vector>
11 
12 #include "base/files/file.h"
13 #include "base/files/file_util.h"
14 #include "base/memory/shared_memory.h"
15 #include "base/process/process_handle.h"
16 #include "build/build_config.h"
17 #include "mojo/core/test/mojo_test_base.h"
18 #include "mojo/public/c/system/platform_handle.h"
19 #include "mojo/public/cpp/system/message_pipe.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 
22 #if defined(OS_WIN)
23 #include <windows.h>
24 #endif
25 
26 #if defined(OS_WIN)
27 #define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE
28 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
29 #define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR
30 #endif
31 
32 #if defined(OS_FUCHSIA)
33 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE \
34   MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE
35 #elif defined(OS_MACOSX) && !defined(OS_IOS)
36 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT
37 #elif defined(OS_WIN) || defined(OS_POSIX)
38 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE SIMPLE_PLATFORM_HANDLE_TYPE
39 #endif
40 
PlatformHandleValueFromPlatformFile(base::PlatformFile file)41 uint64_t PlatformHandleValueFromPlatformFile(base::PlatformFile file) {
42 #if defined(OS_WIN)
43   return reinterpret_cast<uint64_t>(file);
44 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
45   return static_cast<uint64_t>(file);
46 #endif
47 }
48 
PlatformFileFromPlatformHandleValue(uint64_t value)49 base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) {
50 #if defined(OS_WIN)
51   return reinterpret_cast<base::PlatformFile>(value);
52 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
53   return static_cast<base::PlatformFile>(value);
54 #endif
55 }
56 
57 namespace mojo {
58 namespace core {
59 namespace {
60 
61 using PlatformWrapperTest = test::MojoTestBase;
62 
TEST_F(PlatformWrapperTest,WrapPlatformHandle)63 TEST_F(PlatformWrapperTest, WrapPlatformHandle) {
64   // Create a temporary file and write a message to it.
65   base::FilePath temp_file_path;
66   ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path));
67   const std::string kMessage = "Hello, world!";
68   EXPECT_EQ(base::WriteFile(temp_file_path, kMessage.data(),
69                             static_cast<int>(kMessage.size())),
70             static_cast<int>(kMessage.size()));
71 
72   RunTestClient("ReadPlatformFile", [&](MojoHandle h) {
73     // Open the temporary file for reading, wrap its handle, and send it to
74     // the child along with the expected message to be read.
75     base::File file(temp_file_path,
76                     base::File::FLAG_OPEN | base::File::FLAG_READ);
77     EXPECT_TRUE(file.IsValid());
78 
79     MojoHandle wrapped_handle;
80     MojoPlatformHandle os_file;
81     os_file.struct_size = sizeof(MojoPlatformHandle);
82     os_file.type = SIMPLE_PLATFORM_HANDLE_TYPE;
83     os_file.value =
84         PlatformHandleValueFromPlatformFile(file.TakePlatformFile());
85     EXPECT_EQ(MOJO_RESULT_OK,
86               MojoWrapPlatformHandle(&os_file, nullptr, &wrapped_handle));
87 
88     WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1);
89   });
90 
91   base::DeleteFile(temp_file_path, false);
92 }
93 
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile,PlatformWrapperTest,h)94 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile, PlatformWrapperTest, h) {
95   // Read a message and a wrapped file handle; unwrap the handle.
96   MojoHandle wrapped_handle;
97   std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1);
98 
99   MojoPlatformHandle platform_handle;
100   platform_handle.struct_size = sizeof(MojoPlatformHandle);
101   ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformHandle(wrapped_handle, nullptr,
102                                                      &platform_handle));
103   EXPECT_EQ(SIMPLE_PLATFORM_HANDLE_TYPE, platform_handle.type);
104   base::File file(PlatformFileFromPlatformHandleValue(platform_handle.value));
105 
106   // Expect to read the same message from the file.
107   std::vector<char> data(message.size());
108   EXPECT_EQ(file.ReadAtCurrentPos(data.data(), static_cast<int>(data.size())),
109             static_cast<int>(data.size()));
110   EXPECT_TRUE(std::equal(message.begin(), message.end(), data.begin()));
111 }
112 
TEST_F(PlatformWrapperTest,WrapPlatformSharedMemoryRegion)113 TEST_F(PlatformWrapperTest, WrapPlatformSharedMemoryRegion) {
114   // Allocate a new platform shared buffer and write a message into it.
115   const std::string kMessage = "Hello, world!";
116   base::SharedMemory buffer;
117   buffer.CreateAndMapAnonymous(kMessage.size());
118   CHECK(buffer.memory());
119   memcpy(buffer.memory(), kMessage.data(), kMessage.size());
120 
121   RunTestClient("ReadPlatformSharedBuffer", [&](MojoHandle h) {
122     // Wrap the shared memory handle and send it to the child along with the
123     // expected message.
124     base::SharedMemoryHandle memory_handle =
125         base::SharedMemory::DuplicateHandle(buffer.handle());
126     MojoPlatformHandle os_buffer;
127     os_buffer.struct_size = sizeof(MojoPlatformHandle);
128     os_buffer.type = SHARED_BUFFER_PLATFORM_HANDLE_TYPE;
129 #if defined(OS_WIN)
130     os_buffer.value = reinterpret_cast<uint64_t>(memory_handle.GetHandle());
131 #elif defined(OS_MACOSX) && !defined(OS_IOS)
132     os_buffer.value = static_cast<uint64_t>(memory_handle.GetMemoryObject());
133 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
134     os_buffer.value = static_cast<uint64_t>(memory_handle.GetHandle());
135 #else
136 #error Unsupported platform
137 #endif
138 
139     MojoSharedBufferGuid mojo_guid;
140     base::UnguessableToken guid = memory_handle.GetGUID();
141     mojo_guid.high = guid.GetHighForSerialization();
142     mojo_guid.low = guid.GetLowForSerialization();
143 
144     MojoHandle wrapped_handle;
145     ASSERT_EQ(MOJO_RESULT_OK,
146               MojoWrapPlatformSharedMemoryRegion(
147                   &os_buffer, 1, kMessage.size(), &mojo_guid,
148                   MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE,
149                   nullptr, &wrapped_handle));
150     WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1);
151 
152     // As a sanity check, send the GUID explicitly in a second message. We'll
153     // verify that the deserialized buffer handle holds the same GUID on the
154     // receiving end.
155     WriteMessageRaw(MessagePipeHandle(h), &mojo_guid, sizeof(mojo_guid),
156                     nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
157   });
158 }
159 
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer,PlatformWrapperTest,h)160 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer,
161                                   PlatformWrapperTest,
162                                   h) {
163   // Read a message and a wrapped shared buffer handle.
164   MojoHandle wrapped_handle;
165   std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1);
166 
167   // Check the message in the buffer
168   ExpectBufferContents(wrapped_handle, 0, message);
169 
170   // Now unwrap the buffer and verify that the base::SharedMemoryHandle also
171   // works as expected.
172   MojoPlatformHandle os_buffer;
173   os_buffer.struct_size = sizeof(MojoPlatformHandle);
174   uint32_t num_handles = 1;
175   uint64_t size;
176   MojoSharedBufferGuid mojo_guid;
177   MojoPlatformSharedMemoryRegionAccessMode access_mode;
178   ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformSharedMemoryRegion(
179                                 wrapped_handle, nullptr, &os_buffer,
180                                 &num_handles, &size, &mojo_guid, &access_mode));
181   EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE, access_mode);
182 
183   base::UnguessableToken guid =
184       base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low);
185 #if defined(OS_WIN)
186   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE, os_buffer.type);
187   base::SharedMemoryHandle memory_handle(
188       reinterpret_cast<HANDLE>(os_buffer.value), size, guid);
189 #elif defined(OS_FUCHSIA)
190   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE, os_buffer.type);
191   base::SharedMemoryHandle memory_handle(
192       static_cast<zx_handle_t>(os_buffer.value), size, guid);
193 #elif defined(OS_MACOSX) && !defined(OS_IOS)
194   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT, os_buffer.type);
195   base::SharedMemoryHandle memory_handle(
196       static_cast<mach_port_t>(os_buffer.value), size, guid);
197 #elif defined(OS_POSIX)
198   ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR, os_buffer.type);
199   base::SharedMemoryHandle memory_handle(
200       base::FileDescriptor(static_cast<int>(os_buffer.value), false), size,
201       guid);
202 #endif
203 
204   base::SharedMemory memory(memory_handle, false);
205   memory.Map(message.size());
206   ASSERT_TRUE(memory.memory());
207 
208   EXPECT_TRUE(std::equal(message.begin(), message.end(),
209                          static_cast<const char*>(memory.memory())));
210 
211   // Verify that the received buffer's internal GUID was preserved in transit.
212   EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE));
213   std::vector<uint8_t> guid_bytes;
214   EXPECT_EQ(MOJO_RESULT_OK,
215             ReadMessageRaw(MessagePipeHandle(h), &guid_bytes, nullptr,
216                            MOJO_READ_MESSAGE_FLAG_NONE));
217   EXPECT_EQ(sizeof(MojoSharedBufferGuid), guid_bytes.size());
218   auto* expected_guid =
219       reinterpret_cast<MojoSharedBufferGuid*>(guid_bytes.data());
220   EXPECT_EQ(expected_guid->high, mojo_guid.high);
221   EXPECT_EQ(expected_guid->low, mojo_guid.low);
222 }
223 
TEST_F(PlatformWrapperTest,InvalidHandle)224 TEST_F(PlatformWrapperTest, InvalidHandle) {
225   // Wrap an invalid platform handle and expect to unwrap the same.
226 
227   MojoHandle wrapped_handle;
228   MojoPlatformHandle invalid_handle;
229   invalid_handle.struct_size = sizeof(MojoPlatformHandle);
230   invalid_handle.type = MOJO_PLATFORM_HANDLE_TYPE_INVALID;
231   EXPECT_EQ(MOJO_RESULT_OK,
232             MojoWrapPlatformHandle(&invalid_handle, nullptr, &wrapped_handle));
233   EXPECT_EQ(MOJO_RESULT_OK,
234             MojoUnwrapPlatformHandle(wrapped_handle, nullptr, &invalid_handle));
235   EXPECT_EQ(MOJO_PLATFORM_HANDLE_TYPE_INVALID, invalid_handle.type);
236 }
237 
TEST_F(PlatformWrapperTest,InvalidArgument)238 TEST_F(PlatformWrapperTest, InvalidArgument) {
239   // Try to wrap an invalid MojoPlatformHandle struct and expect an error.
240   MojoHandle wrapped_handle;
241   MojoPlatformHandle platform_handle;
242   platform_handle.struct_size = 0;
243   EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
244             MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle));
245 }
246 
247 }  // namespace
248 }  // namespace core
249 }  // namespace mojo
250