1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
#pragma allow_unsafe_libc_calls
#endif
#include "mojo/core/node_channel.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/message_loop/message_pump_type.h"
#include "base/test/task_environment.h"
#include "base/threading/thread.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/test/mock_node_channel_delegate.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace core {
namespace {
using ports::NodeName;
using testing::_;
class NodeChannelTest : public testing::Test {
public:
void SetUp() override {
if (IsMojoIpczEnabled()) {
GTEST_SKIP() << "NodeChannel is never used when ipcz is enabled, so "
<< "these tests are neither supported nor relevant.";
}
}
MockNodeChannelDelegate local_delegate_;
MockNodeChannelDelegate remote_delegate_;
};
scoped_refptr<NodeChannel> CreateNodeChannel(NodeChannel::Delegate* delegate,
PlatformChannelEndpoint endpoint) {
return NodeChannel::Create(delegate, ConnectionParams(std::move(endpoint)),
Channel::HandlePolicy::kAcceptHandles,
GetIOTaskRunner(), base::NullCallback());
}
TEST_F(NodeChannelTest, DestructionIsSafe) {
// Regression test for https://crbug.com/1081874.
base::test::TaskEnvironment task_environment;
PlatformChannel channel;
auto local_channel =
CreateNodeChannel(&local_delegate_, channel.TakeLocalEndpoint());
local_channel->Start();
auto remote_channel =
CreateNodeChannel(&remote_delegate_, channel.TakeRemoteEndpoint());
remote_channel->Start();
// Verify end-to-end operation
const NodeName kRemoteNodeName{123, 456};
const NodeName kToken{987, 654};
base::RunLoop loop;
EXPECT_CALL(local_delegate_,
OnAcceptInvitee(ports::kInvalidNodeName, kRemoteNodeName, kToken))
.WillRepeatedly([&] { loop.Quit(); });
remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
loop.Run();
// Now send another message to the local endpoint but tear it down
// immediately. This will race with the message being received on the IO
// thread, and although the corresponding delegate call may or may not
// dispatch as a result, the race should still be memory-safe.
remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
base::RunLoop error_loop;
EXPECT_CALL(remote_delegate_, OnChannelError).WillOnce([&] {
error_loop.Quit();
});
local_channel.reset();
error_loop.Run();
}
TEST_F(NodeChannelTest, MessagesCannotBeSmallerThanOldestVersion) {
base::test::TaskEnvironment task_environment;
PlatformChannel channel;
auto local_channel =
CreateNodeChannel(&local_delegate_, channel.TakeLocalEndpoint());
local_channel->Start();
auto remote_channel =
CreateNodeChannel(&remote_delegate_, channel.TakeRemoteEndpoint());
remote_channel->Start();
base::RunLoop loop;
// It's a bad message and shouldn't be passed to the delegate.
EXPECT_CALL(local_delegate_, OnRequestPortMerge(_, _, _)).Times(0);
// This good message should go through after.
const NodeName kRemoteNodeName{123, 456};
const NodeName kToken{987, 654};
EXPECT_CALL(local_delegate_,
OnAcceptInvitee(ports::kInvalidNodeName, kRemoteNodeName, kToken))
.WillRepeatedly([&] { loop.Quit(); });
// 1 byte is not enough to contain the oldest version of the request port
// merge payload, it should be discarded.
int payload_size = 1;
int capacity = /*sizeof(header)=*/8 + payload_size;
auto message =
Channel::Message::CreateMessage(capacity, capacity, /*num_handles=*/0);
memset(message->mutable_payload(), 0, capacity);
// Set the type of this message as REQUEST_PORT_MERGE (6)
*reinterpret_cast<uint32_t*>(message->mutable_payload()) = 6;
// This short message should be ignored.
remote_channel->SendChannelMessage(std::move(message));
remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
loop.Run();
remote_channel->ShutDown();
local_channel->ShutDown();
}
} // namespace
} // namespace core
} // namespace mojo
|