[go: nahoru, domu]

blob: 27fb348ae7ae392fa36af7d5a07c73be08f7ff3e [file] [log] [blame]
Avi Drissmand387f0922022-09-14 20:51:311// Copyright 2022 The Chromium Authors
Ken Rockot6daf45222022-08-11 22:04:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/core/core_ipcz.h"
6
Ken Rockot227f3a42022-08-12 22:12:097#include <cstring>
Hyowon Kim624a7aa72023-12-05 07:56:288#include <string_view>
Ken Rockot227f3a42022-08-12 22:12:099
Ken Rockot6daf45222022-08-11 22:04:4710#include "base/check.h"
Ken Rockot227f3a42022-08-12 22:12:0911#include "base/containers/span.h"
Keishi Hattoric1b00232022-11-22 09:04:2612#include "base/memory/raw_ptr.h"
Ken Rockot9afacb072022-08-18 11:11:3413#include "base/synchronization/waitable_event.h"
Gyuyoung Kim789fdc32023-04-01 15:30:5614#include "build/blink_buildflags.h"
Ken Rockotb26d96c2022-09-02 00:28:2015#include "build/build_config.h"
Ken Rockota1427712022-09-08 01:24:0516#include "mojo/core/embedder/embedder.h"
Ken Rockot6daf45222022-08-11 22:04:4717#include "mojo/core/ipcz_api.h"
Ken Rockot9afacb072022-08-18 11:11:3418#include "mojo/core/ipcz_driver/transport.h"
Ken Rockotb26d96c2022-09-02 00:28:2019#include "mojo/core/test/mojo_test_base.h"
20#include "mojo/public/c/system/invitation.h"
Ken Rockot6daf45222022-08-11 22:04:4721#include "mojo/public/c/system/thunks.h"
Ken Rockot9afacb072022-08-18 11:11:3422#include "mojo/public/cpp/platform/platform_channel.h"
23#include "mojo/public/cpp/platform/platform_handle.h"
Ken Rockotb26d96c2022-09-02 00:28:2024#include "mojo/public/cpp/system/platform_handle.h"
Ken Rockot6daf45222022-08-11 22:04:4725#include "testing/gtest/include/gtest/gtest.h"
26
27namespace mojo::core {
28namespace {
29
Ken Rockotb26d96c2022-09-02 00:28:2030struct InvitationDetails {
31 MojoPlatformProcessHandle process;
32 MojoPlatformHandle handle;
33 MojoInvitationTransportEndpoint endpoint;
34};
35
Ken Rockot6daf45222022-08-11 22:04:4736// Basic smoke tests for the Mojo Core API as implemented over ipcz.
Ken Rockotb26d96c2022-09-02 00:28:2037class CoreIpczTest : public test::MojoTestBase {
Ken Rockot6daf45222022-08-11 22:04:4738 public:
39 const MojoSystemThunks2& mojo() const { return *mojo_; }
40 const IpczAPI& ipcz() const { return GetIpczAPI(); }
41 IpczHandle node() const { return GetIpczNode(); }
42
Ken Rockotb26d96c2022-09-02 00:28:2043 CoreIpczTest() : CoreIpczTest(/*is_broker=*/true) {}
44
45 enum { kForClient };
46 explicit CoreIpczTest(decltype(kForClient))
47 : CoreIpczTest(/*is_broker=*/false) {}
Ken Rockot227f3a42022-08-12 22:12:0948
Ken Rockota1427712022-09-08 01:24:0549 ~CoreIpczTest() override {
50 if (!IsMojoIpczEnabled()) {
51 DestroyIpczNodeForProcess();
52 }
53 }
Ken Rockot6daf45222022-08-11 22:04:4754
Hyowon Kim85512d9e2023-11-30 01:36:5955 MojoMessageHandle CreateMessage(std::string_view contents,
Ken Rockot227f3a42022-08-12 22:12:0956 base::span<MojoHandle> handles = {}) {
57 MojoMessageHandle message;
58 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateMessage(nullptr, &message));
59
60 void* buffer;
61 uint32_t buffer_size;
62 MojoAppendMessageDataOptions options = {.struct_size = sizeof(options)};
63 options.flags = MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE;
64 EXPECT_EQ(MOJO_RESULT_OK,
65 mojo().AppendMessageData(message, contents.size(), handles.data(),
66 handles.size(), &options, &buffer,
67 &buffer_size));
68 EXPECT_GE(buffer_size, contents.size());
69 memcpy(buffer, contents.data(), contents.size());
70 return message;
71 }
72
Ken Rockot81738e8a2022-08-19 07:35:0573 // Unwraps and re-wraps a Mojo shared buffer handle, extracting some of its
74 // serialized details in the process.
75 struct SharedBufferDetails {
76 uint64_t size;
77 MojoPlatformSharedMemoryRegionAccessMode mode;
78 };
79 SharedBufferDetails PeekSharedBuffer(MojoHandle& buffer) {
80 SharedBufferDetails details;
81 uint32_t num_platform_handles = 2;
82 MojoPlatformHandle platform_handles[2];
83 MojoSharedBufferGuid guid;
84 EXPECT_EQ(MOJO_RESULT_OK,
85 mojo().UnwrapPlatformSharedMemoryRegion(
86 buffer, nullptr, platform_handles, &num_platform_handles,
87 &details.size, &guid, &details.mode));
88 EXPECT_EQ(MOJO_RESULT_OK,
89 mojo().WrapPlatformSharedMemoryRegion(
90 platform_handles, num_platform_handles, details.size, &guid,
91 details.mode, nullptr, &buffer));
92 return details;
93 }
94
Ken Rockotb26d96c2022-09-02 00:28:2095 static void CreateAndShareInvitationTransport(MojoHandle pipe,
96 const base::Process& process,
97 InvitationDetails& details) {
98 PlatformChannel channel;
99 MojoHandle handle_for_client =
100 WrapPlatformHandle(channel.TakeRemoteEndpoint().TakePlatformHandle())
101 .release()
102 .value();
103 WriteMessageWithHandles(pipe, "", &handle_for_client, 1);
104
105 details.process.struct_size = sizeof(details.process);
106#if BUILDFLAG(IS_WIN)
107 details.process.value =
108 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(process.Handle()));
109#else
110 details.process.value = static_cast<uint64_t>(process.Handle());
111#endif
112
113 details.handle.struct_size = sizeof(details.handle);
114 PlatformHandle::ToMojoPlatformHandle(
115 channel.TakeLocalEndpoint().TakePlatformHandle(), &details.handle);
116 details.endpoint = {
117 .struct_size = sizeof(details.endpoint),
118 .type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
119 .num_platform_handles = 1,
120 .platform_handles = &details.handle,
121 };
122 }
123
124 static void ReceiveInvitationTransport(MojoHandle pipe,
125 InvitationDetails& details) {
126 MojoHandle handle;
127 ReadMessageWithHandles(pipe, &handle, 1);
128
129 details.handle.struct_size = sizeof(details.handle);
130 PlatformHandle::ToMojoPlatformHandle(
131 UnwrapPlatformHandle(ScopedHandle(Handle(handle))), &details.handle);
132 details.endpoint = {
133 .struct_size = sizeof(details.endpoint),
134 .type = MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL,
135 .num_platform_handles = 1,
136 .platform_handles = &details.handle,
137 };
138 }
139
Hyowon Kim85512d9e2023-11-30 01:36:59140 void WriteToMessagePipe(MojoHandle pipe, std::string_view contents) {
Ken Rockotb26d96c2022-09-02 00:28:20141 MojoMessageHandle message = CreateMessage(contents);
142 EXPECT_EQ(MOJO_RESULT_OK, mojo().WriteMessage(pipe, message, nullptr));
143 }
144
Ken Rockotfffc10c2022-09-07 21:05:53145 void WaitForReadable(MojoHandle pipe) {
Ken Rockotb26d96c2022-09-02 00:28:20146 base::WaitableEvent ready;
147 MojoHandle trap;
148 auto handler = +[](const MojoTrapEvent* event) {
149 if (event->result == MOJO_RESULT_OK) {
150 reinterpret_cast<base::WaitableEvent*>(event->trigger_context)
151 ->Signal();
152 }
153 };
154 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateTrap(handler, nullptr, &trap));
155 EXPECT_EQ(MOJO_RESULT_OK,
156 mojo().AddTrigger(trap, pipe, MOJO_HANDLE_SIGNAL_READABLE,
157 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
158 reinterpret_cast<uintptr_t>(&ready), nullptr));
159 const MojoResult result = mojo().ArmTrap(trap, nullptr, nullptr, nullptr);
160 if (result == MOJO_RESULT_OK) {
161 ready.Wait();
162 }
163 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(trap));
Ken Rockotfffc10c2022-09-07 21:05:53164 }
165
166 std::string ReadFromMessagePipe(MojoHandle pipe,
167 base::span<MojoHandle> handles = {}) {
168 WaitForReadable(pipe);
Ken Rockotb26d96c2022-09-02 00:28:20169
170 MojoMessageHandle message;
171 EXPECT_EQ(MOJO_RESULT_OK, mojo().ReadMessage(pipe, nullptr, &message));
172 EXPECT_NE(MOJO_MESSAGE_HANDLE_INVALID, message);
173
174 void* buffer;
175 uint32_t buffer_size;
Ken Rockotfffc10c2022-09-07 21:05:53176 uint32_t num_handles = static_cast<uint32_t>(handles.size());
Ken Rockotb26d96c2022-09-02 00:28:20177 EXPECT_EQ(MOJO_RESULT_OK,
178 mojo().GetMessageData(message, nullptr, &buffer, &buffer_size,
Ken Rockotfffc10c2022-09-07 21:05:53179 handles.data(), &num_handles));
180 EXPECT_EQ(num_handles, handles.size());
Ken Rockotb26d96c2022-09-02 00:28:20181
182 std::string contents(static_cast<char*>(buffer), buffer_size);
183 EXPECT_EQ(MOJO_RESULT_OK, mojo().DestroyMessage(message));
184 return contents;
185 }
186
Ken Rockotfffc10c2022-09-07 21:05:53187 // Validates a handle's signaling state against a set of expectations.
188 struct SignalExpectations {
189 MojoHandleSignals satisfiable = 0;
190 MojoHandleSignals not_satisfiable = 0;
191 MojoHandleSignals satisfied = 0;
192 MojoHandleSignals not_satisfied = 0;
193 };
194 void CheckSignals(MojoHandle handle, const SignalExpectations& e) {
195 MojoHandleSignalsState state;
196 EXPECT_EQ(MOJO_RESULT_OK, mojo().QueryHandleSignalsState(handle, &state));
197 EXPECT_EQ(e.satisfiable, state.satisfiable_signals & e.satisfiable);
198 EXPECT_EQ(0u, state.satisfiable_signals & e.not_satisfiable);
199 EXPECT_EQ(e.satisfied, state.satisfied_signals & e.satisfied);
200 EXPECT_EQ(0u, state.satisfied_signals & e.not_satisfied);
201 }
202
Ken Rockot6daf45222022-08-11 22:04:47203 private:
Ken Rockotb26d96c2022-09-02 00:28:20204 explicit CoreIpczTest(bool is_broker) {
Ken Rockota1427712022-09-08 01:24:05205 // If MojoIpcz is enabled, there's no need for the fixture to try to
206 // initialize it again.
207 if (!IsMojoIpczEnabled()) {
208 CHECK(InitializeIpczNodeForProcess({.is_broker = is_broker}));
209 }
Ken Rockotb26d96c2022-09-02 00:28:20210 }
211
Keishi Hattoric1b00232022-11-22 09:04:26212 const raw_ptr<const MojoSystemThunks2> mojo_{GetMojoIpczImpl()};
Ken Rockot6daf45222022-08-11 22:04:47213};
214
Ken Rockot9afacb072022-08-18 11:11:34215// Watches a PlatformChannel endpoint handle for its peer's closure.
216class ChannelPeerClosureListener {
217 public:
218 explicit ChannelPeerClosureListener(PlatformHandle handle)
Ken Rockot97a5acc2022-10-08 21:08:53219 : transport_(ipcz_driver::Transport::Create(
220 {.source = ipcz_driver::Transport::kNonBroker,
221 .destination = ipcz_driver::Transport::kBroker},
Ken Rockot9afacb072022-08-18 11:11:34222 PlatformChannelEndpoint(std::move(handle)))) {
223 transport_->Activate(
224 reinterpret_cast<uintptr_t>(this),
225 [](IpczHandle self, const void*, size_t, const IpczDriverHandle*,
226 size_t, IpczTransportActivityFlags flags, const void*) {
227 reinterpret_cast<ChannelPeerClosureListener*>(self)->OnEvent(flags);
228 return IPCZ_RESULT_OK;
229 });
230 }
231
232 void WaitForPeerClosure() { disconnected_.Wait(); }
233
234 private:
235 void OnEvent(IpczTransportActivityFlags flags) {
236 if (flags & IPCZ_TRANSPORT_ACTIVITY_ERROR) {
237 transport_->Deactivate();
238 } else if (flags & IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED) {
239 disconnected_.Signal();
240 }
241 }
242
243 base::WaitableEvent disconnected_;
244 scoped_refptr<ipcz_driver::Transport> transport_;
245};
246
Ken Rockotb26d96c2022-09-02 00:28:20247class CoreIpczTestClient : public CoreIpczTest {
248 public:
249 CoreIpczTestClient() : CoreIpczTest(kForClient) {}
250};
251
Ken Rockot6daf45222022-08-11 22:04:47252TEST_F(CoreIpczTest, Close) {
253 // With ipcz-based Mojo Core, Mojo handles are ipcz handles. So Mojo Close()
254 // forwards to ipcz Close().
255
256 IpczHandle a, b;
257 EXPECT_EQ(IPCZ_RESULT_OK,
258 ipcz().OpenPortals(node(), IPCZ_NO_FLAGS, nullptr, &a, &b));
259
260 IpczPortalStatus status = {.size = sizeof(status)};
261 EXPECT_EQ(IPCZ_RESULT_OK,
262 ipcz().QueryPortalStatus(b, IPCZ_NO_FLAGS, nullptr, &status));
263 EXPECT_FALSE(status.flags & IPCZ_PORTAL_STATUS_PEER_CLOSED);
264
265 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(a));
266
267 EXPECT_EQ(IPCZ_RESULT_OK,
268 ipcz().QueryPortalStatus(b, IPCZ_NO_FLAGS, nullptr, &status));
269 EXPECT_TRUE(status.flags & IPCZ_PORTAL_STATUS_PEER_CLOSED);
270
271 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(b));
272}
273
Ken Rockot227f3a42022-08-12 22:12:09274TEST_F(CoreIpczTest, BasicMessageUsage) {
275 MojoHandle a, b;
276 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateMessagePipe(nullptr, &a, &b));
277
Hyowon Kim85512d9e2023-11-30 01:36:59278 constexpr std::string_view kMessage = "hellllooooo";
Will Harrise61641f2023-02-07 19:35:02279 MojoMessageHandle message = CreateMessage(kMessage, {&b, 1u});
Ken Rockot227f3a42022-08-12 22:12:09280
281 void* buffer;
282 uint32_t num_bytes;
283 EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
284 mojo().GetMessageData(message, nullptr, &buffer, &num_bytes,
285 nullptr, nullptr));
286
287 const MojoGetMessageDataOptions options = {
288 .struct_size = sizeof(options),
289 .flags = MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES,
290 };
291 EXPECT_EQ(MOJO_RESULT_OK,
292 mojo().GetMessageData(message, &options, &buffer, &num_bytes,
293 nullptr, nullptr));
294 EXPECT_EQ(kMessage,
Hyowon Kim85512d9e2023-11-30 01:36:59295 std::string_view(static_cast<const char*>(buffer), num_bytes));
Ken Rockot227f3a42022-08-12 22:12:09296
297 b = MOJO_HANDLE_INVALID;
298 uint32_t num_handles = 1;
299 EXPECT_EQ(MOJO_RESULT_OK,
300 mojo().GetMessageData(message, nullptr, &buffer, &num_bytes, &b,
301 &num_handles));
302 EXPECT_EQ(MOJO_RESULT_OK, mojo().DestroyMessage(message));
303
304 MojoHandleSignalsState signals_state;
305 EXPECT_EQ(MOJO_RESULT_OK, mojo().QueryHandleSignalsState(a, &signals_state));
306 EXPECT_EQ(0u,
307 signals_state.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
308 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(b));
309 EXPECT_EQ(MOJO_RESULT_OK, mojo().QueryHandleSignalsState(a, &signals_state));
310 EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED,
311 signals_state.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
312 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(a));
313}
314
315TEST_F(CoreIpczTest, MessageDestruction) {
316 MojoHandle a, b;
317 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateMessagePipe(nullptr, &a, &b));
318
Hyowon Kim85512d9e2023-11-30 01:36:59319 constexpr std::string_view kMessage = "hellllooooo";
Will Harrise61641f2023-02-07 19:35:02320 MojoMessageHandle message = CreateMessage(kMessage, {&b, 1u});
Ken Rockot227f3a42022-08-12 22:12:09321
322 // Destroying the message must also close the attached pipe.
323 MojoHandleSignalsState signals_state;
324 EXPECT_EQ(MOJO_RESULT_OK, mojo().QueryHandleSignalsState(a, &signals_state));
325 EXPECT_EQ(0u,
326 signals_state.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
327 EXPECT_EQ(MOJO_RESULT_OK, mojo().DestroyMessage(message));
328 EXPECT_EQ(MOJO_RESULT_OK, mojo().QueryHandleSignalsState(a, &signals_state));
329 EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED,
330 signals_state.satisfied_signals & MOJO_HANDLE_SIGNAL_PEER_CLOSED);
331 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(a));
332}
333
334TEST_F(CoreIpczTest, MessagePipes) {
335 MojoHandle a, b;
336 MojoHandle c, d;
337 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateMessagePipe(nullptr, &a, &b));
338 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateMessagePipe(nullptr, &c, &d));
339
340 MojoMessageHandle message;
341 EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT, mojo().ReadMessage(a, nullptr, &message));
342
Hyowon Kim85512d9e2023-11-30 01:36:59343 constexpr std::string_view kMessage = "bazongo";
Ken Rockot227f3a42022-08-12 22:12:09344 EXPECT_EQ(MOJO_RESULT_OK,
345 mojo().WriteMessage(a, CreateMessage(kMessage), nullptr));
346
Ken Rockotfffc10c2022-09-07 21:05:53347 constexpr SignalExpectations kReadablePipeExpecations = {
348 .satisfiable = MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE |
349 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
350 .satisfied = MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
351 .not_satisfied = MOJO_HANDLE_SIGNAL_PEER_CLOSED,
352 };
Ken Rockot227f3a42022-08-12 22:12:09353
Ken Rockotfffc10c2022-09-07 21:05:53354 CheckSignals(b, kReadablePipeExpecations);
Ken Rockot227f3a42022-08-12 22:12:09355 EXPECT_EQ(MOJO_RESULT_OK, mojo().FuseMessagePipes(b, c, nullptr));
Ken Rockotfffc10c2022-09-07 21:05:53356 CheckSignals(d, kReadablePipeExpecations);
Ken Rockot227f3a42022-08-12 22:12:09357
358 EXPECT_EQ(MOJO_RESULT_OK, mojo().ReadMessage(d, nullptr, &message));
359 EXPECT_NE(MOJO_MESSAGE_HANDLE_INVALID, message);
360
361 void* buffer;
362 uint32_t buffer_size;
363 EXPECT_EQ(MOJO_RESULT_OK,
364 mojo().GetMessageData(message, nullptr, &buffer, &buffer_size,
365 nullptr, nullptr));
366
367 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(a));
368
369 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
370 mojo().WriteMessage(d, message, nullptr));
371 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
372 mojo().ReadMessage(d, nullptr, &message));
373 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(d));
374}
375
Ken Rockot4de88ac2022-08-15 21:55:27376TEST_F(CoreIpczTest, Traps) {
377 MojoHandle a, b;
378 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateMessagePipe(nullptr, &a, &b));
379
380 // A simple trap event handler which treats its event context as a
381 // MojoTrapEvent pointer, where the fired event will be copied.
382 auto handler = [](const MojoTrapEvent* event) {
383 *reinterpret_cast<MojoTrapEvent*>(event->trigger_context) = *event;
384 };
385 MojoHandle trap;
386 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateTrap(handler, nullptr, &trap));
387
388 // Initialize these events with an impossible result code.
389 MojoTrapEvent readable_event = {.result = MOJO_RESULT_UNKNOWN};
390 MojoTrapEvent writable_event = {.result = MOJO_RESULT_UNKNOWN};
391 uintptr_t kReadableContext = reinterpret_cast<uintptr_t>(&readable_event);
392 uintptr_t kWritableContext = reinterpret_cast<uintptr_t>(&writable_event);
393 EXPECT_EQ(MOJO_RESULT_OK,
394 mojo().AddTrigger(trap, b, MOJO_HANDLE_SIGNAL_READABLE,
395 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
396 kReadableContext, nullptr));
397 EXPECT_EQ(MOJO_RESULT_OK,
398 mojo().AddTrigger(trap, b, MOJO_HANDLE_SIGNAL_WRITABLE,
399 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
400 kWritableContext, nullptr));
401
402 // Arming should fail because the pipe is always writable.
403 uint32_t num_events = 1;
404 MojoTrapEvent event = {.struct_size = sizeof(event)};
405 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
406 mojo().ArmTrap(trap, nullptr, &num_events, &event));
407 EXPECT_EQ(kWritableContext, event.trigger_context);
408 EXPECT_EQ(MOJO_RESULT_OK, event.result);
409
410 // But we should be able to arm after removing that trigger. Trigger removal
411 // should also notify the writable trigger of cancellation.
412 EXPECT_EQ(MOJO_RESULT_OK,
413 mojo().RemoveTrigger(trap, kWritableContext, nullptr));
414 EXPECT_EQ(MOJO_RESULT_CANCELLED, writable_event.result);
415 EXPECT_EQ(MOJO_RESULT_OK, mojo().ArmTrap(trap, nullptr, nullptr, nullptr));
416
417 // Making `b` readable by writing to `a` should immediately activate the
418 // remaining trigger.
419 EXPECT_EQ(MOJO_RESULT_UNKNOWN, readable_event.result);
420 EXPECT_EQ(MOJO_RESULT_OK,
421 mojo().WriteMessage(a, CreateMessage("lol"), nullptr));
422 EXPECT_EQ(MOJO_RESULT_CANCELLED, writable_event.result);
423 EXPECT_EQ(MOJO_RESULT_OK, readable_event.result);
424
425 // Clear the pipe and re-arm the trap.
426 MojoMessageHandle message;
427 EXPECT_EQ(MOJO_RESULT_OK, mojo().ReadMessage(b, nullptr, &message));
428 EXPECT_EQ(MOJO_RESULT_OK, mojo().DestroyMessage(message));
429 EXPECT_EQ(MOJO_RESULT_OK, mojo().ArmTrap(trap, nullptr, nullptr, nullptr));
430
431 // Closing `a` should activate the readable trigger again, this time to signal
432 // its permanent unsatisfiability.
433 EXPECT_EQ(MOJO_RESULT_OK, readable_event.result);
434 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(a));
435 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, readable_event.result);
436
437 // Closing `b` itself should elicit one final cancellation event.
438 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(b));
439 EXPECT_EQ(MOJO_RESULT_CANCELLED, readable_event.result);
440
441 // Finally, closing the trap with an active trigger should also elicit a
442 // cancellation event.
443 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateMessagePipe(nullptr, &a, &b));
444 readable_event.result = MOJO_RESULT_UNKNOWN;
445 EXPECT_EQ(MOJO_RESULT_OK,
446 mojo().AddTrigger(trap, b, MOJO_HANDLE_SIGNAL_READABLE,
447 MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
448 kReadableContext, nullptr));
449 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(trap));
450 EXPECT_EQ(MOJO_RESULT_CANCELLED, readable_event.result);
451
452 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(a));
453 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(b));
454}
455
Ken Rockot9afacb072022-08-18 11:11:34456TEST_F(CoreIpczTest, WrapPlatformHandle) {
457 PlatformChannel channel;
458
459 // We can wrap and unwrap a handle intact.
460 MojoHandle wrapped_handle;
461 MojoPlatformHandle mojo_handle = {.struct_size = sizeof(mojo_handle)};
462 PlatformHandle::ToMojoPlatformHandle(
463 channel.TakeLocalEndpoint().TakePlatformHandle(), &mojo_handle);
464 EXPECT_EQ(MOJO_RESULT_OK,
465 mojo().WrapPlatformHandle(&mojo_handle, nullptr, &wrapped_handle));
466 EXPECT_EQ(MOJO_RESULT_OK,
467 mojo().UnwrapPlatformHandle(wrapped_handle, nullptr, &mojo_handle));
468
469 ChannelPeerClosureListener listener(
470 PlatformHandle::FromMojoPlatformHandle(&mojo_handle));
471
472 // Closing a handle wrapper closes the underlying handle.
473 PlatformHandle::ToMojoPlatformHandle(
474 channel.TakeRemoteEndpoint().TakePlatformHandle(), &mojo_handle);
475 EXPECT_EQ(MOJO_RESULT_OK,
476 mojo().WrapPlatformHandle(&mojo_handle, nullptr, &wrapped_handle));
477 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(wrapped_handle));
478
479 listener.WaitForPeerClosure();
480}
481
Ken Rockot81738e8a2022-08-19 07:35:05482TEST_F(CoreIpczTest, BasicSharedBuffer) {
Hyowon Kim85512d9e2023-11-30 01:36:59483 const std::string_view kContents = "steamed hams";
Ken Rockot81738e8a2022-08-19 07:35:05484 MojoHandle buffer;
485 EXPECT_EQ(MOJO_RESULT_OK,
486 mojo().CreateSharedBuffer(kContents.size(), nullptr, &buffer));
487
488 // New Mojo shared buffers are always writable by default.
489 SharedBufferDetails details = PeekSharedBuffer(buffer);
490 EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE,
491 details.mode);
492 EXPECT_EQ(kContents.size(), details.size);
493
494 void* address;
495 EXPECT_EQ(MOJO_RESULT_OK,
496 mojo().MapBuffer(buffer, 0, kContents.size(), nullptr, &address));
497 memcpy(address, kContents.data(), kContents.size());
498 EXPECT_EQ(MOJO_RESULT_OK, mojo().UnmapBuffer(address));
499 address = nullptr;
500
501 // We can duplicate to handle which can only be mapped for reading.
502 MojoHandle readonly_buffer;
503 const MojoDuplicateBufferHandleOptions readonly_options = {
504 .struct_size = sizeof(readonly_options),
505 .flags = MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY,
506 };
507 EXPECT_EQ(MOJO_RESULT_OK, mojo().DuplicateBufferHandle(
508 buffer, &readonly_options, &readonly_buffer));
509
510 // With a read-only duplicate, it should now be impossible to create a
511 // writable duplicate, and the original buffer handle should now be in
512 // read-only mode.
513 MojoHandle writable_buffer;
514 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
515 mojo().DuplicateBufferHandle(buffer, nullptr, &writable_buffer));
516
517 details = PeekSharedBuffer(buffer);
518 EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY,
519 details.mode);
520 EXPECT_EQ(kContents.size(), details.size);
521
522 details = PeekSharedBuffer(readonly_buffer);
523 EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY,
524 details.mode);
525 EXPECT_EQ(kContents.size(), details.size);
526
527 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(buffer));
528
529 // Additional read-only duplicates are OK though.
530 MojoHandle dupe;
531 EXPECT_EQ(MOJO_RESULT_OK, mojo().DuplicateBufferHandle(
532 readonly_buffer, &readonly_options, &dupe));
533 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(dupe));
534
535 // And finally we can map the buffer again to find the same contents.
536 EXPECT_EQ(MOJO_RESULT_OK,
537 mojo().MapBuffer(readonly_buffer, 0, kContents.size(), nullptr,
538 &address));
Hyowon Kim85512d9e2023-11-30 01:36:59539 EXPECT_EQ(kContents, std::string_view(static_cast<const char*>(address),
540 kContents.size()));
Ken Rockot81738e8a2022-08-19 07:35:05541 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(readonly_buffer));
542}
543
544TEST_F(CoreIpczTest, SharedBufferDuplicateUnsafe) {
545 // A buffer which has been duplicated at least once without READ_ONLY can
546 // never be duplicated as read-only.
547 constexpr size_t kSize = 64;
548 MojoHandle buffer;
549 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateSharedBuffer(kSize, nullptr, &buffer));
550
551 MojoHandle dupe;
552 EXPECT_EQ(MOJO_RESULT_OK,
553 mojo().DuplicateBufferHandle(buffer, nullptr, &dupe));
554
555 SharedBufferDetails details = PeekSharedBuffer(buffer);
556 EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE,
557 details.mode);
558 EXPECT_EQ(kSize, details.size);
559
560 details = PeekSharedBuffer(dupe);
561 EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE,
562 details.mode);
563 EXPECT_EQ(kSize, details.size);
564
565 MojoHandle readonly_dupe;
566 MojoDuplicateBufferHandleOptions options = {
567 .struct_size = sizeof(options),
568 .flags = MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY,
569 };
570 EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
571 mojo().DuplicateBufferHandle(buffer, &options, &readonly_dupe));
572
573 // Unsafe duplication is still possible though.
574 MojoHandle unsafe_dupe;
575 EXPECT_EQ(MOJO_RESULT_OK,
576 mojo().DuplicateBufferHandle(buffer, nullptr, &unsafe_dupe));
577 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(unsafe_dupe));
578 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(dupe));
579 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(buffer));
580}
581
Ken Rockotfffc10c2022-09-07 21:05:53582TEST_F(CoreIpczTest, DataPipeReadWriteQeury) {
583 MojoHandle p, c;
584 MojoCreateDataPipeOptions options = {
585 .struct_size = sizeof(options),
586 .element_num_bytes = 1,
587 .capacity_num_bytes = 5,
588 };
589 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateDataPipe(&options, &p, &c));
590
591 // First check for valid initial signaling state on producer and the consumer.
592 CheckSignals(p, {
593 .satisfiable = MOJO_HANDLE_SIGNAL_WRITABLE |
594 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
595 .not_satisfiable = MOJO_HANDLE_SIGNAL_READABLE |
596 MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
597 .satisfied = MOJO_HANDLE_SIGNAL_WRITABLE,
598 .not_satisfied = MOJO_HANDLE_SIGNAL_READABLE |
599 MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
600 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
601 });
602 CheckSignals(c, {
603 .satisfiable = MOJO_HANDLE_SIGNAL_READABLE |
604 MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
605 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
606 .not_satisfiable = MOJO_HANDLE_SIGNAL_WRITABLE,
607 .not_satisfied = MOJO_HANDLE_SIGNAL_READABLE |
608 MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE |
609 MOJO_HANDLE_SIGNAL_WRITABLE |
610 MOJO_HANDLE_SIGNAL_PEER_CLOSED,
611 });
612
613 // Basic capacity limits are enforced.
614 MojoWriteDataOptions write_options = {
615 .struct_size = sizeof(write_options),
616 .flags = MOJO_WRITE_DATA_FLAG_ALL_OR_NONE,
617 };
Hyowon Kim85512d9e2023-11-30 01:36:59618 constexpr std::string_view kTestMessage = "hello, world!";
Ken Rockotfffc10c2022-09-07 21:05:53619 uint32_t num_bytes = static_cast<uint32_t>(kTestMessage.size());
620 EXPECT_EQ(
621 MOJO_RESULT_OUT_OF_RANGE,
622 mojo().WriteData(p, kTestMessage.data(), &num_bytes, &write_options));
623
624 // Partial writes can succeed when short on capacity.
625 write_options.flags = MOJO_WRITE_DATA_FLAG_NONE;
626 num_bytes = static_cast<uint32_t>(kTestMessage.size());
627 EXPECT_EQ(MOJO_RESULT_OK, mojo().WriteData(p, kTestMessage.data(), &num_bytes,
628 &write_options));
629 EXPECT_EQ(5u, num_bytes);
630
631 // Writability should no longer be signaled, but should still be possible in
632 // the future.
633 CheckSignals(p, {
634 .satisfiable = MOJO_HANDLE_SIGNAL_WRITABLE,
635 .not_satisfied = MOJO_HANDLE_SIGNAL_WRITABLE,
636 });
637 CheckSignals(c, {.satisfied = MOJO_HANDLE_SIGNAL_READABLE});
638
639 // Query only requests the number of available bytes. No data is consumed or
640 // copied and no buffer is required.
641 MojoReadDataOptions read_options = {
642 .struct_size = sizeof(read_options),
643 .flags = MOJO_READ_DATA_FLAG_QUERY,
644 };
645 EXPECT_EQ(MOJO_RESULT_OK,
646 mojo().ReadData(c, &read_options, nullptr, &num_bytes));
647 EXPECT_EQ(5u, num_bytes);
648 CheckSignals(c, {.satisfied = MOJO_HANDLE_SIGNAL_READABLE});
649
650 // Peek requires a buffer and copies data into it, but does not consume
651 // anything from the pipe.
652 read_options.flags = MOJO_READ_DATA_FLAG_PEEK;
653 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
654 mojo().ReadData(c, &read_options, nullptr, &num_bytes));
655
656 char buffer[kTestMessage.size()];
657 num_bytes = std::size(buffer);
658 EXPECT_EQ(MOJO_RESULT_OK,
659 mojo().ReadData(c, &read_options, buffer, &num_bytes));
Hyowon Kim85512d9e2023-11-30 01:36:59660 EXPECT_EQ("hello", std::string_view(buffer, num_bytes));
Ken Rockotfffc10c2022-09-07 21:05:53661 CheckSignals(c, {.satisfied = MOJO_HANDLE_SIGNAL_READABLE});
662
663 // Discard does not require a buffer and copies no data, but it does consume
664 // bytes from the pipe.
665 read_options.flags = MOJO_READ_DATA_FLAG_DISCARD;
666 num_bytes = 1;
667 EXPECT_EQ(MOJO_RESULT_OK,
668 mojo().ReadData(c, &read_options, nullptr, &num_bytes));
669 CheckSignals(p, {.satisfied = MOJO_HANDLE_SIGNAL_WRITABLE});
670 CheckSignals(c, {.satisfied = MOJO_HANDLE_SIGNAL_READABLE});
671
672 // An all-or-none read fails if all the data isn't available.
673 read_options.flags = MOJO_READ_DATA_FLAG_ALL_OR_NONE;
674 num_bytes = std::size(buffer);
675 EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
676 mojo().ReadData(c, &read_options, buffer, &num_bytes));
677 CheckSignals(c, {.satisfied = MOJO_HANDLE_SIGNAL_READABLE});
678
679 // Try again with data in range.
680 num_bytes = 3;
681 EXPECT_EQ(MOJO_RESULT_OK,
682 mojo().ReadData(c, &read_options, buffer, &num_bytes));
Hyowon Kim85512d9e2023-11-30 01:36:59683 EXPECT_EQ("ell", std::string_view(buffer, num_bytes));
Ken Rockotfffc10c2022-09-07 21:05:53684 CheckSignals(c, {.satisfied = MOJO_HANDLE_SIGNAL_READABLE});
685
686 // Finally, default options allow for short reads.
687 char bigger_buffer[100];
688 num_bytes = std::size(bigger_buffer);
689 read_options.flags = MOJO_READ_DATA_FLAG_NONE;
690 EXPECT_EQ(MOJO_RESULT_OK,
691 mojo().ReadData(c, &read_options, bigger_buffer, &num_bytes));
692 CheckSignals(c, {.not_satisfied = MOJO_HANDLE_SIGNAL_READABLE});
693
Hyowon Kim85512d9e2023-11-30 01:36:59694 EXPECT_EQ("o", std::string_view(bigger_buffer, num_bytes));
Ken Rockotfffc10c2022-09-07 21:05:53695
696 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(p));
697 CheckSignals(c, {.not_satisfiable = MOJO_HANDLE_SIGNAL_READABLE |
698 MOJO_HANDLE_SIGNAL_NEW_DATA_READABLE,
699 .satisfied = MOJO_HANDLE_SIGNAL_PEER_CLOSED});
700 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(c));
701}
702
703TEST_F(CoreIpczTest, DataPipeTwoPhase) {
704 MojoHandle p, c;
705 MojoCreateDataPipeOptions options = {
706 .struct_size = sizeof(options),
707 .element_num_bytes = 1,
708 .capacity_num_bytes = 5,
709 };
710 EXPECT_EQ(MOJO_RESULT_OK, mojo().CreateDataPipe(&options, &p, &c));
711
Hyowon Kim85512d9e2023-11-30 01:36:59712 const std::string_view kTestMessage = "hello, world!";
Ken Rockotfffc10c2022-09-07 21:05:53713
714 void* buffer;
715 uint32_t num_bytes = static_cast<uint32_t>(kTestMessage.size());
716 EXPECT_EQ(MOJO_RESULT_OK,
717 mojo().BeginWriteData(p, nullptr, &buffer, &num_bytes));
718 EXPECT_EQ(5u, num_bytes);
719 EXPECT_TRUE(buffer);
720
721 memcpy(buffer, kTestMessage.data(), num_bytes);
722 EXPECT_EQ(MOJO_RESULT_OK, mojo().EndWriteData(p, num_bytes, nullptr));
723
724 const void* in_buffer;
725 EXPECT_EQ(MOJO_RESULT_OK,
726 mojo().BeginReadData(c, nullptr, &in_buffer, &num_bytes));
727 EXPECT_EQ(5u, num_bytes);
728 EXPECT_EQ("hello",
Hyowon Kim85512d9e2023-11-30 01:36:59729 std::string_view(static_cast<const char*>(in_buffer), num_bytes));
Ken Rockotfffc10c2022-09-07 21:05:53730
731 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(p));
732 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(c));
733}
734
Gyuyoung Kim789fdc32023-04-01 15:30:56735#if BUILDFLAG(USE_BLINK)
Ken Rockotb26d96c2022-09-02 00:28:20736
Hyowon Kim85512d9e2023-11-30 01:36:59737constexpr std::string_view kAttachmentName = "interesting pipe name";
Ken Rockotb26d96c2022-09-02 00:28:20738
Hyowon Kim85512d9e2023-11-30 01:36:59739constexpr std::string_view kTestMessages[] = {
Ken Rockotb26d96c2022-09-02 00:28:20740 "hello hello",
741 "i don't know why you say goodbye",
742 "actually nvm i do",
743 "lol bye",
744};
745
746DEFINE_TEST_CLIENT_TEST_WITH_PIPE(InvitationSingleAttachmentClient,
747 CoreIpczTestClient,
748 h) {
749 InvitationDetails details;
750 ReceiveInvitationTransport(h, details);
Ken Rockot7b81f182022-09-07 23:01:03751 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h));
Ken Rockotb26d96c2022-09-02 00:28:20752
753 MojoHandle invitation;
754 EXPECT_EQ(MOJO_RESULT_OK,
755 mojo().AcceptInvitation(&details.endpoint, nullptr, &invitation));
756
757 MojoHandle new_pipe;
758 EXPECT_EQ(MOJO_RESULT_OK, mojo().ExtractMessagePipeFromInvitation(
759 invitation, kAttachmentName.data(),
760 kAttachmentName.size(), nullptr, &new_pipe));
761 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(invitation));
762
763 WriteToMessagePipe(new_pipe, kTestMessages[3]);
764 EXPECT_EQ(kTestMessages[0], ReadFromMessagePipe(new_pipe));
765 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(new_pipe));
766}
767
768TEST_F(CoreIpczTest, InvitationSingleAttachment) {
Ken Rockota1427712022-09-08 01:24:05769 if (IsMojoIpczEnabled()) {
770 GTEST_SKIP() << "This is does not work with the MojoIpcz feature enabled, "
771 << "since its setup conflicts with normal Mojo initialization "
772 << "in that case. It is also redundant in that case since "
773 << "various invitation unittests cover the same code paths.";
774 }
775
Ken Rockotb26d96c2022-09-02 00:28:20776 RunTestClientWithController(
777 "InvitationSingleAttachmentClient", [&](ClientController& c) {
778 InvitationDetails details;
779 CreateAndShareInvitationTransport(c.pipe(), c.process(), details);
780
781 MojoHandle new_pipe;
782 MojoHandle invitation;
783 EXPECT_EQ(MOJO_RESULT_OK,
784 mojo().CreateInvitation(nullptr, &invitation));
785 EXPECT_EQ(MOJO_RESULT_OK,
786 mojo().AttachMessagePipeToInvitation(
787 invitation, kAttachmentName.data(),
788 kAttachmentName.size(), nullptr, &new_pipe));
789 EXPECT_EQ(MOJO_RESULT_OK, mojo().SendInvitation(
790 invitation, &details.process,
791 &details.endpoint, nullptr, 0, nullptr));
792 EXPECT_EQ(kTestMessages[3], ReadFromMessagePipe(new_pipe));
793 WriteToMessagePipe(new_pipe, kTestMessages[0]);
794 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(new_pipe));
795 });
796}
797
798DEFINE_TEST_CLIENT_TEST_WITH_PIPE(InvitationMultipleAttachmentsClient,
799 CoreIpczTestClient,
800 h) {
801 InvitationDetails details;
802 ReceiveInvitationTransport(h, details);
Ken Rockot7b81f182022-09-07 23:01:03803 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h));
Ken Rockotb26d96c2022-09-02 00:28:20804
805 MojoHandle invitation;
806 EXPECT_EQ(MOJO_RESULT_OK,
807 mojo().AcceptInvitation(&details.endpoint, nullptr, &invitation));
808
809 for (uint32_t i = 0; i < std::size(kTestMessages); ++i) {
810 MojoHandle pipe;
811 EXPECT_EQ(MOJO_RESULT_OK, mojo().ExtractMessagePipeFromInvitation(
812 invitation, &i, sizeof(i), nullptr, &pipe));
813 WriteToMessagePipe(pipe, kTestMessages[i]);
814 EXPECT_EQ(kTestMessages[i], ReadFromMessagePipe(pipe));
815 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(pipe));
816 }
817 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(invitation));
818}
819
820TEST_F(CoreIpczTest, InvitationMultipleAttachments) {
Ken Rockota1427712022-09-08 01:24:05821 if (IsMojoIpczEnabled()) {
822 GTEST_SKIP() << "This is does not work with the MojoIpcz feature enabled, "
823 << "since its setup conflicts with normal Mojo initialization "
824 << "in that case. It is also redundant in that case since "
825 << "various invitation unittests cover the same code paths.";
826 }
827
Ken Rockotb26d96c2022-09-02 00:28:20828 RunTestClientWithController(
829 "InvitationMultipleAttachmentsClient", [&](ClientController& c) {
830 InvitationDetails details;
831 CreateAndShareInvitationTransport(c.pipe(), c.process(), details);
832
833 MojoHandle invitation;
834 EXPECT_EQ(MOJO_RESULT_OK,
835 mojo().CreateInvitation(nullptr, &invitation));
836
837 MojoHandle pipes[std::size(kTestMessages)];
838 for (uint32_t i = 0; i < std::size(pipes); ++i) {
839 EXPECT_EQ(MOJO_RESULT_OK,
840 mojo().AttachMessagePipeToInvitation(
841 invitation, &i, sizeof(i), nullptr, &pipes[i]));
842 }
843 EXPECT_EQ(MOJO_RESULT_OK, mojo().SendInvitation(
844 invitation, &details.process,
845 &details.endpoint, nullptr, 0, nullptr));
846
847 for (size_t i = 0; i < std::size(pipes); ++i) {
848 EXPECT_EQ(kTestMessages[i], ReadFromMessagePipe(pipes[i]));
849 WriteToMessagePipe(pipes[i], kTestMessages[i]);
850 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(pipes[i]));
851 }
852 });
853}
854
Hyowon Kim85512d9e2023-11-30 01:36:59855constexpr std::string_view kDataPipeMessage = "hello, world!";
Ken Rockotfffc10c2022-09-07 21:05:53856constexpr size_t kDataPipeCapacity = 8;
857static_assert(kDataPipeCapacity < kDataPipeMessage.size(),
858 "Test requires a data pipe smaller than the test message.");
859
860DEFINE_TEST_CLIENT_TEST_WITH_PIPE(DataPipeTransferClient,
861 CoreIpczTestClient,
862 h) {
863 InvitationDetails details;
864 ReceiveInvitationTransport(h, details);
865 EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h));
866
867 MojoHandle invitation;
868 EXPECT_EQ(MOJO_RESULT_OK,
869 mojo().AcceptInvitation(&details.endpoint, nullptr, &invitation));
870
871 MojoHandle new_pipe;
872 EXPECT_EQ(MOJO_RESULT_OK, mojo().ExtractMessagePipeFromInvitation(
873 invitation, kAttachmentName.data(),
874 kAttachmentName.size(), nullptr, &new_pipe));
875 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(invitation));
876
877 MojoHandle consumer;
Will Harrise61641f2023-02-07 19:35:02878 EXPECT_EQ("", ReadFromMessagePipe(new_pipe, {&consumer, 1u}));
Ken Rockotfffc10c2022-09-07 21:05:53879 EXPECT_NE(MOJO_HANDLE_INVALID, consumer);
880
881 WaitForReadable(consumer);
882
883 const void* data;
884 uint32_t num_bytes;
885 EXPECT_EQ(MOJO_RESULT_OK,
886 mojo().BeginReadData(consumer, nullptr, &data, &num_bytes));
887 EXPECT_EQ(kDataPipeCapacity, num_bytes);
888 EXPECT_EQ(kDataPipeMessage.substr(0, kDataPipeCapacity),
889 std::string(static_cast<const char*>(data), num_bytes));
890 EXPECT_EQ(MOJO_RESULT_OK, mojo().EndReadData(consumer, 0, nullptr));
891 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(consumer));
892 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(new_pipe));
893}
894
895TEST_F(CoreIpczTest, DataPipeTransfer) {
Ken Rockota1427712022-09-08 01:24:05896 if (IsMojoIpczEnabled()) {
897 GTEST_SKIP() << "This is does not work with the MojoIpcz feature enabled, "
898 << "since its setup conflicts with normal Mojo initialization "
899 << "in that case. It is also redundant in that case since "
900 << "various invitation unittests cover the same code paths.";
901 }
902
Ken Rockotfffc10c2022-09-07 21:05:53903 RunTestClientWithController(
904 "DataPipeTransferClient", [&](ClientController& c) {
905 InvitationDetails details;
906 CreateAndShareInvitationTransport(c.pipe(), c.process(), details);
907
908 MojoHandle new_pipe;
909 MojoHandle invitation;
910 EXPECT_EQ(MOJO_RESULT_OK,
911 mojo().CreateInvitation(nullptr, &invitation));
912 EXPECT_EQ(MOJO_RESULT_OK,
913 mojo().AttachMessagePipeToInvitation(
914 invitation, kAttachmentName.data(),
915 kAttachmentName.size(), nullptr, &new_pipe));
916 EXPECT_EQ(MOJO_RESULT_OK, mojo().SendInvitation(
917 invitation, &details.process,
918 &details.endpoint, nullptr, 0, nullptr));
919
920 const MojoCreateDataPipeOptions options = {
921 .struct_size = sizeof(options),
922 .element_num_bytes = 1,
923 .capacity_num_bytes = kDataPipeCapacity,
924 };
925 MojoHandle producer;
926 MojoHandle consumer;
927 EXPECT_EQ(MOJO_RESULT_OK,
928 mojo().CreateDataPipe(&options, &producer, &consumer));
929 EXPECT_EQ(MOJO_RESULT_OK,
930 mojo().WriteMessage(
Will Harrise61641f2023-02-07 19:35:02931 new_pipe, CreateMessage("", {&consumer, 1u}), nullptr));
Ken Rockotfffc10c2022-09-07 21:05:53932 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(new_pipe));
933
934 // First attempt an oversized write, which should fail because this
935 // producer has a smaller capacity than required.
936 const MojoWriteDataOptions write_all = {
937 .struct_size = sizeof(options),
938 .flags = MOJO_WRITE_DATA_FLAG_ALL_OR_NONE,
939 };
940 uint32_t num_bytes = static_cast<uint32_t>(kDataPipeMessage.size());
941 EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
942 mojo().WriteData(producer, kDataPipeMessage.data(),
943 &num_bytes, &write_all));
944
945 // Now let the write proceed with as much data as possible.
946 EXPECT_EQ(MOJO_RESULT_OK,
947 mojo().WriteData(producer, kDataPipeMessage.data(),
948 &num_bytes, nullptr));
949 EXPECT_EQ(kDataPipeCapacity, num_bytes);
950 EXPECT_EQ(MOJO_RESULT_OK, mojo().Close(producer));
951 });
952}
953
Gyuyoung Kim789fdc32023-04-01 15:30:56954#endif // BUILDFLAG(USE_BLINK)
Ken Rockotb26d96c2022-09-02 00:28:20955
Ken Rockot6daf45222022-08-11 22:04:47956} // namespace
957} // namespace mojo::core