Skip to content

Commit ef67b80

Browse files
krockotChromium LUCI CQ
authored andcommitted
ipcz: Implement basic node connection
Split out from the ipcz uber-CL: https://crrev.com/c/3570271 Introduces NodeConnector and some associated ipcz messages which will be used by ConnectNode() to bootstrap new NodeLinks between nodes. A NodeConnector is a short-lived object which takes initial ownership of a DriverTransport to transmit and listen for appropriate handshake messages. Once handshake is complete, the transport is passed on to a newly created NodeLink and given to whichever Node initiated a connection on the transport. This does not actually implement the ConnectNode() API yet. This CL is primarily about landing the most important NodeConnector implementations (broker-to-non-broker, and non-broker-to-broker) and getting test coverage for them. Bug: 1299283 Change-Id: I389ac8796c36446661fe1d96f63254fc96a95cad Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3621786 Commit-Queue: Ken Rockot <rockot@google.com> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Cr-Commit-Position: refs/heads/main@{#1001227}
1 parent 7fdf632 commit ef67b80

15 files changed

+1135
-69
lines changed

third_party/ipcz/src/BUILD.gn

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@ ipcz_source_set("impl") {
169169
"ipcz/link_type.h",
170170
"ipcz/message_internal.h",
171171
"ipcz/node.h",
172+
"ipcz/node_connector.h",
172173
"ipcz/node_link.h",
174+
"ipcz/node_messages.h",
173175
"ipcz/parcel.h",
174176
"ipcz/parcel_queue.h",
175177
"ipcz/portal.h",
@@ -198,9 +200,9 @@ ipcz_source_set("impl") {
198200
"ipcz/message_macros/message_params_declaration_macros.h",
199201
"ipcz/message_macros/undef_message_macros.h",
200202
"ipcz/node.cc",
203+
"ipcz/node_connector.cc",
201204
"ipcz/node_link.cc",
202205
"ipcz/node_messages.cc",
203-
"ipcz/node_messages.h",
204206
"ipcz/node_messages_generator.h",
205207
"ipcz/node_name.cc",
206208
"ipcz/node_name.h",
@@ -253,6 +255,7 @@ ipcz_source_set("ipcz_tests_sources") {
253255
"ipcz/driver_object_test.cc",
254256
"ipcz/driver_transport_test.cc",
255257
"ipcz/message_internal_test.cc",
258+
"ipcz/node_connector_test.cc",
256259
"ipcz/node_link_test.cc",
257260
"ipcz/parcel_queue_test.cc",
258261
"ipcz/sequenced_queue_test.cc",
@@ -261,6 +264,8 @@ ipcz_source_set("ipcz_tests_sources") {
261264
"test/mock_driver.h",
262265
"test/test_base.cc",
263266
"test/test_base.h",
267+
"test/test_transport_listener.cc",
268+
"test/test_transport_listener.h",
264269
"trap_test.cc",
265270
"util/ref_counted_test.cc",
266271
"util/stack_trace_test.cc",

third_party/ipcz/src/ipcz/driver_transport_test.cc

Lines changed: 13 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "ipcz/driver_object.h"
1616
#include "ipcz/node.h"
1717
#include "test/mock_driver.h"
18+
#include "test/test_transport_listener.h"
1819
#include "testing/gtest/include/gtest/gtest.h"
1920
#include "third_party/abseil-cpp/absl/base/macros.h"
2021
#include "util/ref_counted.h"
@@ -30,11 +31,6 @@ DriverTransport::Message MakeMessage(std::string_view s) {
3031
absl::MakeSpan(reinterpret_cast<const uint8_t*>(s.data()), s.size()));
3132
}
3233

33-
std::string_view MessageAsString(const DriverTransport::Message& message) {
34-
return std::string_view(reinterpret_cast<const char*>(message.data.data()),
35-
message.data.size());
36-
}
37-
3834
class DriverTransportTest : public testing::Test {
3935
public:
4036
DriverTransportTest() = default;
@@ -56,34 +52,6 @@ class DriverTransportTest : public testing::Test {
5652
IPCZ_INVALID_DRIVER_HANDLE)};
5753
};
5854

59-
class TestListener : public DriverTransport::Listener {
60-
public:
61-
using MessageHandler =
62-
std::function<IpczResult(const DriverTransport::Message&)>;
63-
using ErrorHandler = std::function<void()>;
64-
65-
explicit TestListener(MessageHandler message_handler,
66-
ErrorHandler error_handler = nullptr)
67-
: message_handler_(std::move(message_handler)),
68-
error_handler_(std::move(error_handler)) {}
69-
~TestListener() override = default;
70-
71-
IpczResult OnTransportMessage(
72-
const DriverTransport::Message& message) override {
73-
return message_handler_(message);
74-
}
75-
76-
void OnTransportError() override {
77-
if (error_handler_) {
78-
error_handler_();
79-
}
80-
}
81-
82-
private:
83-
MessageHandler message_handler_;
84-
ErrorHandler error_handler_;
85-
};
86-
8755
TEST_F(DriverTransportTest, Activation) {
8856
constexpr IpczDriverHandle kTransport0 = 5;
8957
constexpr IpczDriverHandle kTransport1 = 42;
@@ -101,24 +69,23 @@ TEST_F(DriverTransportTest, Activation) {
10169
})
10270
.RetiresOnSaturation();
10371

104-
// Verify that activation of a DriverTransport feeds the driver an activity
105-
// handler and valid ipcz handle to use when notifying ipcz of incoming
106-
// communications.
107-
b->Activate();
108-
EXPECT_NE(IPCZ_INVALID_HANDLE, ipcz_transport);
109-
EXPECT_TRUE(activity_handler);
110-
11172
// And verify that the activity handler actually invokes the transport's
11273
// Listener.
11374

11475
const std::string kTestMessage = "hihihihi";
11576
bool received = false;
116-
TestListener listener([&](const DriverTransport::Message& message) {
117-
EXPECT_EQ(kTestMessage, MessageAsString(message));
77+
test::TestTransportListener listener(b);
78+
listener.OnStringMessage([&](std::string_view message) {
79+
EXPECT_EQ(kTestMessage, message);
11880
received = true;
11981
return IPCZ_RESULT_OK;
12082
});
121-
b->set_listener(&listener);
83+
84+
// Verify that activation of a DriverTransport feeds the driver an activity
85+
// handler and valid ipcz handle to use when notifying ipcz of incoming
86+
// communications.
87+
EXPECT_NE(IPCZ_INVALID_HANDLE, ipcz_transport);
88+
EXPECT_TRUE(activity_handler);
12289

12390
EXPECT_FALSE(received);
12491
EXPECT_EQ(
@@ -135,7 +102,6 @@ TEST_F(DriverTransportTest, Activation) {
135102

136103
EXPECT_CALL(driver(), Close(kTransport1, _, _));
137104
EXPECT_CALL(driver(), Close(kTransport0, _, _));
138-
b->Deactivate();
139105

140106
// The driver must also release its handle to ipcz' DriverTransport, which it
141107
// does by an invocation of the activity handler like this. Without this, we'd
@@ -162,17 +128,9 @@ TEST_F(DriverTransportTest, Error) {
162128
})
163129
.RetiresOnSaturation();
164130

165-
b->Activate();
166-
167131
bool observed_error = false;
168-
TestListener listener(
169-
[&](const DriverTransport::Message& message) {
170-
ABSL_ASSERT(false);
171-
return IPCZ_RESULT_INVALID_ARGUMENT;
172-
},
173-
[&] { observed_error = true; });
174-
175-
b->set_listener(&listener);
132+
test::TestTransportListener listener(b);
133+
listener.OnError([&] { observed_error = true; });
176134

177135
// Verify that a driver invoking the activity handler with
178136
// IPCZ_TRANSPORT_ACTIVITY_ERROR results in an error notification on the
@@ -191,6 +149,7 @@ TEST_F(DriverTransportTest, Error) {
191149
activity_handler(ipcz_transport, nullptr, 0, nullptr, 0,
192150
IPCZ_TRANSPORT_ACTIVITY_DEACTIVATED, nullptr));
193151

152+
EXPECT_CALL(driver(), DeactivateTransport(kTransport1, _, _));
194153
EXPECT_CALL(driver(), Close(kTransport1, _, _));
195154
EXPECT_CALL(driver(), Close(kTransport0, _, _));
196155
}

third_party/ipcz/src/ipcz/node.cc

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44

55
#include "ipcz/node.h"
66

7+
#include <vector>
8+
79
#include "ipcz/ipcz.h"
10+
#include "ipcz/node_connector.h"
11+
#include "ipcz/node_link.h"
12+
#include "ipcz/portal.h"
13+
#include "ipcz/router.h"
14+
#include "third_party/abseil-cpp/absl/base/macros.h"
815
#include "third_party/abseil-cpp/absl/synchronization/mutex.h"
916
#include "util/log.h"
17+
#include "util/ref_counted.h"
1018

1119
namespace ipcz {
1220

@@ -24,6 +32,16 @@ Node::Node(Type type, const IpczDriver& driver, IpczDriverHandle driver_node)
2432
Node::~Node() = default;
2533

2634
IpczResult Node::Close() {
35+
absl::flat_hash_map<NodeName, Ref<NodeLink>> node_links;
36+
{
37+
absl::MutexLock lock(&mutex_);
38+
node_links_.swap(node_links);
39+
broker_link_.reset();
40+
}
41+
42+
for (const auto& entry : node_links) {
43+
entry.second->Deactivate();
44+
}
2745
return IPCZ_RESULT_OK;
2846
}
2947

@@ -32,6 +50,29 @@ NodeName Node::GetAssignedName() {
3250
return assigned_name_;
3351
}
3452

53+
Ref<NodeLink> Node::GetBrokerLink() {
54+
absl::MutexLock lock(&mutex_);
55+
return broker_link_;
56+
}
57+
58+
void Node::SetBrokerLink(Ref<NodeLink> link) {
59+
absl::MutexLock lock(&mutex_);
60+
ABSL_ASSERT(!broker_link_);
61+
broker_link_ = std::move(link);
62+
}
63+
64+
void Node::SetAssignedName(const NodeName& name) {
65+
absl::MutexLock lock(&mutex_);
66+
ABSL_ASSERT(!assigned_name_.is_valid());
67+
assigned_name_ = name;
68+
}
69+
70+
bool Node::AddLink(const NodeName& remote_node_name, Ref<NodeLink> link) {
71+
absl::MutexLock lock(&mutex_);
72+
auto [it, inserted] = node_links_.insert({remote_node_name, std::move(link)});
73+
return inserted;
74+
}
75+
3576
NodeName Node::GenerateRandomName() const {
3677
NodeName name;
3778
IpczResult result =

third_party/ipcz/src/ipcz/node.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
#include "ipcz/api_object.h"
99
#include "ipcz/ipcz.h"
1010
#include "ipcz/node_name.h"
11+
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
1112
#include "third_party/abseil-cpp/absl/synchronization/mutex.h"
13+
#include "third_party/abseil-cpp/absl/types/span.h"
1214

1315
namespace ipcz {
1416

17+
class NodeLink;
18+
1519
// A Node controls creation and interconnection of a collection of routers which
1620
// can establish links to and from other routers in other nodes. Every node is
1721
// assigned a globally unique name by a trusted broker node, and nodes may be
@@ -43,6 +47,30 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
4347
// Retrieves the name assigned to this node, if any.
4448
NodeName GetAssignedName();
4549

50+
// Gets a reference to the node's broker link, if it has one.
51+
Ref<NodeLink> GetBrokerLink();
52+
53+
// Sets this node's broker link, which is used e.g. to make introduction
54+
// requests.
55+
//
56+
// This is called by a NodeConnector implementation after accepting a valid
57+
// handshake message from a broker node, and `link` will be used as this
58+
// node's permanent broker.
59+
//
60+
// Note that like any other NodeLink used by this Node, the same `link` must
61+
// also be registered via AddLink() to associate it with its remote Node's
62+
// name. This is also done by NodeConnector.
63+
void SetBrokerLink(Ref<NodeLink> link);
64+
65+
// Sets this node's assigned name as given by a broker. NodeConnector is
66+
// responsible for calling on non-broker Nodes this after receiving the
67+
// expected handshake from a broker. Must not be called on broker nodes, as
68+
// they assign their own name at construction time.
69+
void SetAssignedName(const NodeName& name);
70+
71+
// Registers a new NodeLink for the given `remote_node_name`.
72+
bool AddLink(const NodeName& remote_node_name, Ref<NodeLink> link);
73+
4674
// Generates a new random NodeName using this node's driver as a source of
4775
// randomness.
4876
NodeName GenerateRandomName() const;
@@ -60,6 +88,18 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
6088
// self-assigned if this is a broker node. Once assigned, this name remains
6189
// constant through the lifetime of the node.
6290
NodeName assigned_name_ ABSL_GUARDED_BY(mutex_);
91+
92+
// A link to the first broker this node connected to. If this link is broken,
93+
// the node will lose all its other links too.
94+
Ref<NodeLink> broker_link_ ABSL_GUARDED_BY(mutex_);
95+
96+
// Lookup table of broker-assigned node names and links to those nodes. All of
97+
// these links and their associated names are received by the `broker_link_`
98+
// if this is a non-broker node. If this is a broker node, these links are
99+
// either assigned by this node itself, or received from other brokers in the
100+
// system.
101+
absl::flat_hash_map<NodeName, Ref<NodeLink>> node_links_
102+
ABSL_GUARDED_BY(mutex_);
63103
};
64104

65105
} // namespace ipcz

0 commit comments

Comments
 (0)