1 // Copyright 2013 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 <stddef.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/bind.h"
15 #include "base/containers/hash_tables.h"
16 #include "base/files/file_path.h"
17 #include "base/files/file_util.h"
18 #include "base/files/scoped_file.h"
19 #include "base/files/scoped_temp_dir.h"
20 #include "base/logging.h"
21 #include "base/message_loop/message_loop.h"
22 #include "base/run_loop.h"
23 #include "base/strings/string_split.h"
24 #include "build/build_config.h"
25 #include "mojo/core/handle_signals_state.h"
26 #include "mojo/core/test/mojo_test_base.h"
27 #include "mojo/core/test/test_utils.h"
28 #include "mojo/core/test_utils.h"
29 #include "mojo/public/c/system/buffer.h"
30 #include "mojo/public/c/system/functions.h"
31 #include "mojo/public/c/system/types.h"
32 #include "mojo/public/cpp/system/message_pipe.h"
33 #include "mojo/public/cpp/system/platform_handle.h"
34 #include "mojo/public/cpp/system/simple_watcher.h"
35 #include "mojo/public/cpp/system/wait.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37
38 namespace mojo {
39 namespace core {
40 namespace {
41
42 // Temporary helpers to avoid tons of churn as old APIs are removed. These
43 // support only enough of a subset of the old APIs to satisfy the usage in these
44 // tests.
45 //
46 // TODO(rockot): Remove these.
MojoReadMessage(MojoHandle pipe,void * out_bytes,uint32_t * num_bytes,MojoHandle * out_handles,uint32_t * num_handles,MojoReadMessageFlags flags)47 MojoResult MojoReadMessage(MojoHandle pipe,
48 void* out_bytes,
49 uint32_t* num_bytes,
50 MojoHandle* out_handles,
51 uint32_t* num_handles,
52 MojoReadMessageFlags flags) {
53 std::vector<uint8_t> bytes;
54 std::vector<ScopedHandle> handles;
55 MojoResult rv =
56 ReadMessageRaw(MessagePipeHandle(pipe), &bytes, &handles, flags);
57 if (rv != MOJO_RESULT_OK)
58 return rv;
59
60 if (num_bytes)
61 *num_bytes = static_cast<uint32_t>(bytes.size());
62 if (!bytes.empty()) {
63 CHECK(out_bytes && num_bytes && *num_bytes >= bytes.size());
64 memcpy(out_bytes, bytes.data(), bytes.size());
65 }
66
67 if (num_handles)
68 *num_handles = static_cast<uint32_t>(handles.size());
69 if (!handles.empty()) {
70 CHECK(out_handles && num_handles && *num_handles >= handles.size());
71 for (size_t i = 0; i < handles.size(); ++i)
72 out_handles[i] = handles[i].release().value();
73 }
74 return MOJO_RESULT_OK;
75 }
76
MojoWriteMessage(MojoHandle pipe,const void * bytes,uint32_t num_bytes,const MojoHandle * handles,uint32_t num_handles,MojoWriteMessageFlags flags)77 MojoResult MojoWriteMessage(MojoHandle pipe,
78 const void* bytes,
79 uint32_t num_bytes,
80 const MojoHandle* handles,
81 uint32_t num_handles,
82 MojoWriteMessageFlags flags) {
83 return WriteMessageRaw(MessagePipeHandle(pipe), bytes, num_bytes, handles,
84 num_handles, flags);
85 }
86
87 class MultiprocessMessagePipeTest : public test::MojoTestBase {
88 protected:
89 // Convenience class for tests which will control command-driven children.
90 // See the CommandDrivenClient definition below.
91 class CommandDrivenClientController {
92 public:
CommandDrivenClientController(MojoHandle h)93 explicit CommandDrivenClientController(MojoHandle h) : h_(h) {}
94
Send(const std::string & command)95 void Send(const std::string& command) {
96 WriteMessage(h_, command);
97 EXPECT_EQ("ok", ReadMessage(h_));
98 }
99
SendHandle(const std::string & name,MojoHandle p)100 void SendHandle(const std::string& name, MojoHandle p) {
101 WriteMessageWithHandles(h_, "take:" + name, &p, 1);
102 EXPECT_EQ("ok", ReadMessage(h_));
103 }
104
RetrieveHandle(const std::string & name)105 MojoHandle RetrieveHandle(const std::string& name) {
106 WriteMessage(h_, "return:" + name);
107 MojoHandle p;
108 EXPECT_EQ("ok", ReadMessageWithHandles(h_, &p, 1));
109 return p;
110 }
111
Exit()112 void Exit() { WriteMessage(h_, "exit"); }
113
114 private:
115 MojoHandle h_;
116 };
117 };
118
119 class MultiprocessMessagePipeTestWithPeerSupport
120 : public MultiprocessMessagePipeTest,
121 public testing::WithParamInterface<test::MojoTestBase::LaunchType> {
122 protected:
SetUp()123 void SetUp() override {
124 test::MojoTestBase::SetUp();
125 set_launch_type(GetParam());
126 }
127 };
128
129 // For each message received, sends a reply message with the same contents
130 // repeated twice, until the other end is closed or it receives "quitquitquit"
131 // (which it doesn't reply to). It'll return the number of messages received,
132 // not including any "quitquitquit" message, modulo 100.
DEFINE_TEST_CLIENT_WITH_PIPE(EchoEcho,MultiprocessMessagePipeTest,h)133 DEFINE_TEST_CLIENT_WITH_PIPE(EchoEcho, MultiprocessMessagePipeTest, h) {
134 const std::string quitquitquit("quitquitquit");
135 int rv = 0;
136 for (;; rv = (rv + 1) % 100) {
137 // Wait for our end of the message pipe to be readable.
138 HandleSignalsState hss;
139 MojoResult result = WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss);
140 if (result != MOJO_RESULT_OK) {
141 // It was closed, probably.
142 CHECK_EQ(result, MOJO_RESULT_FAILED_PRECONDITION);
143 CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
144 CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
145 break;
146 } else {
147 CHECK((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
148 CHECK((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
149 }
150
151 std::string read_buffer(1000, '\0');
152 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
153 CHECK_EQ(MojoReadMessage(h, &read_buffer[0], &read_buffer_size, nullptr, 0,
154 MOJO_READ_MESSAGE_FLAG_NONE),
155 MOJO_RESULT_OK);
156 read_buffer.resize(read_buffer_size);
157 VLOG(2) << "Child got: " << read_buffer;
158
159 if (read_buffer == quitquitquit) {
160 VLOG(2) << "Child quitting.";
161 break;
162 }
163
164 std::string write_buffer = read_buffer + read_buffer;
165 CHECK_EQ(MojoWriteMessage(h, write_buffer.data(),
166 static_cast<uint32_t>(write_buffer.size()),
167 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
168 MOJO_RESULT_OK);
169 }
170
171 return rv;
172 }
173
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,Basic)174 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, Basic) {
175 int exit_code = RunTestClientAndGetExitCode("EchoEcho", [&](MojoHandle h) {
176 std::string hello("hello");
177 ASSERT_EQ(
178 MOJO_RESULT_OK,
179 MojoWriteMessage(h, hello.data(), static_cast<uint32_t>(hello.size()),
180 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
181
182 HandleSignalsState hss;
183 ASSERT_EQ(MOJO_RESULT_OK,
184 WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
185 // The child may or may not have closed its end of the message pipe and died
186 // (and we may or may not know it yet), so our end may or may not appear as
187 // writable.
188 EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
189 EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
190
191 std::string read_buffer(1000, '\0');
192 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
193 CHECK_EQ(MojoReadMessage(h, &read_buffer[0], &read_buffer_size, nullptr, 0,
194 MOJO_READ_MESSAGE_FLAG_NONE),
195 MOJO_RESULT_OK);
196 read_buffer.resize(read_buffer_size);
197 VLOG(2) << "Parent got: " << read_buffer;
198 ASSERT_EQ(hello + hello, read_buffer);
199
200 std::string quitquitquit("quitquitquit");
201 CHECK_EQ(MojoWriteMessage(h, quitquitquit.data(),
202 static_cast<uint32_t>(quitquitquit.size()),
203 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
204 MOJO_RESULT_OK);
205 });
206 EXPECT_EQ(1, exit_code);
207 }
208
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,QueueMessages)209 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, QueueMessages) {
210 static const size_t kNumMessages = 1001;
211 int exit_code = RunTestClientAndGetExitCode("EchoEcho", [&](MojoHandle h) {
212 for (size_t i = 0; i < kNumMessages; i++) {
213 std::string write_buffer(i, 'A' + (i % 26));
214 ASSERT_EQ(MOJO_RESULT_OK,
215 MojoWriteMessage(h, write_buffer.data(),
216 static_cast<uint32_t>(write_buffer.size()),
217 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
218 }
219
220 for (size_t i = 0; i < kNumMessages; i++) {
221 HandleSignalsState hss;
222 ASSERT_EQ(MOJO_RESULT_OK,
223 WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
224 // The child may or may not have closed its end of the message pipe and
225 // died (and we may or may not know it yet), so our end may or may not
226 // appear as writable.
227 ASSERT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
228 ASSERT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
229
230 std::string read_buffer(kNumMessages * 2, '\0');
231 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
232 ASSERT_EQ(MojoReadMessage(h, &read_buffer[0], &read_buffer_size, nullptr,
233 0, MOJO_READ_MESSAGE_FLAG_NONE),
234 MOJO_RESULT_OK);
235 read_buffer.resize(read_buffer_size);
236
237 ASSERT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer);
238 }
239
240 const std::string quitquitquit("quitquitquit");
241 ASSERT_EQ(MOJO_RESULT_OK,
242 MojoWriteMessage(h, quitquitquit.data(),
243 static_cast<uint32_t>(quitquitquit.size()),
244 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
245
246 // Wait for it to become readable, which should fail (since we sent
247 // "quitquitquit").
248 HandleSignalsState hss;
249 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
250 WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
251 ASSERT_FALSE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
252 ASSERT_FALSE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
253 });
254 EXPECT_EQ(static_cast<int>(kNumMessages % 100), exit_code);
255 }
256
DEFINE_TEST_CLIENT_WITH_PIPE(CheckSharedBuffer,MultiprocessMessagePipeTest,h)257 DEFINE_TEST_CLIENT_WITH_PIPE(CheckSharedBuffer,
258 MultiprocessMessagePipeTest,
259 h) {
260 // Wait for the first message from our parent.
261 HandleSignalsState hss;
262 CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
263 MOJO_RESULT_OK);
264 // In this test, the parent definitely doesn't close its end of the message
265 // pipe before we do.
266 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
267 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
268
269 // It should have a shared buffer.
270 std::string read_buffer(100, '\0');
271 uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
272 MojoHandle handles[10];
273 uint32_t num_handlers = arraysize(handles); // Maximum number to receive
274 CHECK_EQ(MojoReadMessage(h, &read_buffer[0], &num_bytes, &handles[0],
275 &num_handlers, MOJO_READ_MESSAGE_FLAG_NONE),
276 MOJO_RESULT_OK);
277 read_buffer.resize(num_bytes);
278 CHECK_EQ(read_buffer, std::string("go 1"));
279 CHECK_EQ(num_handlers, 1u);
280
281 // Make a mapping.
282 void* buffer;
283 CHECK_EQ(MojoMapBuffer(handles[0], 0, 100, nullptr, &buffer), MOJO_RESULT_OK);
284
285 // Write some stuff to the shared buffer.
286 static const char kHello[] = "hello";
287 memcpy(buffer, kHello, sizeof(kHello));
288
289 // We should be able to close the dispatcher now.
290 MojoClose(handles[0]);
291
292 // And send a message to signal that we've written stuff.
293 const std::string go2("go 2");
294 CHECK_EQ(MojoWriteMessage(h, go2.data(), static_cast<uint32_t>(go2.size()),
295 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
296 MOJO_RESULT_OK);
297
298 // Now wait for our parent to send us a message.
299 hss = HandleSignalsState();
300 CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
301 MOJO_RESULT_OK);
302 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
303 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
304
305 read_buffer = std::string(100, '\0');
306 num_bytes = static_cast<uint32_t>(read_buffer.size());
307 CHECK_EQ(MojoReadMessage(h, &read_buffer[0], &num_bytes, nullptr, 0,
308 MOJO_READ_MESSAGE_FLAG_NONE),
309 MOJO_RESULT_OK);
310 read_buffer.resize(num_bytes);
311 CHECK_EQ(read_buffer, std::string("go 3"));
312
313 // It should have written something to the shared buffer.
314 static const char kWorld[] = "world!!!";
315 CHECK_EQ(memcmp(buffer, kWorld, sizeof(kWorld)), 0);
316
317 // And we're done.
318
319 return 0;
320 }
321
TEST_F(MultiprocessMessagePipeTest,SharedBufferPassing)322 TEST_F(MultiprocessMessagePipeTest, SharedBufferPassing) {
323 RunTestClient("CheckSharedBuffer", [&](MojoHandle h) {
324 // Make a shared buffer.
325 MojoCreateSharedBufferOptions options;
326 options.struct_size = sizeof(options);
327 options.flags = MOJO_CREATE_SHARED_BUFFER_FLAG_NONE;
328
329 MojoHandle shared_buffer;
330 ASSERT_EQ(MOJO_RESULT_OK,
331 MojoCreateSharedBuffer(100, &options, &shared_buffer));
332 MojoSharedBufferInfo buffer_info;
333 buffer_info.struct_size = sizeof(buffer_info);
334 ASSERT_EQ(MOJO_RESULT_OK,
335 MojoGetBufferInfo(shared_buffer, nullptr, &buffer_info));
336 EXPECT_GE(buffer_info.size, 100U);
337
338 // Send the shared buffer.
339 const std::string go1("go 1");
340
341 MojoHandle duplicated_shared_buffer;
342 ASSERT_EQ(MOJO_RESULT_OK,
343 MojoDuplicateBufferHandle(shared_buffer, nullptr,
344 &duplicated_shared_buffer));
345 buffer_info.size = 0;
346 ASSERT_EQ(MOJO_RESULT_OK,
347 MojoGetBufferInfo(shared_buffer, nullptr, &buffer_info));
348 EXPECT_GE(buffer_info.size, 100U);
349 MojoHandle handles[1];
350 handles[0] = duplicated_shared_buffer;
351 ASSERT_EQ(MOJO_RESULT_OK,
352 MojoWriteMessage(h, &go1[0], static_cast<uint32_t>(go1.size()),
353 &handles[0], arraysize(handles),
354 MOJO_WRITE_MESSAGE_FLAG_NONE));
355
356 // Wait for a message from the child.
357 HandleSignalsState hss;
358 ASSERT_EQ(MOJO_RESULT_OK,
359 WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
360 EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
361 EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
362
363 std::string read_buffer(100, '\0');
364 uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
365 ASSERT_EQ(MOJO_RESULT_OK,
366 MojoReadMessage(h, &read_buffer[0], &num_bytes, nullptr, 0,
367 MOJO_READ_MESSAGE_FLAG_NONE));
368 read_buffer.resize(num_bytes);
369 ASSERT_EQ(std::string("go 2"), read_buffer);
370
371 // After we get it, the child should have written something to the shared
372 // buffer.
373 static const char kHello[] = "hello";
374 void* buffer;
375 CHECK_EQ(MojoMapBuffer(shared_buffer, 0, 100, nullptr, &buffer),
376 MOJO_RESULT_OK);
377 ASSERT_EQ(0, memcmp(buffer, kHello, sizeof(kHello)));
378
379 // Now we'll write some stuff to the shared buffer.
380 static const char kWorld[] = "world!!!";
381 memcpy(buffer, kWorld, sizeof(kWorld));
382
383 // And send a message to signal that we've written stuff.
384 const std::string go3("go 3");
385 ASSERT_EQ(MOJO_RESULT_OK,
386 MojoWriteMessage(h, &go3[0], static_cast<uint32_t>(go3.size()),
387 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
388
389 // Wait for |h| to become readable, which should fail.
390 hss = HandleSignalsState();
391 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
392 WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
393 ASSERT_FALSE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
394 ASSERT_FALSE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
395 });
396 }
397
DEFINE_TEST_CLIENT_WITH_PIPE(CheckPlatformHandleFile,MultiprocessMessagePipeTest,h)398 DEFINE_TEST_CLIENT_WITH_PIPE(CheckPlatformHandleFile,
399 MultiprocessMessagePipeTest,
400 h) {
401 HandleSignalsState hss;
402 CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
403 MOJO_RESULT_OK);
404 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
405 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
406
407 std::string read_buffer(100, '\0');
408 uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
409 MojoHandle handles[255]; // Maximum number to receive.
410 uint32_t num_handlers = arraysize(handles);
411
412 CHECK_EQ(MojoReadMessage(h, &read_buffer[0], &num_bytes, &handles[0],
413 &num_handlers, MOJO_READ_MESSAGE_FLAG_NONE),
414 MOJO_RESULT_OK);
415
416 read_buffer.resize(num_bytes);
417 char hello[32];
418 int num_handles = 0;
419 sscanf(read_buffer.c_str(), "%s %d", hello, &num_handles);
420 CHECK_EQ(std::string("hello"), std::string(hello));
421 CHECK_GT(num_handles, 0);
422
423 for (int i = 0; i < num_handles; ++i) {
424 PlatformHandle h = UnwrapPlatformHandle(ScopedHandle(Handle(handles[i])));
425 CHECK(h.is_valid());
426
427 base::ScopedFILE fp = test::FILEFromPlatformHandle(std::move(h), "r");
428 CHECK(fp);
429 std::string fread_buffer(100, '\0');
430 size_t bytes_read =
431 fread(&fread_buffer[0], 1, fread_buffer.size(), fp.get());
432 fread_buffer.resize(bytes_read);
433 CHECK_EQ(fread_buffer, "world");
434 }
435
436 return 0;
437 }
438
439 class MultiprocessMessagePipeTestWithPipeCount
440 : public MultiprocessMessagePipeTest,
441 public testing::WithParamInterface<size_t> {};
442
TEST_P(MultiprocessMessagePipeTestWithPipeCount,PlatformHandlePassing)443 TEST_P(MultiprocessMessagePipeTestWithPipeCount, PlatformHandlePassing) {
444 base::ScopedTempDir temp_dir;
445 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
446
447 RunTestClient("CheckPlatformHandleFile", [&](MojoHandle h) {
448 std::vector<MojoHandle> handles;
449
450 size_t pipe_count = GetParam();
451 for (size_t i = 0; i < pipe_count; ++i) {
452 base::FilePath unused;
453 base::ScopedFILE fp(
454 CreateAndOpenTemporaryFileInDir(temp_dir.GetPath(), &unused));
455 const std::string world("world");
456 CHECK_EQ(fwrite(&world[0], 1, world.size(), fp.get()), world.size());
457 fflush(fp.get());
458 rewind(fp.get());
459 ScopedHandle handle =
460 WrapPlatformHandle(test::PlatformHandleFromFILE(std::move(fp)));
461 ASSERT_TRUE(handle.is_valid());
462 handles.push_back(handle.release().value());
463 }
464
465 char message[128];
466 snprintf(message, sizeof(message), "hello %d",
467 static_cast<int>(pipe_count));
468 ASSERT_EQ(
469 MOJO_RESULT_OK,
470 MojoWriteMessage(h, message, static_cast<uint32_t>(strlen(message)),
471 &handles[0], static_cast<uint32_t>(handles.size()),
472 MOJO_WRITE_MESSAGE_FLAG_NONE));
473
474 // Wait for it to become readable, which should fail.
475 HandleSignalsState hss;
476 ASSERT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
477 WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss));
478 ASSERT_FALSE(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
479 ASSERT_FALSE(hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE);
480 });
481 }
482
483 // Android multi-process tests are not executing the new process. This is flaky.
484 #if !defined(OS_ANDROID)
485 INSTANTIATE_TEST_CASE_P(PipeCount,
486 MultiprocessMessagePipeTestWithPipeCount,
487 // TODO(rockot): Enable the 128 and 250 pipe cases when
488 // ChannelPosix and ChannelFuchsia have support for
489 // sending larger numbers of handles per-message. See
490 // kMaxAttachedHandles in channel.cc for details.
491 testing::Values(1u, 64u /*, 128u, 250u*/));
492 #endif
493
DEFINE_TEST_CLIENT_WITH_PIPE(CheckMessagePipe,MultiprocessMessagePipeTest,h)494 DEFINE_TEST_CLIENT_WITH_PIPE(CheckMessagePipe, MultiprocessMessagePipeTest, h) {
495 // Wait for the first message from our parent.
496 HandleSignalsState hss;
497 CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
498 MOJO_RESULT_OK);
499 // In this test, the parent definitely doesn't close its end of the message
500 // pipe before we do.
501 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
502 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
503
504 // It should have a message pipe.
505 MojoHandle handles[10];
506 uint32_t num_handlers = arraysize(handles);
507 CHECK_EQ(MojoReadMessage(h, nullptr, nullptr, &handles[0], &num_handlers,
508 MOJO_READ_MESSAGE_FLAG_NONE),
509 MOJO_RESULT_OK);
510 CHECK_EQ(num_handlers, 1u);
511
512 // Read data from the received message pipe.
513 CHECK_EQ(WaitForSignals(handles[0], MOJO_HANDLE_SIGNAL_READABLE, &hss),
514 MOJO_RESULT_OK);
515 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
516 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
517
518 std::string read_buffer(100, '\0');
519 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
520 CHECK_EQ(MojoReadMessage(handles[0], &read_buffer[0], &read_buffer_size,
521 nullptr, 0, MOJO_READ_MESSAGE_FLAG_NONE),
522 MOJO_RESULT_OK);
523 read_buffer.resize(read_buffer_size);
524 CHECK_EQ(read_buffer, std::string("hello"));
525
526 // Now write some data into the message pipe.
527 std::string write_buffer = "world";
528 CHECK_EQ(MojoWriteMessage(handles[0], write_buffer.data(),
529 static_cast<uint32_t>(write_buffer.size()), nullptr,
530 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
531 MOJO_RESULT_OK);
532 MojoClose(handles[0]);
533 return 0;
534 }
535
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,MessagePipePassing)536 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipePassing) {
537 RunTestClient("CheckMessagePipe", [&](MojoHandle h) {
538 MojoCreateSharedBufferOptions options;
539 options.struct_size = sizeof(options);
540 options.flags = MOJO_CREATE_SHARED_BUFFER_FLAG_NONE;
541
542 MojoHandle mp1, mp2;
543 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp1, &mp2));
544
545 // Write a string into one end of the new message pipe and send the other
546 // end.
547 const std::string hello("hello");
548 ASSERT_EQ(
549 MOJO_RESULT_OK,
550 MojoWriteMessage(mp1, &hello[0], static_cast<uint32_t>(hello.size()),
551 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE));
552 ASSERT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h, nullptr, 0, &mp2, 1,
553 MOJO_WRITE_MESSAGE_FLAG_NONE));
554
555 // Wait for a message from the child.
556 HandleSignalsState hss;
557 ASSERT_EQ(MOJO_RESULT_OK,
558 WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &hss));
559 EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
560 EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
561
562 std::string read_buffer(100, '\0');
563 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
564 CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], &read_buffer_size, nullptr,
565 0, MOJO_READ_MESSAGE_FLAG_NONE),
566 MOJO_RESULT_OK);
567 read_buffer.resize(read_buffer_size);
568 CHECK_EQ(read_buffer, std::string("world"));
569
570 MojoClose(mp1);
571 });
572 }
573
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,MessagePipeTwoPassing)574 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MessagePipeTwoPassing) {
575 RunTestClient("CheckMessagePipe", [&](MojoHandle h) {
576 MojoHandle mp1, mp2;
577 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp1));
578
579 // Write a string into one end of the new message pipe and send the other
580 // end.
581 const std::string hello("hello");
582 ASSERT_EQ(
583 MOJO_RESULT_OK,
584 MojoWriteMessage(mp1, &hello[0], static_cast<uint32_t>(hello.size()),
585 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
586 ASSERT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h, nullptr, 0u, &mp2, 1u,
587 MOJO_WRITE_MESSAGE_FLAG_NONE));
588
589 // Wait for a message from the child.
590 HandleSignalsState hss;
591 ASSERT_EQ(MOJO_RESULT_OK,
592 WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &hss));
593 EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
594 EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
595
596 std::string read_buffer(100, '\0');
597 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
598 CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], &read_buffer_size, nullptr,
599 0, MOJO_READ_MESSAGE_FLAG_NONE),
600 MOJO_RESULT_OK);
601 read_buffer.resize(read_buffer_size);
602 CHECK_EQ(read_buffer, std::string("world"));
603 });
604 }
605
DEFINE_TEST_CLIENT_WITH_PIPE(DataPipeConsumer,MultiprocessMessagePipeTest,h)606 DEFINE_TEST_CLIENT_WITH_PIPE(DataPipeConsumer, MultiprocessMessagePipeTest, h) {
607 // Wait for the first message from our parent.
608 HandleSignalsState hss;
609 CHECK_EQ(WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE, &hss),
610 MOJO_RESULT_OK);
611 // In this test, the parent definitely doesn't close its end of the message
612 // pipe before we do.
613 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
614 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
615 CHECK_EQ(hss.satisfiable_signals,
616 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
617 MOJO_HANDLE_SIGNAL_PEER_CLOSED | MOJO_HANDLE_SIGNAL_PEER_REMOTE |
618 MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
619
620 // It should have a message pipe.
621 MojoHandle handles[10];
622 uint32_t num_handlers = arraysize(handles);
623 CHECK_EQ(MojoReadMessage(h, nullptr, nullptr, &handles[0], &num_handlers,
624 MOJO_READ_MESSAGE_FLAG_NONE),
625 MOJO_RESULT_OK);
626 CHECK_EQ(num_handlers, 1u);
627
628 // Read data from the received message pipe.
629 CHECK_EQ(WaitForSignals(handles[0], MOJO_HANDLE_SIGNAL_READABLE, &hss),
630 MOJO_RESULT_OK);
631 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE);
632 CHECK(hss.satisfied_signals & MOJO_HANDLE_SIGNAL_WRITABLE);
633 CHECK_EQ(hss.satisfiable_signals,
634 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
635 MOJO_HANDLE_SIGNAL_PEER_CLOSED | MOJO_HANDLE_SIGNAL_PEER_REMOTE |
636 MOJO_HANDLE_SIGNAL_QUOTA_EXCEEDED);
637
638 std::string read_buffer(100, '\0');
639 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
640 CHECK_EQ(MojoReadMessage(handles[0], &read_buffer[0], &read_buffer_size,
641 nullptr, 0, MOJO_READ_MESSAGE_FLAG_NONE),
642 MOJO_RESULT_OK);
643 read_buffer.resize(read_buffer_size);
644 CHECK_EQ(read_buffer, std::string("hello"));
645
646 // Now write some data into the message pipe.
647 std::string write_buffer = "world";
648 CHECK_EQ(MojoWriteMessage(handles[0], write_buffer.data(),
649 static_cast<uint32_t>(write_buffer.size()), nullptr,
650 0u, MOJO_WRITE_MESSAGE_FLAG_NONE),
651 MOJO_RESULT_OK);
652 MojoClose(handles[0]);
653 return 0;
654 }
655
TEST_F(MultiprocessMessagePipeTest,DataPipeConsumer)656 TEST_F(MultiprocessMessagePipeTest, DataPipeConsumer) {
657 RunTestClient("DataPipeConsumer", [&](MojoHandle h) {
658 MojoCreateSharedBufferOptions options;
659 options.struct_size = sizeof(options);
660 options.flags = MOJO_CREATE_SHARED_BUFFER_FLAG_NONE;
661
662 MojoHandle mp1, mp2;
663 ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessagePipe(nullptr, &mp2, &mp1));
664
665 // Write a string into one end of the new message pipe and send the other
666 // end.
667 const std::string hello("hello");
668 ASSERT_EQ(
669 MOJO_RESULT_OK,
670 MojoWriteMessage(mp1, &hello[0], static_cast<uint32_t>(hello.size()),
671 nullptr, 0u, MOJO_WRITE_MESSAGE_FLAG_NONE));
672 ASSERT_EQ(MOJO_RESULT_OK, MojoWriteMessage(h, nullptr, 0, &mp2, 1u,
673 MOJO_WRITE_MESSAGE_FLAG_NONE));
674
675 // Wait for a message from the child.
676 HandleSignalsState hss;
677 ASSERT_EQ(MOJO_RESULT_OK,
678 WaitForSignals(mp1, MOJO_HANDLE_SIGNAL_READABLE, &hss));
679 EXPECT_TRUE((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE));
680 EXPECT_TRUE((hss.satisfiable_signals & MOJO_HANDLE_SIGNAL_READABLE));
681
682 std::string read_buffer(100, '\0');
683 uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
684 CHECK_EQ(MojoReadMessage(mp1, &read_buffer[0], &read_buffer_size, nullptr,
685 0, MOJO_READ_MESSAGE_FLAG_NONE),
686 MOJO_RESULT_OK);
687 read_buffer.resize(read_buffer_size);
688 CHECK_EQ(read_buffer, std::string("world"));
689
690 MojoClose(mp1);
691 });
692 }
693
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,CreateMessagePipe)694 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, CreateMessagePipe) {
695 MojoHandle p0, p1;
696 CreateMessagePipe(&p0, &p1);
697 VerifyTransmission(p0, p1, std::string(10 * 1024 * 1024, 'a'));
698 VerifyTransmission(p1, p0, std::string(10 * 1024 * 1024, 'e'));
699
700 CloseHandle(p0);
701 CloseHandle(p1);
702 }
703
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,PassMessagePipeLocal)704 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PassMessagePipeLocal) {
705 MojoHandle p0, p1;
706 CreateMessagePipe(&p0, &p1);
707 VerifyTransmission(p0, p1, "testing testing");
708 VerifyTransmission(p1, p0, "one two three");
709
710 MojoHandle p2, p3;
711
712 CreateMessagePipe(&p2, &p3);
713 VerifyTransmission(p2, p3, "testing testing");
714 VerifyTransmission(p3, p2, "one two three");
715
716 // Pass p2 over p0 to p1.
717 const std::string message = "ceci n'est pas une pipe";
718 WriteMessageWithHandles(p0, message, &p2, 1);
719 EXPECT_EQ(message, ReadMessageWithHandles(p1, &p2, 1));
720
721 CloseHandle(p0);
722 CloseHandle(p1);
723
724 // Verify that the received handle (now in p2) still works.
725 VerifyTransmission(p2, p3, "Easy come, easy go; will you let me go?");
726 VerifyTransmission(p3, p2, "Bismillah! NO! We will not let you go!");
727
728 CloseHandle(p2);
729 CloseHandle(p3);
730 }
731
732 // Echos the primordial channel until "exit".
DEFINE_TEST_CLIENT_WITH_PIPE(ChannelEchoClient,MultiprocessMessagePipeTest,h)733 DEFINE_TEST_CLIENT_WITH_PIPE(ChannelEchoClient,
734 MultiprocessMessagePipeTest,
735 h) {
736 for (;;) {
737 std::string message = ReadMessage(h);
738 if (message == "exit")
739 break;
740 WriteMessage(h, message);
741 }
742 return 0;
743 }
744
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,MultiprocessChannelPipe)745 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, MultiprocessChannelPipe) {
746 RunTestClient("ChannelEchoClient", [&](MojoHandle h) {
747 VerifyEcho(h, "in an interstellar burst");
748 VerifyEcho(h, "i am back to save the universe");
749 VerifyEcho(h, std::string(10 * 1024 * 1024, 'o'));
750
751 WriteMessage(h, "exit");
752 });
753 }
754
755 // Receives a pipe handle from the primordial channel and echos on it until
756 // "exit". Used to test simple pipe transfer across processes via channels.
DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceClient,MultiprocessMessagePipeTest,h)757 DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceClient,
758 MultiprocessMessagePipeTest,
759 h) {
760 MojoHandle p;
761 ReadMessageWithHandles(h, &p, 1);
762 for (;;) {
763 std::string message = ReadMessage(p);
764 if (message == "exit")
765 break;
766 WriteMessage(p, message);
767 }
768 return 0;
769 }
770
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,PassMessagePipeCrossProcess)771 TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
772 PassMessagePipeCrossProcess) {
773 MojoHandle p0, p1;
774 CreateMessagePipe(&p0, &p1);
775 RunTestClient("EchoServiceClient", [&](MojoHandle h) {
776 // Pass one end of the pipe to the other process.
777 WriteMessageWithHandles(h, "here take this", &p1, 1);
778
779 VerifyEcho(p0, "and you may ask yourself");
780 VerifyEcho(p0, "where does that highway go?");
781 VerifyEcho(p0, std::string(20 * 1024 * 1024, 'i'));
782
783 WriteMessage(p0, "exit");
784 });
785 CloseHandle(p0);
786 }
787
788 // Receives a pipe handle from the primordial channel and reads new handles
789 // from it. Each read handle establishes a new echo channel.
DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceFactoryClient,MultiprocessMessagePipeTest,h)790 DEFINE_TEST_CLIENT_WITH_PIPE(EchoServiceFactoryClient,
791 MultiprocessMessagePipeTest,
792 h) {
793 MojoHandle p;
794 ReadMessageWithHandles(h, &p, 1);
795
796 std::vector<Handle> handles(2);
797 handles[0] = Handle(h);
798 handles[1] = Handle(p);
799 std::vector<MojoHandleSignals> signals(2, MOJO_HANDLE_SIGNAL_READABLE);
800 for (;;) {
801 size_t index;
802 CHECK_EQ(
803 mojo::WaitMany(handles.data(), signals.data(), handles.size(), &index),
804 MOJO_RESULT_OK);
805 DCHECK_LE(index, handles.size());
806 if (index == 0) {
807 // If data is available on the first pipe, it should be an exit command.
808 EXPECT_EQ(std::string("exit"), ReadMessage(h));
809 break;
810 } else if (index == 1) {
811 // If the second pipe, it should be a new handle requesting echo service.
812 MojoHandle echo_request;
813 ReadMessageWithHandles(p, &echo_request, 1);
814 handles.push_back(Handle(echo_request));
815 signals.push_back(MOJO_HANDLE_SIGNAL_READABLE);
816 } else {
817 // Otherwise it was one of our established echo pipes. Echo!
818 WriteMessage(handles[index].value(), ReadMessage(handles[index].value()));
819 }
820 }
821
822 for (size_t i = 1; i < handles.size(); ++i)
823 CloseHandle(handles[i].value());
824
825 return 0;
826 }
827
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,PassMoarMessagePipesCrossProcess)828 TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
829 PassMoarMessagePipesCrossProcess) {
830 MojoHandle echo_factory_proxy, echo_factory_request;
831 CreateMessagePipe(&echo_factory_proxy, &echo_factory_request);
832
833 MojoHandle echo_proxy_a, echo_request_a;
834 CreateMessagePipe(&echo_proxy_a, &echo_request_a);
835
836 MojoHandle echo_proxy_b, echo_request_b;
837 CreateMessagePipe(&echo_proxy_b, &echo_request_b);
838
839 MojoHandle echo_proxy_c, echo_request_c;
840 CreateMessagePipe(&echo_proxy_c, &echo_request_c);
841
842 RunTestClient("EchoServiceFactoryClient", [&](MojoHandle h) {
843 WriteMessageWithHandles(h, "gief factory naow plz", &echo_factory_request,
844 1);
845
846 WriteMessageWithHandles(echo_factory_proxy, "give me an echo service plz!",
847 &echo_request_a, 1);
848 WriteMessageWithHandles(echo_factory_proxy, "give me one too!",
849 &echo_request_b, 1);
850
851 VerifyEcho(echo_proxy_a, "i came here for an argument");
852 VerifyEcho(echo_proxy_a, "shut your festering gob");
853 VerifyEcho(echo_proxy_a, "mumble mumble mumble");
854
855 VerifyEcho(echo_proxy_b, "wubalubadubdub");
856 VerifyEcho(echo_proxy_b, "wubalubadubdub");
857
858 WriteMessageWithHandles(echo_factory_proxy, "hook me up also thanks",
859 &echo_request_c, 1);
860
861 VerifyEcho(echo_proxy_a, "the frobinators taste like frobinators");
862 VerifyEcho(echo_proxy_b, "beep bop boop");
863 VerifyEcho(echo_proxy_c, "zzzzzzzzzzzzzzzzzzzzzzzzzz");
864
865 WriteMessage(h, "exit");
866 });
867
868 CloseHandle(echo_factory_proxy);
869 CloseHandle(echo_proxy_a);
870 CloseHandle(echo_proxy_b);
871 CloseHandle(echo_proxy_c);
872 }
873
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,ChannelPipesWithMultipleChildren)874 TEST_P(MultiprocessMessagePipeTestWithPeerSupport,
875 ChannelPipesWithMultipleChildren) {
876 RunTestClient("ChannelEchoClient", [&](MojoHandle a) {
877 RunTestClient("ChannelEchoClient", [&](MojoHandle b) {
878 VerifyEcho(a, "hello child 0");
879 VerifyEcho(b, "hello child 1");
880
881 WriteMessage(a, "exit");
882 WriteMessage(b, "exit");
883 });
884 });
885 }
886
887 // Reads and turns a pipe handle some number of times to create lots of
888 // transient proxies.
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingPongPipeClient,MultiprocessMessagePipeTest,h)889 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingPongPipeClient,
890 MultiprocessMessagePipeTest,
891 h) {
892 const size_t kNumBounces = 50;
893 MojoHandle p0, p1;
894 ReadMessageWithHandles(h, &p0, 1);
895 ReadMessageWithHandles(h, &p1, 1);
896 for (size_t i = 0; i < kNumBounces; ++i) {
897 WriteMessageWithHandles(h, "", &p1, 1);
898 ReadMessageWithHandles(h, &p1, 1);
899 }
900 WriteMessageWithHandles(h, "", &p0, 1);
901 WriteMessage(p1, "bye");
902 MojoClose(p1);
903 EXPECT_EQ("quit", ReadMessage(h));
904 }
905
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,PingPongPipe)906 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, PingPongPipe) {
907 MojoHandle p0, p1;
908 CreateMessagePipe(&p0, &p1);
909
910 RunTestClient("PingPongPipeClient", [&](MojoHandle h) {
911 const size_t kNumBounces = 50;
912 WriteMessageWithHandles(h, "", &p0, 1);
913 WriteMessageWithHandles(h, "", &p1, 1);
914 for (size_t i = 0; i < kNumBounces; ++i) {
915 ReadMessageWithHandles(h, &p1, 1);
916 WriteMessageWithHandles(h, "", &p1, 1);
917 }
918 ReadMessageWithHandles(h, &p0, 1);
919 WriteMessage(h, "quit");
920 });
921
922 EXPECT_EQ("bye", ReadMessage(p0));
923
924 // We should still be able to observe peer closure from the other end.
925 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(p0, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
926 }
927
928 // Parses commands from the parent pipe and does whatever it's asked to do.
DEFINE_TEST_CLIENT_WITH_PIPE(CommandDrivenClient,MultiprocessMessagePipeTest,h)929 DEFINE_TEST_CLIENT_WITH_PIPE(CommandDrivenClient,
930 MultiprocessMessagePipeTest,
931 h) {
932 base::hash_map<std::string, MojoHandle> named_pipes;
933 for (;;) {
934 MojoHandle p;
935 auto parts = base::SplitString(ReadMessageWithOptionalHandle(h, &p), ":",
936 base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
937 CHECK(!parts.empty());
938 std::string command = parts[0];
939 if (command == "take") {
940 // Take a pipe.
941 CHECK_EQ(parts.size(), 2u);
942 CHECK_NE(p, MOJO_HANDLE_INVALID);
943 named_pipes[parts[1]] = p;
944 WriteMessage(h, "ok");
945 } else if (command == "return") {
946 // Return a pipe.
947 CHECK_EQ(parts.size(), 2u);
948 CHECK_EQ(p, MOJO_HANDLE_INVALID);
949 p = named_pipes[parts[1]];
950 CHECK_NE(p, MOJO_HANDLE_INVALID);
951 named_pipes.erase(parts[1]);
952 WriteMessageWithHandles(h, "ok", &p, 1);
953 } else if (command == "say") {
954 // Say something to a named pipe.
955 CHECK_EQ(parts.size(), 3u);
956 CHECK_EQ(p, MOJO_HANDLE_INVALID);
957 p = named_pipes[parts[1]];
958 CHECK_NE(p, MOJO_HANDLE_INVALID);
959 CHECK(!parts[2].empty());
960 WriteMessage(p, parts[2]);
961 WriteMessage(h, "ok");
962 } else if (command == "hear") {
963 // Expect to read something from a named pipe.
964 CHECK_EQ(parts.size(), 3u);
965 CHECK_EQ(p, MOJO_HANDLE_INVALID);
966 p = named_pipes[parts[1]];
967 CHECK_NE(p, MOJO_HANDLE_INVALID);
968 CHECK(!parts[2].empty());
969 CHECK_EQ(parts[2], ReadMessage(p));
970 WriteMessage(h, "ok");
971 } else if (command == "pass") {
972 // Pass one named pipe over another named pipe.
973 CHECK_EQ(parts.size(), 3u);
974 CHECK_EQ(p, MOJO_HANDLE_INVALID);
975 p = named_pipes[parts[1]];
976 MojoHandle carrier = named_pipes[parts[2]];
977 CHECK_NE(p, MOJO_HANDLE_INVALID);
978 CHECK_NE(carrier, MOJO_HANDLE_INVALID);
979 named_pipes.erase(parts[1]);
980 WriteMessageWithHandles(carrier, "got a pipe for ya", &p, 1);
981 WriteMessage(h, "ok");
982 } else if (command == "catch") {
983 // Expect to receive one named pipe from another named pipe.
984 CHECK_EQ(parts.size(), 3u);
985 CHECK_EQ(p, MOJO_HANDLE_INVALID);
986 MojoHandle carrier = named_pipes[parts[2]];
987 CHECK_NE(carrier, MOJO_HANDLE_INVALID);
988 ReadMessageWithHandles(carrier, &p, 1);
989 CHECK_NE(p, MOJO_HANDLE_INVALID);
990 named_pipes[parts[1]] = p;
991 WriteMessage(h, "ok");
992 } else if (command == "exit") {
993 CHECK_EQ(parts.size(), 1u);
994 break;
995 }
996 }
997
998 for (auto& pipe : named_pipes)
999 CloseHandle(pipe.second);
1000
1001 return 0;
1002 }
1003
TEST_F(MultiprocessMessagePipeTest,ChildToChildPipes)1004 TEST_F(MultiprocessMessagePipeTest, ChildToChildPipes) {
1005 RunTestClient("CommandDrivenClient", [&](MojoHandle h0) {
1006 RunTestClient("CommandDrivenClient", [&](MojoHandle h1) {
1007 CommandDrivenClientController a(h0);
1008 CommandDrivenClientController b(h1);
1009
1010 // Create a pipe and pass each end to a different client.
1011 MojoHandle p0, p1;
1012 CreateMessagePipe(&p0, &p1);
1013 a.SendHandle("x", p0);
1014 b.SendHandle("y", p1);
1015
1016 // Make sure they can talk.
1017 a.Send("say:x:hello");
1018 b.Send("hear:y:hello");
1019
1020 b.Send("say:y:i love multiprocess pipes!");
1021 a.Send("hear:x:i love multiprocess pipes!");
1022
1023 a.Exit();
1024 b.Exit();
1025 });
1026 });
1027 }
1028
TEST_F(MultiprocessMessagePipeTest,MoreChildToChildPipes)1029 TEST_F(MultiprocessMessagePipeTest, MoreChildToChildPipes) {
1030 RunTestClient("CommandDrivenClient", [&](MojoHandle h0) {
1031 RunTestClient("CommandDrivenClient", [&](MojoHandle h1) {
1032 RunTestClient("CommandDrivenClient", [&](MojoHandle h2) {
1033 RunTestClient("CommandDrivenClient", [&](MojoHandle h3) {
1034 CommandDrivenClientController a(h0), b(h1), c(h2), d(h3);
1035
1036 // Connect a to b and c to d
1037
1038 MojoHandle p0, p1;
1039
1040 CreateMessagePipe(&p0, &p1);
1041 a.SendHandle("b_pipe", p0);
1042 b.SendHandle("a_pipe", p1);
1043
1044 MojoHandle p2, p3;
1045
1046 CreateMessagePipe(&p2, &p3);
1047 c.SendHandle("d_pipe", p2);
1048 d.SendHandle("c_pipe", p3);
1049
1050 // Connect b to c via a and d
1051 MojoHandle p4, p5;
1052 CreateMessagePipe(&p4, &p5);
1053 a.SendHandle("d_pipe", p4);
1054 d.SendHandle("a_pipe", p5);
1055
1056 // Have |a| pass its new |d|-pipe to |b|. It will eventually connect
1057 // to |c|.
1058 a.Send("pass:d_pipe:b_pipe");
1059 b.Send("catch:c_pipe:a_pipe");
1060
1061 // Have |d| pass its new |a|-pipe to |c|. It will now be connected to
1062 // |b|.
1063 d.Send("pass:a_pipe:c_pipe");
1064 c.Send("catch:b_pipe:d_pipe");
1065
1066 // Make sure b and c and talk.
1067 b.Send("say:c_pipe:it's a beautiful day");
1068 c.Send("hear:b_pipe:it's a beautiful day");
1069
1070 // Create x and y and have b and c exchange them.
1071 MojoHandle x, y;
1072 CreateMessagePipe(&x, &y);
1073 b.SendHandle("x", x);
1074 c.SendHandle("y", y);
1075 b.Send("pass:x:c_pipe");
1076 c.Send("pass:y:b_pipe");
1077 b.Send("catch:y:c_pipe");
1078 c.Send("catch:x:b_pipe");
1079
1080 // Make sure the pipe still works in both directions.
1081 b.Send("say:y:hello");
1082 c.Send("hear:x:hello");
1083 c.Send("say:x:goodbye");
1084 b.Send("hear:y:goodbye");
1085
1086 // Take both pipes back.
1087 y = c.RetrieveHandle("x");
1088 x = b.RetrieveHandle("y");
1089
1090 VerifyTransmission(x, y, "still works");
1091 VerifyTransmission(y, x, "in both directions");
1092
1093 CloseHandle(x);
1094 CloseHandle(y);
1095
1096 a.Exit();
1097 b.Exit();
1098 c.Exit();
1099 d.Exit();
1100 });
1101 });
1102 });
1103 });
1104 }
1105
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeer,MultiprocessMessagePipeTest,h)1106 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeer,
1107 MultiprocessMessagePipeTest,
1108 h) {
1109 MojoHandle p;
1110 EXPECT_EQ("foo", ReadMessageWithHandles(h, &p, 1));
1111 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
1112 }
1113
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,SendPipeThenClosePeer)1114 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendPipeThenClosePeer) {
1115 RunTestClient("ReceivePipeWithClosedPeer", [&](MojoHandle h) {
1116 MojoHandle a, b;
1117 CreateMessagePipe(&a, &b);
1118
1119 // Send |a| and immediately close |b|. The child should observe closure.
1120 WriteMessageWithHandles(h, "foo", &a, 1);
1121 MojoClose(b);
1122 });
1123 }
1124
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(SendOtherChildPipeWithClosedPeer,MultiprocessMessagePipeTest,h)1125 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(SendOtherChildPipeWithClosedPeer,
1126 MultiprocessMessagePipeTest,
1127 h) {
1128 // Create a new pipe and send one end to the parent, who will connect it to
1129 // a client running ReceivePipeWithClosedPeerFromOtherChild.
1130 MojoHandle application_proxy, application_request;
1131 CreateMessagePipe(&application_proxy, &application_request);
1132 WriteMessageWithHandles(h, "c2a plz", &application_request, 1);
1133
1134 // Create another pipe and send one end to the remote "application".
1135 MojoHandle service_proxy, service_request;
1136 CreateMessagePipe(&service_proxy, &service_request);
1137 WriteMessageWithHandles(application_proxy, "c2s lol", &service_request, 1);
1138
1139 // Immediately close the service proxy. The "application" should detect this.
1140 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(service_proxy));
1141
1142 // Wait for quit.
1143 EXPECT_EQ("quit", ReadMessage(h));
1144 }
1145
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeerFromOtherChild,MultiprocessMessagePipeTest,h)1146 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReceivePipeWithClosedPeerFromOtherChild,
1147 MultiprocessMessagePipeTest,
1148 h) {
1149 // Receive a pipe from the parent. This is akin to an "application request".
1150 MojoHandle application_client;
1151 EXPECT_EQ("c2a", ReadMessageWithHandles(h, &application_client, 1));
1152
1153 // Receive a pipe from the "application" "client".
1154 MojoHandle service_client;
1155 EXPECT_EQ("c2s lol",
1156 ReadMessageWithHandles(application_client, &service_client, 1));
1157
1158 // Wait for the service client to signal closure.
1159 EXPECT_EQ(MOJO_RESULT_OK,
1160 WaitForSignals(service_client, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
1161
1162 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(service_client));
1163 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(application_client));
1164 }
1165
1166 #if defined(OS_ANDROID)
1167 // Android multi-process tests are not executing the new process. This is flaky.
1168 #define MAYBE_SendPipeWithClosedPeerBetweenChildren \
1169 DISABLED_SendPipeWithClosedPeerBetweenChildren
1170 #else
1171 #define MAYBE_SendPipeWithClosedPeerBetweenChildren \
1172 SendPipeWithClosedPeerBetweenChildren
1173 #endif
TEST_F(MultiprocessMessagePipeTest,MAYBE_SendPipeWithClosedPeerBetweenChildren)1174 TEST_F(MultiprocessMessagePipeTest,
1175 MAYBE_SendPipeWithClosedPeerBetweenChildren) {
1176 RunTestClient("SendOtherChildPipeWithClosedPeer", [&](MojoHandle kid_a) {
1177 RunTestClient(
1178 "ReceivePipeWithClosedPeerFromOtherChild", [&](MojoHandle kid_b) {
1179 // Receive an "application request" from the first child and forward
1180 // it to the second child.
1181 MojoHandle application_request;
1182 EXPECT_EQ("c2a plz",
1183 ReadMessageWithHandles(kid_a, &application_request, 1));
1184
1185 WriteMessageWithHandles(kid_b, "c2a", &application_request, 1);
1186 });
1187
1188 WriteMessage(kid_a, "quit");
1189 });
1190 }
1191
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,SendClosePeerSend)1192 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, SendClosePeerSend) {
1193 MojoHandle a, b;
1194 CreateMessagePipe(&a, &b);
1195
1196 MojoHandle c, d;
1197 CreateMessagePipe(&c, &d);
1198
1199 // Send |a| over |c|, immediately close |b|, then send |a| back over |d|.
1200 WriteMessageWithHandles(c, "foo", &a, 1);
1201 EXPECT_EQ("foo", ReadMessageWithHandles(d, &a, 1));
1202 WriteMessageWithHandles(d, "bar", &a, 1);
1203 EXPECT_EQ("bar", ReadMessageWithHandles(c, &a, 1));
1204 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(b));
1205
1206 // We should be able to detect peer closure on |a|.
1207 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(a, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
1208 }
1209
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(WriteCloseSendPeerClient,MultiprocessMessagePipeTest,h)1210 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(WriteCloseSendPeerClient,
1211 MultiprocessMessagePipeTest,
1212 h) {
1213 MojoHandle pipe[2];
1214 EXPECT_EQ("foo", ReadMessageWithHandles(h, pipe, 2));
1215
1216 // Write some messages to the first endpoint and then close it.
1217 WriteMessage(pipe[0], "baz");
1218 WriteMessage(pipe[0], "qux");
1219 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(pipe[0]));
1220
1221 MojoHandle c, d;
1222 CreateMessagePipe(&c, &d);
1223
1224 // Pass the orphaned endpoint over another pipe before passing it back to
1225 // the parent, just for some extra proxying goodness.
1226 WriteMessageWithHandles(c, "foo", &pipe[1], 1);
1227 EXPECT_EQ("foo", ReadMessageWithHandles(d, &pipe[1], 1));
1228
1229 // And finally pass it back to the parent.
1230 WriteMessageWithHandles(h, "bar", &pipe[1], 1);
1231
1232 EXPECT_EQ("quit", ReadMessage(h));
1233 }
1234
TEST_P(MultiprocessMessagePipeTestWithPeerSupport,WriteCloseSendPeer)1235 TEST_P(MultiprocessMessagePipeTestWithPeerSupport, WriteCloseSendPeer) {
1236 MojoHandle pipe[2];
1237 CreateMessagePipe(&pipe[0], &pipe[1]);
1238
1239 RunTestClient("WriteCloseSendPeerClient", [&](MojoHandle h) {
1240 // Pass the pipe to the child.
1241 WriteMessageWithHandles(h, "foo", pipe, 2);
1242
1243 // Read back an endpoint which should have messages on it.
1244 MojoHandle p;
1245 EXPECT_EQ("bar", ReadMessageWithHandles(h, &p, 1));
1246
1247 EXPECT_EQ("baz", ReadMessage(p));
1248 EXPECT_EQ("qux", ReadMessage(p));
1249
1250 // Expect to have peer closure signaled.
1251 EXPECT_EQ(MOJO_RESULT_OK,
1252 WaitForSignals(p, MOJO_HANDLE_SIGNAL_PEER_CLOSED));
1253
1254 WriteMessage(h, "quit");
1255 });
1256 }
1257
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MessagePipeStatusChangeInTransitClient,MultiprocessMessagePipeTest,parent)1258 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(MessagePipeStatusChangeInTransitClient,
1259 MultiprocessMessagePipeTest,
1260 parent) {
1261 // This test verifies that peer closure is detectable through various
1262 // mechanisms when it races with handle transfer.
1263 MojoHandle handles[4];
1264 EXPECT_EQ("o_O", ReadMessageWithHandles(parent, handles, 4));
1265
1266 EXPECT_EQ(MOJO_RESULT_OK,
1267 WaitForSignals(handles[0], MOJO_HANDLE_SIGNAL_PEER_CLOSED));
1268
1269 base::MessageLoop message_loop;
1270
1271 // Wait on handle 1 using a SimpleWatcher.
1272 {
1273 base::RunLoop run_loop;
1274 SimpleWatcher watcher(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC,
1275 base::SequencedTaskRunnerHandle::Get());
1276 watcher.Watch(Handle(handles[1]), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
1277 base::Bind(
1278 [](base::RunLoop* loop, MojoResult result) {
1279 EXPECT_EQ(MOJO_RESULT_OK, result);
1280 loop->Quit();
1281 },
1282 &run_loop));
1283 run_loop.Run();
1284 }
1285
1286 // Wait on handle 2 by polling with MojoReadMessage.
1287 MojoResult result;
1288 do {
1289 result = MojoReadMessage(handles[2], nullptr, nullptr, nullptr, nullptr,
1290 MOJO_READ_MESSAGE_FLAG_NONE);
1291 } while (result == MOJO_RESULT_SHOULD_WAIT);
1292 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
1293
1294 // Wait on handle 3 by polling with MojoWriteMessage.
1295 do {
1296 result = MojoWriteMessage(handles[3], nullptr, 0, nullptr, 0,
1297 MOJO_WRITE_MESSAGE_FLAG_NONE);
1298 } while (result == MOJO_RESULT_OK);
1299 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
1300
1301 for (size_t i = 0; i < 4; ++i)
1302 CloseHandle(handles[i]);
1303 }
1304
TEST_F(MultiprocessMessagePipeTest,MessagePipeStatusChangeInTransit)1305 TEST_F(MultiprocessMessagePipeTest, MessagePipeStatusChangeInTransit) {
1306 MojoHandle local_handles[4];
1307 MojoHandle sent_handles[4];
1308 for (size_t i = 0; i < 4; ++i)
1309 CreateMessagePipe(&local_handles[i], &sent_handles[i]);
1310
1311 RunTestClient("MessagePipeStatusChangeInTransitClient",
1312 [&](MojoHandle child) {
1313 // Send 4 handles and let their transfer race with their
1314 // peers' closure.
1315 WriteMessageWithHandles(child, "o_O", sent_handles, 4);
1316 for (size_t i = 0; i < 4; ++i)
1317 CloseHandle(local_handles[i]);
1318 });
1319 }
1320
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(BadMessageClient,MultiprocessMessagePipeTest,parent)1321 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(BadMessageClient,
1322 MultiprocessMessagePipeTest,
1323 parent) {
1324 MojoHandle pipe;
1325 EXPECT_EQ("hi", ReadMessageWithHandles(parent, &pipe, 1));
1326 WriteMessage(pipe, "derp");
1327 EXPECT_EQ("bye", ReadMessage(parent));
1328 }
1329
1330 INSTANTIATE_TEST_CASE_P(
1331 ,
1332 MultiprocessMessagePipeTestWithPeerSupport,
1333 testing::Values(test::MojoTestBase::LaunchType::CHILD,
1334 test::MojoTestBase::LaunchType::PEER,
1335 test::MojoTestBase::LaunchType::NAMED_CHILD,
1336 test::MojoTestBase::LaunchType::NAMED_PEER));
1337 } // namespace
1338 } // namespace core
1339 } // namespace mojo
1340