summaryrefslogtreecommitdiff
path: root/chromium/third_party/ipcz
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-11-28 16:14:41 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-12-13 15:19:41 +0000
commit61d9742824d54be5693191fe502325a909feca59 (patch)
treecbf28e779b11338fe52eb75b915684cd8955542c /chromium/third_party/ipcz
parent45f9ded08bb7526984b24ccb5a5327aaf6821676 (diff)
downloadqtwebengine-chromium-61d9742824d54be5693191fe502325a909feca59.tar.gz
BASELINE: Update Chromium to 108.0.5359.70
Change-Id: I77334ff232b819600f275bd3cfe41fbaa3619230 Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/445904 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/ipcz')
-rw-r--r--chromium/third_party/ipcz/BUILD.gn2
-rw-r--r--chromium/third_party/ipcz/DIR_METADATA11
-rw-r--r--chromium/third_party/ipcz/LICENSE4
-rw-r--r--chromium/third_party/ipcz/build_overrides/build.gni2
-rw-r--r--chromium/third_party/ipcz/build_overrides/gtest.gni2
-rw-r--r--chromium/third_party/ipcz/build_overrides/ipcz.gni2
-rw-r--r--chromium/third_party/ipcz/include/ipcz/ipcz.h82
-rw-r--r--chromium/third_party/ipcz/src/BUILD.gn14
-rw-r--r--chromium/third_party/ipcz/src/api.cc26
-rw-r--r--chromium/third_party/ipcz/src/api.h2
-rw-r--r--chromium/third_party/ipcz/src/api_test.cc119
-rw-r--r--chromium/third_party/ipcz/src/box_test.cc139
-rw-r--r--chromium/third_party/ipcz/src/connect_test.cc161
-rw-r--r--chromium/third_party/ipcz/src/ipcz/api_object.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/api_object.h3
-rw-r--r--chromium/third_party/ipcz/src/ipcz/atomic_queue_state.cc38
-rw-r--r--chromium/third_party/ipcz/src/ipcz/atomic_queue_state.h75
-rw-r--r--chromium/third_party/ipcz/src/ipcz/block_allocator.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/block_allocator.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/block_allocator_pool.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/block_allocator_pool.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/block_allocator_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/box.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/box.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/buffer_id.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/buffer_pool.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/buffer_pool.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/buffer_pool_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_memory.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_memory.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_memory_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_object.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_object.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_object_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_transport.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_transport.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/driver_transport_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/fragment.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/fragment.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/fragment_descriptor.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/fragment_descriptor.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/fragment_ref.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/fragment_ref.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/handle_type.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/link_side.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/link_side.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/link_type.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/link_type.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/local_router_link.cc61
-rw-r--r--chromium/third_party/ipcz/src/ipcz/local_router_link.h33
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_declaration_macros.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_definition_macros.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_dispatch_macros.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/message_params_declaration_macros.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/message_params_definition_macros.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_macros/undef_message_macros.h4
-rw-r--r--chromium/third_party/ipcz/src/ipcz/message_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/monitored_atomic.h77
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node.cc413
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node.h104
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_connector.cc141
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_connector.h16
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_connector_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_link.cc92
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_link.h12
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_link_memory.cc64
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_link_memory.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_link_memory_test.cc15
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_link_test.cc21
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_messages.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_messages.h3
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_messages_generator.h65
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_name.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_name.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_test.cc7
-rw-r--r--chromium/third_party/ipcz/src/ipcz/node_type.h30
-rw-r--r--chromium/third_party/ipcz/src/ipcz/operation_context.h46
-rw-r--r--chromium/third_party/ipcz/src/ipcz/parcel.cc7
-rw-r--r--chromium/third_party/ipcz/src/ipcz/parcel.h12
-rw-r--r--chromium/third_party/ipcz/src/ipcz/parcel_queue.cc4
-rw-r--r--chromium/third_party/ipcz/src/ipcz/parcel_queue.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/parcel_queue_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/portal.cc22
-rw-r--r--chromium/third_party/ipcz/src/ipcz/portal.h8
-rw-r--r--chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/remote_router_link.cc145
-rw-r--r--chromium/third_party/ipcz/src/ipcz/remote_router_link.h50
-rw-r--r--chromium/third_party/ipcz/src/ipcz/route_edge.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/route_edge.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/route_edge_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router.cc949
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router.h123
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router_descriptor.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router_descriptor.h56
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router_link.h68
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router_link_state.cc36
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router_link_state.h43
-rw-r--r--chromium/third_party/ipcz/src/ipcz/router_link_test.cc40
-rw-r--r--chromium/third_party/ipcz/src/ipcz/sequence_number.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/sequenced_queue.h55
-rw-r--r--chromium/third_party/ipcz/src/ipcz/sequenced_queue_test.cc55
-rw-r--r--chromium/third_party/ipcz/src/ipcz/sublink_id.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/test_messages.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/test_messages.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/test_messages_generator.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.cc2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.h2
-rw-r--r--chromium/third_party/ipcz/src/ipcz/trap_set.cc61
-rw-r--r--chromium/third_party/ipcz/src/ipcz/trap_set.h29
-rw-r--r--chromium/third_party/ipcz/src/ipcz/validator.cc37
-rw-r--r--chromium/third_party/ipcz/src/ipcz/validator.h43
-rw-r--r--chromium/third_party/ipcz/src/merge_portals_test.cc12
-rw-r--r--chromium/third_party/ipcz/src/queueing_test.cc95
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.cc12
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.h9
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/blob.cc41
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/blob.h62
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/file_descriptor.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/file_descriptor.h2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/handle_eintr.h2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/memfd_memory.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/memfd_memory.h2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/memfd_memory_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc28
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.h2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/object.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/object.h7
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/random.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/random.h2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.cc24
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.h11
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/socket_transport.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/socket_transport.h2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/socket_transport_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.cc3
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.h2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.cc2
-rw-r--r--chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.h2
-rw-r--r--chromium/third_party/ipcz/src/remote_portal_test.cc48
-rw-r--r--chromium/third_party/ipcz/src/standalone/BUILD.gn2
-rw-r--r--chromium/third_party/ipcz/src/standalone/base/logging.cc2
-rw-r--r--chromium/third_party/ipcz/src/standalone/base/logging.h2
-rw-r--r--chromium/third_party/ipcz/src/standalone/base/stack_trace.cc2
-rw-r--r--chromium/third_party/ipcz/src/standalone/base/stack_trace.h2
-rw-r--r--chromium/third_party/ipcz/src/trap_test.cc41
-rw-r--r--chromium/third_party/ipcz/src/util/log.h2
-rw-r--r--chromium/third_party/ipcz/src/util/multi_mutex_lock.h2
-rw-r--r--chromium/third_party/ipcz/src/util/ref_counted.cc2
-rw-r--r--chromium/third_party/ipcz/src/util/ref_counted.h2
-rw-r--r--chromium/third_party/ipcz/src/util/ref_counted_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/util/safe_math.h15
-rw-r--r--chromium/third_party/ipcz/src/util/safe_math_test.cc34
-rw-r--r--chromium/third_party/ipcz/src/util/stack_trace.h2
-rw-r--r--chromium/third_party/ipcz/src/util/stack_trace_test.cc2
-rw-r--r--chromium/third_party/ipcz/src/util/strong_alias.h2
165 files changed, 3027 insertions, 1336 deletions
diff --git a/chromium/third_party/ipcz/BUILD.gn b/chromium/third_party/ipcz/BUILD.gn
index 00ee98279b3..fc14e13e69d 100644
--- a/chromium/third_party/ipcz/BUILD.gn
+++ b/chromium/third_party/ipcz/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2022 The Chromium Authors. All rights reserved.
+# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/DIR_METADATA b/chromium/third_party/ipcz/DIR_METADATA
new file mode 100644
index 00000000000..dc2b868ccd8
--- /dev/null
+++ b/chromium/third_party/ipcz/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+ component: "Internals>Mojo>Core"
+}
diff --git a/chromium/third_party/ipcz/LICENSE b/chromium/third_party/ipcz/LICENSE
index 794df6b5591..57c22a518fc 100644
--- a/chromium/third_party/ipcz/LICENSE
+++ b/chromium/third_party/ipcz/LICENSE
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@@ -10,7 +10,7 @@
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
-// * Neither the name of Google Inc. nor the names of its
+// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
diff --git a/chromium/third_party/ipcz/build_overrides/build.gni b/chromium/third_party/ipcz/build_overrides/build.gni
index c406776d3e2..be40719702e 100644
--- a/chromium/third_party/ipcz/build_overrides/build.gni
+++ b/chromium/third_party/ipcz/build_overrides/build.gni
@@ -1,4 +1,4 @@
-# Copyright 2022 The Chromium Authors. All rights reserved.
+# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/build_overrides/gtest.gni b/chromium/third_party/ipcz/build_overrides/gtest.gni
index 5c2ab79cede..e0d128ff301 100644
--- a/chromium/third_party/ipcz/build_overrides/gtest.gni
+++ b/chromium/third_party/ipcz/build_overrides/gtest.gni
@@ -1,4 +1,4 @@
-# Copyright 2022 The Chromium Authors. All rights reserved.
+# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/build_overrides/ipcz.gni b/chromium/third_party/ipcz/build_overrides/ipcz.gni
index 3c630c5bf4c..c4055c317f6 100644
--- a/chromium/third_party/ipcz/build_overrides/ipcz.gni
+++ b/chromium/third_party/ipcz/build_overrides/ipcz.gni
@@ -1,4 +1,4 @@
-# Copyright 2022 The Chromium Authors. All rights reserved.
+# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/include/ipcz/ipcz.h b/chromium/third_party/ipcz/include/ipcz/ipcz.h
index c8c3b532ca6..cffbc11f784 100644
--- a/chromium/third_party/ipcz/include/ipcz/ipcz.h
+++ b/chromium/third_party/ipcz/include/ipcz/ipcz.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -437,6 +437,18 @@ struct IPCZ_ALIGN(8) IpczDriver {
uint32_t flags, // in
const void* options); // in
+ // The ipcz Reject() API can be used by an application to reject a specific
+ // parcel received from a portal. If the parcel in question came from a
+ // remote node, ipcz invokes ReportBadTransportActivity() to notify the driver
+ // about the `transport` which delivered the rejected parcel.
+ //
+ // `context` is an opaque value passed by the application to the Reject() call
+ // which elicited this invocation.
+ IpczResult(IPCZ_API* ReportBadTransportActivity)(IpczDriverHandle transport,
+ uintptr_t context,
+ uint32_t flags,
+ const void* options);
+
// Allocates a shared memory region and returns a driver handle in
// `driver_memory` which can be used to reference it in other calls to the
// driver.
@@ -729,6 +741,18 @@ typedef uint32_t IpczTrapConditionFlags;
// by any amount. Edge-triggered.
#define IPCZ_TRAP_CONSUMED_REMOTE_PARCEL IPCZ_FLAG_BIT(8)
+// Indicates that the trap event is being fired from within the extent of an
+// ipcz API call (i.e., as opposed to being fired from within the extent of an
+// incoming driver transport notification.) For example if a trap is monitoring
+// a portal for incoming parcels, and the application puts a parcel into the
+// portal's peer on the same node, the trap event will be fired within the
+// extent of the corresponding Put() call, and this flag will be set on the
+// event.
+//
+// This flag is ignored when specifying conditions to watch for Trap(), and it
+// may be set on any event dispatched to an IpczTrapEventHandler.
+#define IPCZ_TRAP_WITHIN_API_CALL IPCZ_FLAG_BIT(9)
+
// A structure describing portal conditions necessary to trigger a trap and
// invoke its event handler.
struct IPCZ_ALIGN(8) IpczTrapConditions {
@@ -1225,6 +1249,11 @@ struct IPCZ_ALIGN(8) IpczAPI {
// (`num_bytes` and `num_handles`) are still updated as specified in the
// IPCZ_RESULT_OK details below.
//
+ // If this call succeeds and `validator` is non-null, it's populated with a
+ // new validator handle which the application can use to report
+ // application-level validation failures regarding this specific transaction.
+ // See Reject().
+ //
// `options` is ignored and must be null.
//
// Returns:
@@ -1258,13 +1287,14 @@ struct IPCZ_ALIGN(8) IpczAPI {
//
// IPCZ_RESULT_ALREADY_EXISTS if there is a two-phase get operation in
// progress on `portal`.
- IpczResult(IPCZ_API* Get)(IpczHandle portal, // in
- IpczGetFlags flags, // in
- const void* options, // in
- void* data, // out
- size_t* num_bytes, // in/out
- IpczHandle* handles, // out
- size_t* num_handles); // in/out
+ IpczResult(IPCZ_API* Get)(IpczHandle portal, // in
+ IpczGetFlags flags, // in
+ const void* options, // in
+ void* data, // out
+ size_t* num_bytes, // in/out
+ IpczHandle* handles, // out
+ size_t* num_handles, // in/out
+ IpczHandle* validator); // out
// Begins a two-phase get operation on `portal` to retrieve data and handles.
// While a two-phase get operation is in progress on a portal, all other get
@@ -1337,6 +1367,11 @@ struct IPCZ_ALIGN(8) IpczAPI {
// operation in progress on `portal`, all other arguments are ignored and the
// pending operation is cancelled without consuming any data from the portal.
//
+ // If this call succeeds (without IPCZ_END_GET_ABORT specified) and
+ // `validator` is non-null, it's populated with a new validator handle which
+ // the application can use to report application-level validation failures
+ // regarding this specific transaction. See Reject().
+ //
// `options` is unused and must be null.
//
// Returns:
@@ -1360,7 +1395,8 @@ struct IPCZ_ALIGN(8) IpczAPI {
size_t num_handles, // in
IpczEndGetFlags flags, // in
const void* options, // in
- IpczHandle* handles); // out
+ IpczHandle* handles, // out
+ IpczHandle* validator); // out
// Attempts to install a trap to catch interesting changes to a portal's
// state. The condition(s) to observe are specified in `conditions`.
@@ -1418,6 +1454,34 @@ struct IPCZ_ALIGN(8) IpczAPI {
IpczTrapConditionFlags* satisfied_condition_flags, // out
struct IpczPortalStatus* status); // out
+ // Reports an application-level validation failure to ipcz, in reference to
+ // a specific `validator` returned by a previous call to Get() or EndGet().
+ // ipcz propagates this rejection to the driver via
+ // ReportBadTransportActivity(), if and only if the associated parcel did in
+ // fact come from a remote node.
+ //
+ // `context` is an opaque handle which, on success, is passed to the driver
+ // when issuing a corresponding ReportBadTransportActivity() invocation.
+ //
+ // `flags` is ignored and must be 0.
+ //
+ // `options` is ignored and must be null.
+ //
+ // Returns:
+ //
+ // IPCZ_RESULT_OK if the driver was successfully notified about this
+ // rejection via ReportBadTransportActivity().
+ //
+ // IPCZ_RESULT_INVALID_ARGUMENT if `validator` is not a valid validator
+ // handle previously returned by Get() or EndGet().
+ //
+ // IPCZ_RESULT_FAILED_PRECONDITION if `validator` is associated with a
+ // parcel that did not come from another node.
+ IpczResult(IPCZ_API* Reject)(IpczHandle validator,
+ uintptr_t context,
+ uint32_t flags,
+ const void* options);
+
// Boxes an object managed by a node's driver and returns a new IpczHandle to
// reference the box. If the driver is able to serialize the boxed object, the
// box can be placed into a portal for transmission to the other side.
diff --git a/chromium/third_party/ipcz/src/BUILD.gn b/chromium/third_party/ipcz/src/BUILD.gn
index 4fa9f4fd751..8b98d75aaa8 100644
--- a/chromium/third_party/ipcz/src/BUILD.gn
+++ b/chromium/third_party/ipcz/src/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2022 The Chromium Authors. All rights reserved.
+# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -138,19 +138,17 @@ ipcz_source_set("reference_drivers") {
public = [
"reference_drivers/async_reference_driver.h",
- "reference_drivers/blob.h",
+ "reference_drivers/single_process_reference_driver_base.h",
"reference_drivers/sync_reference_driver.h",
]
sources = [
"reference_drivers/async_reference_driver.cc",
- "reference_drivers/blob.cc",
"reference_drivers/object.cc",
"reference_drivers/object.h",
"reference_drivers/random.cc",
"reference_drivers/random.h",
"reference_drivers/single_process_reference_driver_base.cc",
- "reference_drivers/single_process_reference_driver_base.h",
"reference_drivers/sync_reference_driver.cc",
]
@@ -230,6 +228,8 @@ ipcz_source_set("impl") {
"ipcz/node_link_memory.h",
"ipcz/node_messages.h",
"ipcz/node_name.h",
+ "ipcz/node_type.h",
+ "ipcz/operation_context.h",
"ipcz/parcel.h",
"ipcz/parcel_queue.h",
"ipcz/portal.h",
@@ -243,9 +243,12 @@ ipcz_source_set("impl") {
"ipcz/sequenced_queue.h",
"ipcz/sublink_id.h",
"ipcz/test_messages.h",
+ "ipcz/validator.h",
]
sources = [
"ipcz/api_object.cc",
+ "ipcz/atomic_queue_state.cc",
+ "ipcz/atomic_queue_state.h",
"ipcz/block_allocator.cc",
"ipcz/block_allocator_pool.cc",
"ipcz/block_allocator_pool.h",
@@ -272,6 +275,7 @@ ipcz_source_set("impl") {
"ipcz/message_macros/message_params_declaration_macros.h",
"ipcz/message_macros/message_params_declaration_macros.h",
"ipcz/message_macros/undef_message_macros.h",
+ "ipcz/monitored_atomic.h",
"ipcz/node.cc",
"ipcz/node_connector.cc",
"ipcz/node_link.cc",
@@ -295,6 +299,7 @@ ipcz_source_set("impl") {
"ipcz/trap_event_dispatcher.h",
"ipcz/trap_set.cc",
"ipcz/trap_set.h",
+ "ipcz/validator.cc",
]
public_deps = [
":ipcz_header",
@@ -387,6 +392,7 @@ ipcz_source_set("ipcz_tests_sources") {
"remote_portal_test.cc",
"trap_test.cc",
"util/ref_counted_test.cc",
+ "util/safe_math_test.cc",
"util/stack_trace_test.cc",
]
diff --git a/chromium/third_party/ipcz/src/api.cc b/chromium/third_party/ipcz/src/api.cc
index c398f25da7c..74cf5b1134c 100644
--- a/chromium/third_party/ipcz/src/api.cc
+++ b/chromium/third_party/ipcz/src/api.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,6 +13,7 @@
#include "ipcz/node_link_memory.h"
#include "ipcz/portal.h"
#include "ipcz/router.h"
+#include "ipcz/validator.h"
#include "util/ref_counted.h"
extern "C" {
@@ -215,12 +216,13 @@ IpczResult Get(IpczHandle portal_handle,
void* data,
size_t* num_bytes,
IpczHandle* handles,
- size_t* num_handles) {
+ size_t* num_handles,
+ IpczHandle* validator) {
ipcz::Portal* portal = ipcz::Portal::FromHandle(portal_handle);
if (!portal) {
return IPCZ_RESULT_INVALID_ARGUMENT;
}
- return portal->Get(flags, data, num_bytes, handles, num_handles);
+ return portal->Get(flags, data, num_bytes, handles, num_handles, validator);
}
IpczResult BeginGet(IpczHandle portal_handle,
@@ -242,7 +244,8 @@ IpczResult EndGet(IpczHandle portal_handle,
size_t num_handles,
IpczEndGetFlags flags,
const void* options,
- IpczHandle* handles) {
+ IpczHandle* handles,
+ IpczHandle* validator) {
ipcz::Portal* portal = ipcz::Portal::FromHandle(portal_handle);
if (!portal) {
return IPCZ_RESULT_INVALID_ARGUMENT;
@@ -256,7 +259,7 @@ IpczResult EndGet(IpczHandle portal_handle,
}
return portal->CommitGet(num_bytes_consumed,
- absl::MakeSpan(handles, num_handles));
+ absl::MakeSpan(handles, num_handles), validator);
}
IpczResult Trap(IpczHandle portal_handle,
@@ -281,6 +284,18 @@ IpczResult Trap(IpczHandle portal_handle,
satisfied_condition_flags, status);
}
+IpczResult Reject(IpczHandle validator_handle,
+ uintptr_t context,
+ uint32_t flags,
+ const void* options) {
+ ipcz::Validator* validator = ipcz::Validator::FromHandle(validator_handle);
+ if (!validator) {
+ return IPCZ_RESULT_INVALID_ARGUMENT;
+ }
+
+ return validator->Reject(context);
+}
+
IpczResult Box(IpczHandle node_handle,
IpczDriverHandle driver_handle,
uint32_t flags,
@@ -334,6 +349,7 @@ constexpr IpczAPI kCurrentAPI = {
BeginGet,
EndGet,
Trap,
+ Reject,
Box,
Unbox,
};
diff --git a/chromium/third_party/ipcz/src/api.h b/chromium/third_party/ipcz/src/api.h
index 6a6bee21dae..3a02c431630 100644
--- a/chromium/third_party/ipcz/src/api.h
+++ b/chromium/third_party/ipcz/src/api.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/api_test.cc b/chromium/third_party/ipcz/src/api_test.cc
index 4bf73ab35f2..88275cfe773 100644
--- a/chromium/third_party/ipcz/src/api_test.cc
+++ b/chromium/third_party/ipcz/src/api_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#include <string>
#include "ipcz/ipcz.h"
+#include "reference_drivers/single_process_reference_driver_base.h"
#include "reference_drivers/sync_reference_driver.h"
#include "test/test.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -233,8 +234,9 @@ TEST_F(APITest, PutGet) {
// Get from an empty portal.
char data[4];
size_t num_bytes = 4;
- EXPECT_EQ(IPCZ_RESULT_UNAVAILABLE, ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, data,
- &num_bytes, nullptr, nullptr));
+ EXPECT_EQ(IPCZ_RESULT_UNAVAILABLE,
+ ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, data, &num_bytes, nullptr,
+ nullptr, nullptr));
// A portal can't transfer itself or its peer.
EXPECT_EQ(IPCZ_RESULT_INVALID_ARGUMENT,
@@ -264,18 +266,18 @@ TEST_F(APITest, PutGet) {
num_bytes = 0;
EXPECT_EQ(IPCZ_RESULT_RESOURCE_EXHAUSTED,
ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, data, &num_bytes, nullptr,
- nullptr));
+ nullptr, nullptr));
EXPECT_EQ(2u, num_bytes);
num_bytes = 4;
EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, data,
- &num_bytes, nullptr, nullptr));
+ &num_bytes, nullptr, nullptr, nullptr));
EXPECT_EQ(2u, num_bytes);
EXPECT_EQ("hi", std::string(data, 2));
num_bytes = 4;
EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, data,
- &num_bytes, nullptr, nullptr));
+ &num_bytes, nullptr, nullptr, nullptr));
EXPECT_EQ(3u, num_bytes);
EXPECT_EQ("bye", std::string(data, 3));
@@ -286,7 +288,7 @@ TEST_F(APITest, PutGet) {
// Getting an empty parcel requires no storage.
EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, nullptr,
- nullptr, nullptr, nullptr));
+ nullptr, nullptr, nullptr, nullptr));
EXPECT_EQ(IPCZ_RESULT_OK,
ipcz().QueryPortalStatus(b, IPCZ_NO_FLAGS, nullptr, &status));
EXPECT_EQ(1u, status.num_local_parcels);
@@ -295,11 +297,11 @@ TEST_F(APITest, PutGet) {
// Insufficient handle storage.
EXPECT_EQ(IPCZ_RESULT_RESOURCE_EXHAUSTED,
ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, nullptr, nullptr, nullptr,
- nullptr));
+ nullptr, nullptr));
size_t num_handles = 1;
EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, nullptr,
- nullptr, &d, &num_handles));
+ nullptr, &d, &num_handles, nullptr));
EXPECT_EQ(1u, num_handles);
Close(d);
@@ -403,22 +405,23 @@ TEST_F(APITest, BeginEndGetFailure) {
// Invalid handle.
EXPECT_EQ(IPCZ_RESULT_INVALID_ARGUMENT,
ipcz().EndGet(IPCZ_INVALID_HANDLE, 0, 0, IPCZ_NO_FLAGS, nullptr,
- nullptr));
+ nullptr, nullptr));
// Non-zero handle count with null handle buffer.
EXPECT_EQ(IPCZ_RESULT_INVALID_ARGUMENT,
- ipcz().EndGet(a, 0, 1, IPCZ_NO_FLAGS, nullptr, nullptr));
+ ipcz().EndGet(a, 0, 1, IPCZ_NO_FLAGS, nullptr, nullptr, nullptr));
// Data size out of range.
- EXPECT_EQ(
- IPCZ_RESULT_OUT_OF_RANGE,
- ipcz().EndGet(a, num_bytes + 1, 0, IPCZ_NO_FLAGS, nullptr, nullptr));
+ EXPECT_EQ(IPCZ_RESULT_OUT_OF_RANGE,
+ ipcz().EndGet(a, num_bytes + 1, 0, IPCZ_NO_FLAGS, nullptr, nullptr,
+ nullptr));
// Two-phase Get not in progress.
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().EndGet(a, num_bytes, 0, IPCZ_NO_FLAGS, nullptr, nullptr));
- EXPECT_EQ(IPCZ_RESULT_FAILED_PRECONDITION,
- ipcz().EndGet(a, num_bytes, 0, IPCZ_NO_FLAGS, nullptr, nullptr));
+ EXPECT_EQ(IPCZ_RESULT_OK, ipcz().EndGet(a, num_bytes, 0, IPCZ_NO_FLAGS,
+ nullptr, nullptr, nullptr));
+ EXPECT_EQ(
+ IPCZ_RESULT_FAILED_PRECONDITION,
+ ipcz().EndGet(a, num_bytes, 0, IPCZ_NO_FLAGS, nullptr, nullptr, nullptr));
CloseAll({a, b, node});
}
@@ -443,15 +446,15 @@ TEST_F(APITest, TwoPhasePutGet) {
EXPECT_EQ(kMessage[0], *reinterpret_cast<const char*>(in_data));
EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().EndGet(b, 1, 0, IPCZ_NO_FLAGS, nullptr, nullptr));
+ ipcz().EndGet(b, 1, 0, IPCZ_NO_FLAGS, nullptr, nullptr, nullptr));
EXPECT_EQ(IPCZ_RESULT_OK, ipcz().BeginGet(b, IPCZ_NO_FLAGS, nullptr, &in_data,
&num_bytes, nullptr));
EXPECT_EQ(
kMessage.substr(1),
std::string_view(reinterpret_cast<const char*>(in_data), num_bytes));
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().EndGet(b, num_bytes, 0, IPCZ_NO_FLAGS, nullptr, nullptr));
+ EXPECT_EQ(IPCZ_RESULT_OK, ipcz().EndGet(b, num_bytes, 0, IPCZ_NO_FLAGS,
+ nullptr, nullptr, nullptr));
EXPECT_EQ(
IPCZ_RESULT_UNAVAILABLE,
@@ -500,6 +503,80 @@ TEST_F(APITest, TrapInvalid) {
CloseAll({a, b, node});
}
+TEST_F(APITest, RejectInvalid) {
+ EXPECT_EQ(IPCZ_RESULT_INVALID_ARGUMENT,
+ ipcz().Reject(IPCZ_INVALID_HANDLE, 0, IPCZ_NO_FLAGS, nullptr));
+
+ const IpczHandle node = CreateNode(kDefaultDriver);
+ auto [a, b] = OpenPortals(node);
+ EXPECT_EQ(IPCZ_RESULT_INVALID_ARGUMENT,
+ ipcz().Reject(a, 0, IPCZ_NO_FLAGS, nullptr));
+ CloseAll({a, b, node});
+}
+
+TEST_F(APITest, RejectLocal) {
+ const IpczHandle node = CreateNode(kDefaultDriver);
+ auto [a, b] = OpenPortals(node);
+ Put(a, "!");
+
+ char byte;
+ size_t num_bytes = 1;
+ IpczHandle validator;
+ EXPECT_EQ(IPCZ_RESULT_OK,
+ ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, &byte, &num_bytes, nullptr,
+ nullptr, &validator));
+ EXPECT_EQ('!', byte);
+
+ EXPECT_EQ(IPCZ_RESULT_FAILED_PRECONDITION,
+ ipcz().Reject(validator, 0, IPCZ_NO_FLAGS, nullptr));
+
+ CloseAll({a, b, node, validator});
+}
+
+TEST_F(APITest, RejectRemote) {
+ const IpczHandle node_a =
+ CreateNode(kDefaultDriver, IPCZ_CREATE_NODE_AS_BROKER);
+ const IpczHandle node_b = CreateNode(kDefaultDriver);
+ IpczDriverHandle transport0, transport1;
+ ASSERT_EQ(IPCZ_RESULT_OK,
+ kDefaultDriver.CreateTransports(
+ IPCZ_INVALID_DRIVER_HANDLE, IPCZ_INVALID_DRIVER_HANDLE,
+ IPCZ_NO_FLAGS, nullptr, &transport0, &transport1));
+
+ IpczHandle a;
+ ASSERT_EQ(IPCZ_RESULT_OK, ipcz().ConnectNode(node_a, transport0, 1,
+ IPCZ_NO_FLAGS, nullptr, &a));
+ IpczHandle b;
+ ASSERT_EQ(IPCZ_RESULT_OK,
+ ipcz().ConnectNode(node_b, transport1, 1,
+ IPCZ_CONNECT_NODE_TO_BROKER, nullptr, &b));
+
+ Put(a, "!");
+ char byte;
+ size_t num_bytes = 1;
+ IpczHandle validator;
+ EXPECT_EQ(IPCZ_RESULT_OK,
+ ipcz().Get(b, IPCZ_NO_FLAGS, nullptr, &byte, &num_bytes, nullptr,
+ nullptr, &validator));
+ EXPECT_EQ('!', byte);
+
+ constexpr uintptr_t kTestContext = 42;
+ IpczDriverHandle error_transport = IPCZ_INVALID_DRIVER_HANDLE;
+ uintptr_t error_context = 0;
+ reference_drivers::SetBadTransportActivityCallback(
+ [&](IpczDriverHandle transport, uintptr_t context) {
+ error_transport = transport;
+ error_context = context;
+ });
+ EXPECT_EQ(IPCZ_RESULT_OK,
+ ipcz().Reject(validator, kTestContext, IPCZ_NO_FLAGS, nullptr));
+ EXPECT_EQ(transport1, error_transport);
+ EXPECT_EQ(kTestContext, error_context);
+ reference_drivers::SetBadTransportActivityCallback(nullptr);
+
+ CloseAll({a, b, node_b, node_a, validator});
+}
+
TEST_F(APITest, BoxInvalid) {
IpczDriverHandle transport0, transport1;
ASSERT_EQ(IPCZ_RESULT_OK,
diff --git a/chromium/third_party/ipcz/src/box_test.cc b/chromium/third_party/ipcz/src/box_test.cc
index f13203abaad..726081ecd74 100644
--- a/chromium/third_party/ipcz/src/box_test.cc
+++ b/chromium/third_party/ipcz/src/box_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,6 @@
#include <string_view>
#include "ipcz/ipcz.h"
-#include "reference_drivers/blob.h"
#include "test/multinode_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "util/ref_counted.h"
@@ -14,75 +13,50 @@
namespace ipcz {
namespace {
-using Blob = reference_drivers::Blob;
-
using BoxTestNode = test::TestNode;
using BoxTest = test::MultinodeTest<BoxTestNode>;
-IpczDriverHandle CreateTestBlob(std::string_view message) {
- return Blob::ReleaseAsHandle(MakeRefCounted<Blob>(message));
-}
-
-std::string GetBlobContents(IpczDriverHandle handle) {
- Ref<Blob> blob = Blob::TakeFromHandle(handle);
- return std::string(blob->message());
-}
-
-TEST_P(BoxTest, BoxAndUnbox) {
+MULTINODE_TEST(BoxTest, BoxAndUnbox) {
constexpr const char kMessage[] = "Hello, world?";
- IpczDriverHandle blob_handle = CreateTestBlob(kMessage);
-
- IpczHandle box;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box));
-
- blob_handle = IPCZ_INVALID_DRIVER_HANDLE;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle));
- EXPECT_EQ(kMessage, GetBlobContents(blob_handle));
+ EXPECT_EQ(kMessage, UnboxBlob(BoxBlob(kMessage)));
}
-TEST_P(BoxTest, CloseBox) {
- Ref<Blob> blob = MakeRefCounted<Blob>("meh");
- Ref<Blob::RefCountedFlag> destroyed = blob->destruction_flag_for_testing();
- IpczDriverHandle blob_handle = Blob::ReleaseAsHandle(std::move(blob));
-
- IpczHandle box;
+MULTINODE_TEST(BoxTest, CloseBox) {
+ // Verifies that box closure releases its underlying driver object. This test
+ // does not explicitly observe side effects of that release, but LSan will
+ // fail if something's off.
EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box));
-
- EXPECT_FALSE(destroyed->get());
- EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Close(box, IPCZ_NO_FLAGS, nullptr));
- EXPECT_TRUE(destroyed->get());
+ ipcz().Close(BoxBlob("meh"), IPCZ_NO_FLAGS, nullptr));
}
-TEST_P(BoxTest, Peek) {
- constexpr const char kMessage[] = "Hello, world?";
- IpczDriverHandle blob_handle = CreateTestBlob(kMessage);
- IpczHandle box;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box));
+MULTINODE_TEST(BoxTest, Peek) {
+ constexpr std::string_view kMessage = "Hello, world?";
+ IpczHandle box = BoxBlob(kMessage);
- blob_handle = IPCZ_INVALID_DRIVER_HANDLE;
+ IpczDriverHandle memory = IPCZ_INVALID_DRIVER_HANDLE;
EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &blob_handle));
+ ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &memory));
EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &blob_handle));
+ ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &memory));
EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &blob_handle));
-
- Blob* blob = Blob::FromHandle(blob_handle);
- EXPECT_EQ(kMessage, blob->message());
+ ipcz().Unbox(box, IPCZ_UNBOX_PEEK, nullptr, &memory));
+ EXPECT_NE(IPCZ_INVALID_DRIVER_HANDLE, memory);
+ IpczDriverHandle mapping;
+ void* base;
EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle));
+ GetDriver().MapSharedMemory(memory, IPCZ_NO_FLAGS, nullptr, &base,
+ &mapping));
+ std::string contents(static_cast<const char*>(base), kMessage.size());
+ EXPECT_EQ(kMessage, contents);
+ EXPECT_EQ(IPCZ_RESULT_OK, GetDriver().Close(mapping, IPCZ_NO_FLAGS, nullptr));
- Ref<Blob> released_blob = Blob::TakeFromHandle(blob_handle);
- EXPECT_EQ(blob, released_blob.get());
+ EXPECT_EQ(kMessage, UnboxBlob(box));
}
constexpr const char kMessage1[] = "Hello, world?";
constexpr const char kMessage2[] = "Hello, world!";
+constexpr const char kMessage3[] = "Hello. World.";
MULTINODE_TEST_NODE(BoxTestNode, TransferBoxClient) {
IpczHandle b = ConnectToBroker();
@@ -91,26 +65,41 @@ MULTINODE_TEST_NODE(BoxTestNode, TransferBoxClient) {
IpczHandle box;
EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, &message, {&box, 1}));
EXPECT_EQ(kMessage2, message);
-
- IpczDriverHandle blob_handle;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle));
- EXPECT_EQ(kMessage1, GetBlobContents(blob_handle));
-
+ EXPECT_EQ(kMessage1, UnboxBlob(box));
Close(b);
}
-TEST_P(BoxTest, TransferBox) {
+MULTINODE_TEST(BoxTest, TransferBox) {
IpczHandle c = SpawnTestNode<TransferBoxClient>();
+ IpczHandle box = BoxBlob(kMessage1);
+ EXPECT_EQ(IPCZ_RESULT_OK, Put(c, kMessage2, {&box, 1}));
+ Close(c);
+}
- IpczDriverHandle blob_handle = CreateTestBlob(kMessage1);
- IpczHandle box;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box));
+MULTINODE_TEST_NODE(BoxTestNode, TransferBoxAndPortalClient) {
+ IpczHandle b = ConnectToBroker();
- EXPECT_EQ(IPCZ_RESULT_OK, Put(c, kMessage2, {&box, 1}));
+ IpczHandle handles[2];
+ std::string message;
+ EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, &message, handles));
+ EXPECT_EQ(kMessage2, message);
+ EXPECT_EQ(IPCZ_RESULT_OK, Put(handles[1], kMessage3));
+ EXPECT_EQ(kMessage1, UnboxBlob(handles[0]));
+ CloseAll({b, handles[1]});
+}
- Close(c);
+MULTINODE_TEST(BoxTest, TransferBoxAndPortal) {
+ IpczHandle c = SpawnTestNode<TransferBoxAndPortalClient>();
+
+ auto [q, p] = OpenPortals();
+ IpczHandle box = BoxBlob(kMessage1);
+ IpczHandle handles[] = {box, p};
+ EXPECT_EQ(IPCZ_RESULT_OK, Put(c, kMessage2, absl::MakeSpan(handles)));
+
+ std::string message;
+ EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(q, &message));
+ EXPECT_EQ(kMessage3, message);
+ CloseAll({c, q});
}
constexpr size_t TransferBoxBetweenNonBrokersNumIterations = 50;
@@ -121,19 +110,14 @@ MULTINODE_TEST_NODE(BoxTestNode, TransferBoxBetweenNonBrokersClient1) {
EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, nullptr, {&q, 1}));
for (size_t i = 0; i < TransferBoxBetweenNonBrokersNumIterations; ++i) {
- IpczDriverHandle blob_handle = CreateTestBlob(kMessage1);
- IpczHandle box;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box));
+ IpczHandle box = BoxBlob(kMessage1);
EXPECT_EQ(IPCZ_RESULT_OK, Put(q, kMessage2, {&box, 1}));
box = IPCZ_INVALID_DRIVER_HANDLE;
std::string message;
EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(q, &message, {&box, 1}));
EXPECT_EQ(kMessage1, message);
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle));
- EXPECT_EQ(kMessage2, GetBlobContents(blob_handle));
+ EXPECT_EQ(kMessage2, UnboxBlob(box));
}
WaitForDirectRemoteLink(q);
@@ -147,17 +131,12 @@ MULTINODE_TEST_NODE(BoxTestNode, TransferBoxBetweenNonBrokersClient2) {
for (size_t i = 0; i < TransferBoxBetweenNonBrokersNumIterations; ++i) {
IpczHandle box;
- IpczDriverHandle blob_handle;
std::string message;
EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(p, &message, {&box, 1}));
EXPECT_EQ(kMessage2, message);
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob_handle));
- EXPECT_EQ(kMessage1, GetBlobContents(blob_handle));
+ EXPECT_EQ(kMessage1, UnboxBlob(box));
- blob_handle = CreateTestBlob(kMessage2);
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob_handle, IPCZ_NO_FLAGS, nullptr, &box));
+ box = BoxBlob(kMessage2);
EXPECT_EQ(IPCZ_RESULT_OK, Put(p, kMessage1, {&box, 1}));
}
@@ -165,7 +144,7 @@ MULTINODE_TEST_NODE(BoxTestNode, TransferBoxBetweenNonBrokersClient2) {
CloseAll({p, b});
}
-TEST_P(BoxTest, TransferBoxBetweenNonBrokers) {
+MULTINODE_TEST(BoxTest, TransferBoxBetweenNonBrokers) {
IpczHandle c1 = SpawnTestNode<TransferBoxBetweenNonBrokersClient1>();
IpczHandle c2 = SpawnTestNode<TransferBoxBetweenNonBrokersClient2>();
@@ -181,7 +160,5 @@ TEST_P(BoxTest, TransferBoxBetweenNonBrokers) {
CloseAll({c1, c2});
}
-INSTANTIATE_MULTINODE_TEST_SUITE_P(BoxTest);
-
} // namespace
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/connect_test.cc b/chromium/third_party/ipcz/src/connect_test.cc
index 10d4df50722..1e6cc9aefbc 100644
--- a/chromium/third_party/ipcz/src/connect_test.cc
+++ b/chromium/third_party/ipcz/src/connect_test.cc
@@ -1,12 +1,14 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
+#include "build/build_config.h"
#include "ipcz/ipcz.h"
#include "ipcz/node_messages.h"
-#include "reference_drivers/blob.h"
+#include "reference_drivers/async_reference_driver.h"
+#include "reference_drivers/sync_reference_driver.h"
#include "test/multinode_test.h"
#include "test/test_transport_listener.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -16,7 +18,16 @@
namespace ipcz {
namespace {
-using ConnectTestNode = test::TestNode;
+class ConnectTestNode : public test::TestNode {
+ public:
+ void ActivateAndClose(IpczDriverHandle transport) {
+ // Registering any listener callback activates the transport, and
+ // listener destruction closes it.
+ test::TestTransportListener listener(node(), transport);
+ listener.OnError([] {});
+ }
+};
+
using ConnectTest = test::MultinodeTest<ConnectTestNode>;
MULTINODE_TEST_NODE(ConnectTestNode, BrokerToNonBrokerClient) {
@@ -25,7 +36,7 @@ MULTINODE_TEST_NODE(ConnectTestNode, BrokerToNonBrokerClient) {
Close(b);
}
-TEST_P(ConnectTest, BrokerToNonBroker) {
+MULTINODE_TEST(ConnectTest, BrokerToNonBroker) {
IpczHandle c = SpawnTestNode<BrokerToNonBrokerClient>();
Close(c);
}
@@ -47,7 +58,7 @@ MULTINODE_TEST_NODE(ConnectTestNode, SurplusPortalsClient) {
CloseAll(portals);
}
-TEST_P(ConnectTest, SurplusPortals) {
+MULTINODE_TEST(ConnectTest, SurplusPortals) {
IpczHandle portals[kNumBrokerPortals];
SpawnTestNode<SurplusPortalsClient>(portals);
CloseAll(portals);
@@ -59,12 +70,11 @@ MULTINODE_TEST_NODE(ConnectTestNode, ExpectDisconnectFromBroker) {
Close(b);
}
-TEST_P(ConnectTest, DisconnectWithoutBrokerHandshake) {
- TransportPair transports = CreateTransports();
+MULTINODE_TEST(ConnectTest, DisconnectWithoutBrokerHandshake) {
+ IpczDriverHandle our_transport;
auto controller =
- SpawnTestNodeWithTransport<ExpectDisconnectFromBroker>(transports.theirs);
- EXPECT_EQ(IPCZ_RESULT_OK,
- GetDriver().Close(transports.ours, IPCZ_NO_FLAGS, nullptr));
+ SpawnTestNodeNoConnect<ExpectDisconnectFromBroker>(our_transport);
+ ActivateAndClose(our_transport);
controller->WaitForShutdown();
}
@@ -74,25 +84,24 @@ MULTINODE_TEST_NODE(ConnectTestNode,
// we never call ConnectToBroker(). No action required.
}
-TEST_P(ConnectTest, DisconnectWithoutNonBrokerHandshake) {
+MULTINODE_TEST(ConnectTest, DisconnectWithoutNonBrokerHandshake) {
IpczHandle c = SpawnTestNode<DisconnectWithoutNonBrokerHandshakeClient>();
EXPECT_EQ(IPCZ_RESULT_OK, WaitForConditionFlags(c, IPCZ_TRAP_PEER_CLOSED));
Close(c);
}
-TEST_P(ConnectTest, DisconnectOnBadBrokerMessage) {
- TransportPair transports = CreateTransports();
+MULTINODE_TEST(ConnectTest, DisconnectOnBadBrokerMessage) {
+ IpczDriverHandle our_transport;
auto controller =
- SpawnTestNodeWithTransport<ExpectDisconnectFromBroker>(transports.theirs);
+ SpawnTestNodeNoConnect<ExpectDisconnectFromBroker>(our_transport);
// Send some garbage to the other node.
const char kBadMessage[] = "this will never be a valid handshake message!";
EXPECT_EQ(
IPCZ_RESULT_OK,
- GetDriver().Transmit(transports.ours, kBadMessage, std::size(kBadMessage),
+ GetDriver().Transmit(our_transport, kBadMessage, std::size(kBadMessage),
nullptr, 0, IPCZ_NO_FLAGS, nullptr));
- EXPECT_EQ(IPCZ_RESULT_OK,
- GetDriver().Close(transports.ours, IPCZ_NO_FLAGS, nullptr));
+ ActivateAndClose(our_transport);
// The other node will only shut down once it's observed peer closure on its
// portal to us; which it should, because we just sent it some garbage.
@@ -115,7 +124,7 @@ MULTINODE_TEST_NODE(ConnectTestNode, TransmitSomeGarbage) {
listener.StopListening();
}
-TEST_P(ConnectTest, DisconnectOnBadNonBrokerMessage) {
+MULTINODE_TEST(ConnectTest, DisconnectOnBadNonBrokerMessage) {
IpczHandle c;
auto controller = SpawnTestNode<TransmitSomeGarbage>({&c, 1});
@@ -160,7 +169,17 @@ MULTINODE_TEST_NODE(ConnectTestNode, NonBrokerToNonBrokerClient) {
CloseAll({c, b});
}
-TEST_P(ConnectTest, NonBrokerToNonBroker) {
+MULTINODE_TEST(ConnectTest, NonBrokerToNonBroker) {
+#if BUILDFLAG(IS_ANDROID)
+ // Client nodes launching other client nodes doesn't work for Chromium's
+ // custom test driver on Android. Limit this test to the reference test
+ // drivers there.
+ if (&GetDriver() != &reference_drivers::kSyncReferenceDriver &&
+ &GetDriver() != &reference_drivers::kAsyncReferenceDriver) {
+ return;
+ }
+#endif
+
IpczHandle c1 = SpawnTestNode<NonBrokerToNonBrokerClient>();
IpczHandle c2 = SpawnTestNode<NonBrokerToNonBrokerClient>();
@@ -212,7 +231,7 @@ MULTINODE_TEST_NODE(ConnectTestNode, BadNonBrokerReferralClient) {
GetDriver().Close(transports.theirs, IPCZ_NO_FLAGS, nullptr));
}
-TEST_P(ConnectTest, BadNonBrokerReferral) {
+MULTINODE_TEST(ConnectTest, BadNonBrokerReferral) {
IpczHandle c = SpawnTestNode<BadNonBrokerReferralClient>();
EXPECT_EQ(IPCZ_RESULT_OK, WaitForConditionFlags(c, IPCZ_TRAP_PEER_CLOSED));
Close(c);
@@ -230,27 +249,109 @@ MULTINODE_TEST_NODE(ConnectTestNode, FailedNonBrokerReferralReferredClient) {
MULTINODE_TEST_NODE(ConnectTestNode, FailedNonBrokerReferralClient) {
IpczHandle b = ConnectToBroker();
- TransportPair transports = CreateTransports();
+ IpczDriverHandle our_transport;
auto controller =
- SpawnTestNodeWithTransport<FailedNonBrokerReferralReferredClient>(
- transports.theirs);
+ SpawnTestNodeNoConnect<FailedNonBrokerReferralReferredClient>(
+ our_transport);
- // Disconnect the transport instead of passing to our broker with
- // ConnectNode(). The referred client should observe disconnection of its
- // initial portals and terminate itself.
- EXPECT_EQ(IPCZ_RESULT_OK,
- GetDriver().Close(transports.ours, IPCZ_NO_FLAGS, nullptr));
+ // Activate and immediately disconnect the transport instead of passing to our
+ // broker with ConnectNode(). The referred client should observe disconnection
+ // of its initial portals and terminate itself.
+ ActivateAndClose(our_transport);
controller->WaitForShutdown();
Close(b);
}
-TEST_P(ConnectTest, FailedNonBrokerReferral) {
+MULTINODE_TEST(ConnectTest, FailedNonBrokerReferral) {
IpczHandle c = SpawnTestNode<FailedNonBrokerReferralClient>();
EXPECT_EQ(IPCZ_RESULT_OK, WaitForConditionFlags(c, IPCZ_TRAP_PEER_CLOSED));
Close(c);
}
-INSTANTIATE_MULTINODE_TEST_SUITE_P(ConnectTest);
+MULTINODE_TEST_BROKER_NODE(ConnectTestNode, AnotherBroker) {
+ IpczHandle b = ConnectToBroker();
+ PingPong(b);
+ Close(b);
+}
+
+MULTINODE_TEST(ConnectTest, BrokerToBroker) {
+ IpczHandle b = SpawnTestNode<AnotherBroker>();
+
+ PingPong(b);
+ EXPECT_EQ(IPCZ_RESULT_OK, WaitForConditionFlags(b, IPCZ_TRAP_PEER_CLOSED));
+ Close(b);
+}
+
+MULTINODE_TEST_NODE(ConnectTestNode, BrokerClient) {
+ IpczHandle b = ConnectToBroker();
+ IpczHandle other_client;
+ EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, nullptr, {&other_client, 1}));
+
+ // Ensure that we end up with a direct connection to the other client, which
+ // implies the two non-broker nodes have been properly introduced across the
+ // boundary of their respective node networks.
+ PingPong(other_client);
+ WaitForDirectRemoteLink(other_client);
+
+ // Synchronize against the main test node. See synchronization comment there.
+ PingPong(b);
+ CloseAll({b, other_client});
+}
+
+MULTINODE_TEST_BROKER_NODE(ConnectTestNode, BrokerWithClientNode) {
+ IpczHandle b = ConnectToBroker();
+ IpczHandle client = SpawnTestNode<BrokerClient>();
+
+ IpczHandle other_client;
+ EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, nullptr, {&other_client, 1}));
+ Put(client, "", {&other_client, 1});
+
+ // Synchronize against the launched client to ensure that it's done before we
+ // join it and terminate.
+ PingPong(client);
+ EXPECT_EQ(IPCZ_RESULT_OK,
+ WaitForConditionFlags(client, IPCZ_TRAP_PEER_CLOSED));
+
+ // Synchronize against the main test node. See synchronization comment there.
+ PingPong(b);
+ CloseAll({b, client});
+}
+
+// TODOD(crbug.com/1374114): Fix flakiness and re-enable
+MULTINODE_TEST(ConnectTest, DISABLED_MultiBrokerIntroductions) {
+ // This test covers introductions in a multi-broker network. There are four
+ // test nodes involved here: the main node (this one, call it A), a secondary
+ // broker B launched with the BrokerWithClientNode body defined above; and
+ // two client nodes (running BrokerClient above) we will call C and D, with
+ // C launched by A and D launched by B.
+ //
+ // A portal pair is created on A and its portals are passed to node B (our
+ // secondary broker) and node C (the singular non-broker client node in A's
+ // local network) respectively.
+ //
+ // Node B in turn passes its end to its own launched non-broker client D. This
+ // ultimately elicits a need for node C to be introduced to node D. The test
+ // succeeds only once the portal on node C appears to be directly connected to
+ // the portal on node D -- and vice versa -- implying successful introduction.
+
+ IpczHandle other_broker = SpawnTestNode<BrokerWithClientNode>();
+ IpczHandle client = SpawnTestNode<BrokerClient>();
+
+ auto [q, p] = OpenPortals();
+ Put(other_broker, "", {&q, 1});
+ Put(client, "", {&p, 1});
+
+ // Synchronize against both the launched broker and the launched client node
+ // to ensure that they're done before we join them and terminate.
+ PingPong(other_broker);
+ PingPong(client);
+ EXPECT_EQ(IPCZ_RESULT_OK,
+ WaitForConditionFlags(other_broker, IPCZ_TRAP_PEER_CLOSED));
+ EXPECT_EQ(IPCZ_RESULT_OK,
+ WaitForConditionFlags(client, IPCZ_TRAP_PEER_CLOSED));
+
+ CloseAll({other_broker, client});
+}
} // namespace
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/api_object.cc b/chromium/third_party/ipcz/src/ipcz/api_object.cc
index 08b0474939e..0a6784b9754 100644
--- a/chromium/third_party/ipcz/src/ipcz/api_object.cc
+++ b/chromium/third_party/ipcz/src/ipcz/api_object.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/api_object.h b/chromium/third_party/ipcz/src/ipcz/api_object.h
index aa5f19d9263..0477ccd04a3 100644
--- a/chromium/third_party/ipcz/src/ipcz/api_object.h
+++ b/chromium/third_party/ipcz/src/ipcz/api_object.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -24,6 +24,7 @@ class APIObject : public RefCounted {
kPortal,
kBox,
kTransport,
+ kValidator,
};
explicit APIObject(ObjectType type);
diff --git a/chromium/third_party/ipcz/src/ipcz/atomic_queue_state.cc b/chromium/third_party/ipcz/src/ipcz/atomic_queue_state.cc
new file mode 100644
index 00000000000..d2f2dc94fd1
--- /dev/null
+++ b/chromium/third_party/ipcz/src/ipcz/atomic_queue_state.cc
@@ -0,0 +1,38 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipcz/atomic_queue_state.h"
+
+#include <cstdint>
+
+#include "ipcz/monitored_atomic.h"
+#include "third_party/abseil-cpp/absl/base/macros.h"
+
+namespace ipcz {
+
+AtomicQueueState::AtomicQueueState() noexcept = default;
+
+AtomicQueueState::QueryResult AtomicQueueState::Query(
+ const MonitorSelection& monitors) {
+ return {
+ .num_parcels_consumed =
+ num_parcels_consumed_.Query({.monitor = monitors.monitor_parcels}),
+ .num_bytes_consumed =
+ num_bytes_consumed_.Query({.monitor = monitors.monitor_bytes}),
+ };
+}
+
+bool AtomicQueueState::Update(const UpdateValue& value) {
+ ABSL_ASSERT(value.num_parcels_consumed <=
+ MonitoredAtomic<uint64_t>::kMaxValue);
+ ABSL_ASSERT(value.num_bytes_consumed <= MonitoredAtomic<uint64_t>::kMaxValue);
+ const bool parcels_were_monitored =
+ num_parcels_consumed_.UpdateValueAndResetMonitor(
+ value.num_parcels_consumed);
+ const bool bytes_were_monitored =
+ num_bytes_consumed_.UpdateValueAndResetMonitor(value.num_bytes_consumed);
+ return parcels_were_monitored || bytes_were_monitored;
+}
+
+} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/atomic_queue_state.h b/chromium/third_party/ipcz/src/ipcz/atomic_queue_state.h
new file mode 100644
index 00000000000..bb7401feb8e
--- /dev/null
+++ b/chromium/third_party/ipcz/src/ipcz/atomic_queue_state.h
@@ -0,0 +1,75 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPCZ_SRC_IPCZ_ATOMIC_QUEUE_STATE_
+#define IPCZ_SRC_IPCZ_ATOMIC_QUEUE_STATE_
+
+#include <cstdint>
+#include <type_traits>
+
+#include "ipcz/monitored_atomic.h"
+
+namespace ipcz {
+
+// AtomicQueueState holds some trivial data about how much of a router's inbound
+// parcel sequence has been consumed so far.
+//
+// Note that the fields herein are not strictly synchronized. If a queue
+// accumulates a 4k parcel and an 8k parcel which are both then consumed by the
+// application, the remote sender may observe `num_parcels_consumed` at 0, then
+// 1, then 2; and they may observe `num_bytes_consumed` at 0, then 4k, and then
+// 12k; the ordering of those individual progressions is guaranteed, but there's
+// no guarantee that an observer will see `num_parcels_consumed` as 1 at the
+// same time they see `num_bytes_consumed` as 4k.
+class alignas(8) AtomicQueueState {
+ public:
+ AtomicQueueState() noexcept;
+
+ // Performs a best-effort query of the most recently visible value on both
+ // fields and returns them as a QueryResult. `monitors` determines whether
+ // each field will be atomically marked for monitoring at the same time its
+ // value is retrieved.
+ struct QueryResult {
+ MonitoredAtomic<uint64_t>::State num_parcels_consumed;
+ MonitoredAtomic<uint64_t>::State num_bytes_consumed;
+ };
+ struct MonitorSelection {
+ bool monitor_parcels;
+ bool monitor_bytes;
+ };
+ QueryResult Query(const MonitorSelection& monitors);
+
+ // Updates both fields with new values, resetting any monitor bit that may
+ // have been set on either one. If either field had a monitor bit set prior to
+ // this update, this returns true. Otherwise it returns false.
+ struct UpdateValue {
+ uint64_t num_parcels_consumed;
+ uint64_t num_bytes_consumed;
+ };
+ bool Update(const UpdateValue& value);
+
+ private:
+ // The number of parcels consumed from the router's inbound parcel queue,
+ // either by the application reading from its portal, or by ipcz proxying them
+ // onward to another router.
+ MonitoredAtomic<uint64_t> num_parcels_consumed_{0};
+
+ // The total number of bytes of data consumed from the router's inbound parcel
+ // queue. This is the sum of the data size of all parcels covered by
+ // `consumed_sequence_length`, plus any bytes already consumed from the
+ // next parcel in sequence if it's been partially consumed..
+ MonitoredAtomic<uint64_t> num_bytes_consumed_{0};
+};
+
+// This must remain stable at 16 bytes in size, as it's part of shared memory
+// layouts. Trivial copyability is also required as a proxy condition to prevent
+// changes which might break that usage (e.g. introduction of a non-trivial
+// destructor.)
+static_assert(sizeof(AtomicQueueState) == 16, "Invalid AtomicQueueState size");
+static_assert(std::is_trivially_copyable_v<AtomicQueueState>,
+ "AtomicQueueState must be trivially copyable");
+
+} // namespace ipcz
+
+#endif // IPCZ_SRC_IPCZ_ATOMIC_QUEUE_STATE_
diff --git a/chromium/third_party/ipcz/src/ipcz/block_allocator.cc b/chromium/third_party/ipcz/src/ipcz/block_allocator.cc
index 8b0cdb518d4..a826bd79d3f 100644
--- a/chromium/third_party/ipcz/src/ipcz/block_allocator.cc
+++ b/chromium/third_party/ipcz/src/ipcz/block_allocator.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/block_allocator.h b/chromium/third_party/ipcz/src/ipcz/block_allocator.h
index 8f6781bf2ab..ff9b29318eb 100644
--- a/chromium/third_party/ipcz/src/ipcz/block_allocator.h
+++ b/chromium/third_party/ipcz/src/ipcz/block_allocator.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.cc b/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.cc
index 8e32b5404e6..bd464f897d1 100644
--- a/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.cc
+++ b/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.h b/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.h
index bbaed157671..103e2949014 100644
--- a/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.h
+++ b/chromium/third_party/ipcz/src/ipcz/block_allocator_pool.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/block_allocator_test.cc b/chromium/third_party/ipcz/src/ipcz/block_allocator_test.cc
index 01327939375..dcd339de1a9 100644
--- a/chromium/third_party/ipcz/src/ipcz/block_allocator_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/block_allocator_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/box.cc b/chromium/third_party/ipcz/src/ipcz/box.cc
index ca4d19e9457..f6e2285ddc8 100644
--- a/chromium/third_party/ipcz/src/ipcz/box.cc
+++ b/chromium/third_party/ipcz/src/ipcz/box.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/box.h b/chromium/third_party/ipcz/src/ipcz/box.h
index a861405e6b3..9a13d17cb53 100644
--- a/chromium/third_party/ipcz/src/ipcz/box.h
+++ b/chromium/third_party/ipcz/src/ipcz/box.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/buffer_id.h b/chromium/third_party/ipcz/src/ipcz/buffer_id.h
index 763a436d1de..99635050362 100644
--- a/chromium/third_party/ipcz/src/ipcz/buffer_id.h
+++ b/chromium/third_party/ipcz/src/ipcz/buffer_id.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/buffer_pool.cc b/chromium/third_party/ipcz/src/ipcz/buffer_pool.cc
index 945e33eda15..6881346d8f8 100644
--- a/chromium/third_party/ipcz/src/ipcz/buffer_pool.cc
+++ b/chromium/third_party/ipcz/src/ipcz/buffer_pool.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/buffer_pool.h b/chromium/third_party/ipcz/src/ipcz/buffer_pool.h
index 4244375ba68..9a73aef4634 100644
--- a/chromium/third_party/ipcz/src/ipcz/buffer_pool.h
+++ b/chromium/third_party/ipcz/src/ipcz/buffer_pool.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/buffer_pool_test.cc b/chromium/third_party/ipcz/src/ipcz/buffer_pool_test.cc
index 428b61cb376..a009ffe1c20 100644
--- a/chromium/third_party/ipcz/src/ipcz/buffer_pool_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/buffer_pool_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_memory.cc b/chromium/third_party/ipcz/src/ipcz/driver_memory.cc
index bc28fcdc6c6..6dcf5c4dcc0 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_memory.cc
+++ b/chromium/third_party/ipcz/src/ipcz/driver_memory.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_memory.h b/chromium/third_party/ipcz/src/ipcz/driver_memory.h
index 3545418d1f4..2a5569967bb 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_memory.h
+++ b/chromium/third_party/ipcz/src/ipcz/driver_memory.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.cc b/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.cc
index d2c04f1b3e9..9d0b8c0833b 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.cc
+++ b/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.h b/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.h
index 525f3508400..946518783ef 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.h
+++ b/chromium/third_party/ipcz/src/ipcz/driver_memory_mapping.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_memory_test.cc b/chromium/third_party/ipcz/src/ipcz/driver_memory_test.cc
index bd6ab4693e6..cb16efe94e5 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_memory_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/driver_memory_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_object.cc b/chromium/third_party/ipcz/src/ipcz/driver_object.cc
index 5f429c7082a..967b3b41b64 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_object.cc
+++ b/chromium/third_party/ipcz/src/ipcz/driver_object.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_object.h b/chromium/third_party/ipcz/src/ipcz/driver_object.h
index 2a5ecac8fff..44b0c688956 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_object.h
+++ b/chromium/third_party/ipcz/src/ipcz/driver_object.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_object_test.cc b/chromium/third_party/ipcz/src/ipcz/driver_object_test.cc
index 35a7279f3c4..78ce1da9245 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_object_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/driver_object_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_transport.cc b/chromium/third_party/ipcz/src/ipcz/driver_transport.cc
index f78971c640c..0103284c7bd 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_transport.cc
+++ b/chromium/third_party/ipcz/src/ipcz/driver_transport.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_transport.h b/chromium/third_party/ipcz/src/ipcz/driver_transport.h
index a9f79f53733..e95bffffcef 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_transport.h
+++ b/chromium/third_party/ipcz/src/ipcz/driver_transport.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/driver_transport_test.cc b/chromium/third_party/ipcz/src/ipcz/driver_transport_test.cc
index 0af63717c6b..e64dab378cb 100644
--- a/chromium/third_party/ipcz/src/ipcz/driver_transport_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/driver_transport_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/fragment.cc b/chromium/third_party/ipcz/src/ipcz/fragment.cc
index 2cb2e8753a3..651d1c2fca5 100644
--- a/chromium/third_party/ipcz/src/ipcz/fragment.cc
+++ b/chromium/third_party/ipcz/src/ipcz/fragment.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/fragment.h b/chromium/third_party/ipcz/src/ipcz/fragment.h
index e1a87d2122d..c0151fdcf4b 100644
--- a/chromium/third_party/ipcz/src/ipcz/fragment.h
+++ b/chromium/third_party/ipcz/src/ipcz/fragment.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.cc b/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.cc
index 1e65f2832f2..6ef132c6a57 100644
--- a/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.cc
+++ b/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.h b/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.h
index 578acca45e4..b247215fd5e 100644
--- a/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.h
+++ b/chromium/third_party/ipcz/src/ipcz/fragment_descriptor.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/fragment_ref.cc b/chromium/third_party/ipcz/src/ipcz/fragment_ref.cc
index b294e1cadb3..30ea949d8d1 100644
--- a/chromium/third_party/ipcz/src/ipcz/fragment_ref.cc
+++ b/chromium/third_party/ipcz/src/ipcz/fragment_ref.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/fragment_ref.h b/chromium/third_party/ipcz/src/ipcz/fragment_ref.h
index e54135b01aa..6f6ef49df67 100644
--- a/chromium/third_party/ipcz/src/ipcz/fragment_ref.h
+++ b/chromium/third_party/ipcz/src/ipcz/fragment_ref.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/handle_type.h b/chromium/third_party/ipcz/src/ipcz/handle_type.h
index df08a27a45d..26a15f13abe 100644
--- a/chromium/third_party/ipcz/src/ipcz/handle_type.h
+++ b/chromium/third_party/ipcz/src/ipcz/handle_type.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/link_side.cc b/chromium/third_party/ipcz/src/ipcz/link_side.cc
index d6bb1836f1e..40f029ef9a1 100644
--- a/chromium/third_party/ipcz/src/ipcz/link_side.cc
+++ b/chromium/third_party/ipcz/src/ipcz/link_side.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/link_side.h b/chromium/third_party/ipcz/src/ipcz/link_side.h
index 7032e9a0e0a..5d95a1995c0 100644
--- a/chromium/third_party/ipcz/src/ipcz/link_side.h
+++ b/chromium/third_party/ipcz/src/ipcz/link_side.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/link_type.cc b/chromium/third_party/ipcz/src/ipcz/link_type.cc
index d69a4514229..c98306cc525 100644
--- a/chromium/third_party/ipcz/src/ipcz/link_type.cc
+++ b/chromium/third_party/ipcz/src/ipcz/link_type.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/link_type.h b/chromium/third_party/ipcz/src/ipcz/link_type.h
index 28b52c5115e..1c4eacccf6a 100644
--- a/chromium/third_party/ipcz/src/ipcz/link_type.h
+++ b/chromium/third_party/ipcz/src/ipcz/link_type.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/local_router_link.cc b/chromium/third_party/ipcz/src/ipcz/local_router_link.cc
index e675a579fab..6091424a5e1 100644
--- a/chromium/third_party/ipcz/src/ipcz/local_router_link.cc
+++ b/chromium/third_party/ipcz/src/ipcz/local_router_link.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -94,6 +94,10 @@ RouterLinkState* LocalRouterLink::GetLinkState() const {
return &state_->link_state();
}
+void LocalRouterLink::WaitForLinkStateAsync(std::function<void()> callback) {
+ callback();
+}
+
Ref<Router> LocalRouterLink::GetLocalPeer() {
return state_->GetRouter(side_.opposite());
}
@@ -108,47 +112,42 @@ void LocalRouterLink::AllocateParcelData(size_t num_bytes,
parcel.AllocateData(num_bytes, allow_partial, /*memory=*/nullptr);
}
-void LocalRouterLink::AcceptParcel(Parcel& parcel) {
+void LocalRouterLink::AcceptParcel(const OperationContext& context,
+ Parcel& parcel) {
if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
if (state_->type() == LinkType::kCentral) {
- receiver->AcceptInboundParcel(parcel);
+ receiver->AcceptInboundParcel(context, parcel);
} else {
ABSL_ASSERT(state_->type() == LinkType::kBridge);
- receiver->AcceptOutboundParcel(parcel);
+ receiver->AcceptOutboundParcel(context, parcel);
}
}
}
-void LocalRouterLink::AcceptRouteClosure(SequenceNumber sequence_length) {
+void LocalRouterLink::AcceptRouteClosure(const OperationContext& context,
+ SequenceNumber sequence_length) {
if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
- receiver->AcceptRouteClosureFrom(state_->type(), sequence_length);
+ receiver->AcceptRouteClosureFrom(context, state_->type(), sequence_length);
}
}
-size_t LocalRouterLink::GetParcelCapacityInBytes(const IpczPutLimits& limits) {
- return state_->GetRouter(side_.opposite())->GetInboundCapacityInBytes(limits);
-}
-
-RouterLinkState::QueueState LocalRouterLink::GetPeerQueueState() {
- return state_->link_state().GetQueueState(side_.opposite());
+AtomicQueueState* LocalRouterLink::GetPeerQueueState() {
+ return &state_->link_state().GetQueueState(side_.opposite());
}
-bool LocalRouterLink::UpdateInboundQueueState(size_t num_parcels,
- size_t num_bytes) {
- return state_->link_state().UpdateQueueState(side_, num_parcels, num_bytes);
+AtomicQueueState* LocalRouterLink::GetLocalQueueState() {
+ return &state_->link_state().GetQueueState(side_);
}
-void LocalRouterLink::NotifyDataConsumed() {
- state_->GetRouter(side_.opposite())->NotifyPeerConsumedData();
-}
-
-bool LocalRouterLink::EnablePeerMonitoring(bool enable) {
- return state_->link_state().SetSideIsMonitoringPeer(side_, enable);
+void LocalRouterLink::SnapshotPeerQueueState(const OperationContext& context) {
+ if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
+ receiver->SnapshotPeerQueueState(context);
+ }
}
-void LocalRouterLink::AcceptRouteDisconnected() {
+void LocalRouterLink::AcceptRouteDisconnected(const OperationContext& context) {
if (Ref<Router> receiver = state_->GetRouter(side_.opposite())) {
- receiver->AcceptRouteDisconnectedFrom(state_->type());
+ receiver->AcceptRouteDisconnectedFrom(context, state_->type());
}
}
@@ -174,10 +173,11 @@ void LocalRouterLink::Unlock() {
state_->link_state().Unlock(side_);
}
-bool LocalRouterLink::FlushOtherSideIfWaiting() {
+bool LocalRouterLink::FlushOtherSideIfWaiting(const OperationContext& context) {
const LinkSide other_side = side_.opposite();
if (state_->link_state().ResetWaitingBit(other_side)) {
- state_->GetRouter(other_side)->Flush(Router::kForceProxyBypassAttempt);
+ state_->GetRouter(other_side)
+ ->Flush(context, Router::kForceProxyBypassAttempt);
return true;
}
return false;
@@ -192,24 +192,28 @@ bool LocalRouterLink::CanNodeRequestBypass(
allowed_source == bypass_request_source;
}
-void LocalRouterLink::BypassPeer(const NodeName& bypass_target_node,
+void LocalRouterLink::BypassPeer(const OperationContext& context,
+ const NodeName& bypass_target_node,
SublinkId bypass_target_sublink) {
// Not implemented, and never called on local links.
ABSL_ASSERT(false);
}
-void LocalRouterLink::StopProxying(SequenceNumber inbound_sequence_length,
+void LocalRouterLink::StopProxying(const OperationContext& context,
+ SequenceNumber inbound_sequence_length,
SequenceNumber outbound_sequence_length) {
// Not implemented, and never called on local links.
ABSL_ASSERT(false);
}
-void LocalRouterLink::ProxyWillStop(SequenceNumber inbound_sequence_length) {
+void LocalRouterLink::ProxyWillStop(const OperationContext& context,
+ SequenceNumber inbound_sequence_length) {
// Not implemented, and never called on local links.
ABSL_ASSERT(false);
}
void LocalRouterLink::BypassPeerWithLink(
+ const OperationContext& context,
SublinkId new_sublink,
FragmentRef<RouterLinkState> new_link_state,
SequenceNumber inbound_sequence_length) {
@@ -218,6 +222,7 @@ void LocalRouterLink::BypassPeerWithLink(
}
void LocalRouterLink::StopProxyingToLocalPeer(
+ const OperationContext& context,
SequenceNumber outbound_sequence_length) {
// Not implemented, and never called on local links.
ABSL_ASSERT(false);
diff --git a/chromium/third_party/ipcz/src/ipcz/local_router_link.h b/chromium/third_party/ipcz/src/ipcz/local_router_link.h
index 512230877ae..ccf33f2e7e7 100644
--- a/chromium/third_party/ipcz/src/ipcz/local_router_link.h
+++ b/chromium/third_party/ipcz/src/ipcz/local_router_link.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -35,34 +35,39 @@ class LocalRouterLink : public RouterLink {
// RouterLink:
LinkType GetType() const override;
RouterLinkState* GetLinkState() const override;
+ void WaitForLinkStateAsync(std::function<void()> callback) override;
Ref<Router> GetLocalPeer() override;
RemoteRouterLink* AsRemoteRouterLink() override;
void AllocateParcelData(size_t num_bytes,
bool allow_partial,
Parcel& parcel) override;
- void AcceptParcel(Parcel& parcel) override;
- void AcceptRouteClosure(SequenceNumber sequence_length) override;
- void AcceptRouteDisconnected() override;
- size_t GetParcelCapacityInBytes(const IpczPutLimits& limits) override;
- RouterLinkState::QueueState GetPeerQueueState() override;
- bool UpdateInboundQueueState(size_t num_parcels, size_t num_bytes) override;
- void NotifyDataConsumed() override;
- bool EnablePeerMonitoring(bool enable) override;
+ void AcceptParcel(const OperationContext& context, Parcel& parcel) override;
+ void AcceptRouteClosure(const OperationContext& context,
+ SequenceNumber sequence_length) override;
+ void AcceptRouteDisconnected(const OperationContext& context) override;
+ AtomicQueueState* GetPeerQueueState() override;
+ AtomicQueueState* GetLocalQueueState() override;
+ void SnapshotPeerQueueState(const OperationContext& context) override;
void MarkSideStable() override;
bool TryLockForBypass(const NodeName& bypass_request_source) override;
bool TryLockForClosure() override;
void Unlock() override;
- bool FlushOtherSideIfWaiting() override;
+ bool FlushOtherSideIfWaiting(const OperationContext& context) override;
bool CanNodeRequestBypass(const NodeName& bypass_request_source) override;
- void BypassPeer(const NodeName& bypass_target_node,
+ void BypassPeer(const OperationContext& context,
+ const NodeName& bypass_target_node,
SublinkId bypass_target_sublink) override;
- void StopProxying(SequenceNumber inbound_sequence_length,
+ void StopProxying(const OperationContext& context,
+ SequenceNumber inbound_sequence_length,
SequenceNumber outbound_sequence_length) override;
- void ProxyWillStop(SequenceNumber inbound_sequence_length) override;
- void BypassPeerWithLink(SublinkId new_sublink,
+ void ProxyWillStop(const OperationContext& context,
+ SequenceNumber inbound_sequence_length) override;
+ void BypassPeerWithLink(const OperationContext& context,
+ SublinkId new_sublink,
FragmentRef<RouterLinkState> new_link_state,
SequenceNumber inbound_sequence_length) override;
void StopProxyingToLocalPeer(
+ const OperationContext& context,
SequenceNumber outbound_sequence_length) override;
void Deactivate() override;
std::string Describe() const override;
diff --git a/chromium/third_party/ipcz/src/ipcz/message.cc b/chromium/third_party/ipcz/src/ipcz/message.cc
index 1b686ed649f..fea6a45fbd5 100644
--- a/chromium/third_party/ipcz/src/ipcz/message.cc
+++ b/chromium/third_party/ipcz/src/ipcz/message.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message.h b/chromium/third_party/ipcz/src/ipcz/message.h
index 180f207d49a..879afcd66c0 100644
--- a/chromium/third_party/ipcz/src/ipcz/message.h
+++ b/chromium/third_party/ipcz/src/ipcz/message.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h
index ecfc7243285..89b5e68dbe9 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/message_declaration_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h
index a373ca652ab..f4149ae8e41 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/message_definition_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_declaration_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_declaration_macros.h
index 05e00a17634..a60eada1c7e 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_declaration_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_declaration_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_definition_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_definition_macros.h
index 1525d24f135..72b31e45195 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_definition_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_definition_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_dispatch_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_dispatch_macros.h
index 719944bbf52..5e8738420c5 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_dispatch_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/message_listener_dispatch_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_declaration_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_declaration_macros.h
index b50ed1e391d..aea9cd54b01 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_declaration_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_declaration_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_definition_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_definition_macros.h
index b4bfa11bc90..04789edffa3 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_definition_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/message_params_definition_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_macros/undef_message_macros.h b/chromium/third_party/ipcz/src/ipcz/message_macros/undef_message_macros.h
index bc07bf5e66e..a5b260468aa 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_macros/undef_message_macros.h
+++ b/chromium/third_party/ipcz/src/ipcz/message_macros/undef_message_macros.h
@@ -1,9 +1,9 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// no-include-guard-because-multiply-included
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/message_test.cc b/chromium/third_party/ipcz/src/ipcz/message_test.cc
index 9b21738f73a..ee85d11103e 100644
--- a/chromium/third_party/ipcz/src/ipcz/message_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/message_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/monitored_atomic.h b/chromium/third_party/ipcz/src/ipcz/monitored_atomic.h
new file mode 100644
index 00000000000..b8ec5c4f316
--- /dev/null
+++ b/chromium/third_party/ipcz/src/ipcz/monitored_atomic.h
@@ -0,0 +1,77 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPCZ_SRC_IPCZ_MONITORED_VALUE_H_
+#define IPCZ_SRC_IPCZ_MONITORED_VALUE_H_
+
+#include <atomic>
+#include <limits>
+#include <type_traits>
+
+namespace ipcz {
+
+// MonitoredAtomic is a trivial wrapper around around an atomic unsigned
+// integral value, with the high bit reserved for primitive communication
+// between one producer and any number of concurrent consumers of the value.
+//
+// Consumers can atomically query the value while simultaneously signaling that
+// they want to be notified about the next time the value changes. Producers can
+// atomically update the value while simulataneously querying (and resetting)
+// the consumer's interest in being notified about the change.
+template <typename T>
+class MonitoredAtomic {
+ static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
+ "MonitoredAtomic requires an unsigned integral type");
+
+ public:
+ struct State {
+ T value;
+ bool monitored;
+ };
+
+ static constexpr T kMaxValue = std::numeric_limits<T>::max() >> 1;
+ static constexpr T kMonitorBit = kMaxValue + 1;
+
+ MonitoredAtomic() noexcept = default;
+ explicit MonitoredAtomic(T value) noexcept : value_(value) {}
+
+ // Returns a best-effort snapshot of the most recent underlying value. If
+ // `monitor` is true in `options`, then the stored value is also atomically
+ // flagged for monitoring.
+ struct QueryOptions {
+ bool monitor;
+ };
+ State Query(const QueryOptions& options) {
+ T value = value_.load(std::memory_order_relaxed);
+ while (options.monitor && !IsMonitored(value) &&
+ !value_.compare_exchange_weak(value, Monitored(value),
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ }
+ return {.value = Unmonitored(value), .monitored = IsMonitored(value)};
+ }
+
+ // Stores a new underlying value, resetting the monitor bit if it was set.
+ // Returns a boolean indicating whether the monitor bit was set.
+ [[nodiscard]] bool UpdateValueAndResetMonitor(T value) {
+ T old_value = value_.load(std::memory_order_relaxed);
+ while (value != old_value &&
+ !value_.compare_exchange_weak(old_value, value,
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ }
+ return IsMonitored(old_value);
+ }
+
+ private:
+ static bool IsMonitored(T value) { return (value & kMonitorBit) != 0; }
+ static T Monitored(T value) { return value | kMonitorBit; }
+ static T Unmonitored(T value) { return value & kMaxValue; }
+
+ std::atomic<T> value_{0};
+};
+
+} // namespace ipcz
+
+#endif // IPCZ_SRC_IPCZ_MONITORED_VALUE_H_
diff --git a/chromium/third_party/ipcz/src/ipcz/node.cc b/chromium/third_party/ipcz/src/ipcz/node.cc
index 19e584a4362..f2fc29e5454 100644
--- a/chromium/third_party/ipcz/src/ipcz/node.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,12 +16,60 @@
#include "ipcz/portal.h"
#include "ipcz/router.h"
#include "third_party/abseil-cpp/absl/base/macros.h"
+#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
#include "third_party/abseil-cpp/absl/synchronization/mutex.h"
+#include "third_party/abseil-cpp/absl/types/span.h"
#include "util/log.h"
#include "util/ref_counted.h"
namespace ipcz {
+// A pending introduction tracks progress of one or more outstanding
+// introduction requests for a single node in the system.
+class Node::PendingIntroduction {
+ public:
+ // Constructs a new object to track introduction a specific node. `broker`
+ // is the sequence of broker nodes queried for the introduction.
+ explicit PendingIntroduction(absl::Span<const Ref<NodeLink>> brokers) {
+ pending_replies_.reserve(brokers.size());
+ for (const auto& broker : brokers) {
+ pending_replies_.insert(broker->remote_node_name());
+ }
+ }
+
+ // Indicates that all pending responses have come back indicating failure,
+ // and that the pending introduction itself has failed.
+ bool failed() const { return pending_replies_.empty(); }
+
+ // Marks a specific broker as having responded with rejection.
+ void NotifyFailureFrom(NodeLink& rejecting_broker) {
+ pending_replies_.erase(rejecting_broker.remote_node_name());
+ }
+
+ // Registers a new callback to be invoked once the introduction process has
+ // completed, regardless of success or failure.
+ void AddCallback(Node::EstablishLinkCallback callback) {
+ callbacks_.push_back(std::move(callback));
+ }
+
+ // Runs all callbacks associated with this introduction. If the introduction
+ // failed, `result` will be null. Otherwise it's a link to the newly
+ // introduced remote node.
+ void Finish(NodeLink* result) {
+ for (auto& callback : callbacks_) {
+ callback(result);
+ }
+ }
+
+ private:
+ // Set of brokers from whom we're still expecting a reply for this pending
+ // introduction request.
+ absl::flat_hash_set<NodeName> pending_replies_;
+
+ // Callbacks to be invoked once the introduction is finished.
+ std::vector<EstablishLinkCallback> callbacks_;
+};
+
Node::Node(Type type, const IpczDriver& driver, IpczDriverHandle driver_node)
: type_(type), driver_(driver), driver_node_(driver_node) {
if (type_ == Type::kBroker) {
@@ -80,46 +128,66 @@ Ref<NodeLink> Node::GetBrokerLink() {
return broker_link_;
}
-void Node::SetBrokerLink(Ref<NodeLink> link) {
- std::vector<BrokerLinkCallback> callbacks;
- {
- absl::MutexLock lock(&mutex_);
- ABSL_ASSERT(!broker_link_);
- broker_link_ = link;
- broker_link_callbacks_.swap(callbacks);
- }
-
- for (auto& callback : callbacks) {
- callback(link);
- }
-}
-
void Node::SetAssignedName(const NodeName& name) {
absl::MutexLock lock(&mutex_);
ABSL_ASSERT(!assigned_name_.is_valid());
assigned_name_ = name;
}
-bool Node::AddLink(const NodeName& remote_node_name, Ref<NodeLink> link) {
+bool Node::AddConnection(const NodeName& remote_node_name,
+ Connection connection) {
+ std::vector<BrokerLinkCallback> callbacks;
{
- absl::MutexLock lock(&mutex_);
- auto [it, inserted] = node_links_.insert({remote_node_name, link});
- if (inserted) {
- return true;
+ absl::ReleasableMutexLock lock(&mutex_);
+ auto [it, inserted] = connections_.insert({remote_node_name, connection});
+ if (!inserted) {
+ lock.Release();
+
+ const OperationContext context{OperationContext::kTransportNotification};
+ connection.link->Deactivate(context);
+ return false;
+ }
+
+ const bool remote_is_broker =
+ connection.link->remote_node_type() == Type::kBroker;
+ const bool local_is_broker = type_ == Type::kBroker;
+ if (local_is_broker && remote_is_broker) {
+ // We're a broker, and this is a link to some other broker. We retain a
+ // separate mapping of other brokers so they can be consulted for
+ // introductions.
+ other_brokers_.insert({remote_node_name, connection.link});
+ } else if (remote_is_broker) {
+ // The first connection accepted by a non-broker must be a connection to
+ // its own broker.
+ ABSL_ASSERT(connections_.size() == 1);
+ ABSL_ASSERT(!broker_link_);
+ broker_link_ = connection.link;
+ broker_link_callbacks_.swap(callbacks);
}
}
- link->Deactivate();
- return false;
+ for (auto& callback : callbacks) {
+ callback(connection.link);
+ }
+ return true;
+}
+
+absl::optional<Node::Connection> Node::GetConnection(const NodeName& name) {
+ absl::MutexLock lock(&mutex_);
+ auto it = connections_.find(name);
+ if (it == connections_.end()) {
+ return absl::nullopt;
+ }
+ return it->second;
}
Ref<NodeLink> Node::GetLink(const NodeName& name) {
absl::MutexLock lock(&mutex_);
- auto it = node_links_.find(name);
- if (it == node_links_.end()) {
+ auto it = connections_.find(name);
+ if (it == connections_.end()) {
return nullptr;
}
- return it->second;
+ return it->second.link;
}
NodeName Node::GenerateRandomName() const {
@@ -152,30 +220,50 @@ void Node::AllocateSharedMemory(size_t size,
}
void Node::EstablishLink(const NodeName& name, EstablishLinkCallback callback) {
- Ref<NodeLink> broker;
- Ref<NodeLink> link;
+ Ref<NodeLink> existing_link;
+ absl::InlinedVector<Ref<NodeLink>, 2> brokers_to_query;
{
absl::MutexLock lock(&mutex_);
- broker = broker_link_;
- auto it = node_links_.find(name);
- if (it != node_links_.end()) {
- link = it->second;
- } else if (type_ == Type::kNormal && broker) {
- auto [pending_it, inserted] = pending_introductions_.insert({name, {}});
- pending_it->second.push_back(std::move(callback));
- if (!inserted) {
- // There's already an introduction request out for this node, so there's
- // nothing more we need to do.
- return;
+ auto it = connections_.find(name);
+ if (it != connections_.end()) {
+ existing_link = it->second.link;
+ } else {
+ if (type_ == Type::kNormal && broker_link_) {
+ brokers_to_query.push_back(broker_link_);
+ } else if (!other_brokers_.empty()) {
+ ABSL_ASSERT(type_ == Type::kBroker);
+ brokers_to_query.reserve(other_brokers_.size());
+ for (const auto& [broker_name, link] : other_brokers_) {
+ brokers_to_query.push_back(link);
+ }
+ }
+
+ if (!brokers_to_query.empty()) {
+ auto [pending_it, inserted] =
+ pending_introductions_.insert({name, nullptr});
+ auto& intro = pending_it->second;
+ if (!intro) {
+ intro = std::make_unique<PendingIntroduction>(
+ absl::MakeSpan(brokers_to_query));
+ }
+ intro->AddCallback(std::move(callback));
+ if (!inserted) {
+ // There was already a pending introduction we can wait for.
+ return;
+ }
}
}
}
- if (broker && !link) {
- broker->RequestIntroduction(name);
- } else {
- callback(link.get());
+ if (!brokers_to_query.empty()) {
+ for (const auto& broker : brokers_to_query) {
+ broker->RequestIntroduction(name);
+ }
+ return;
}
+
+ // NOTE: `existing_link` may be null here, implying that we have failed.
+ callback(existing_link.get());
}
void Node::HandleIntroductionRequest(NodeLink& from_node_link,
@@ -189,50 +277,62 @@ void Node::HandleIntroductionRequest(NodeLink& from_node_link,
<< " received introduction request for " << for_node.ToString()
<< " from " << requestor.ToString();
- // A key which uniquely identifies the pair of nodes being introduced
- // regardless of who requested the introduction.
- const auto key = (requestor < for_node)
- ? IntroductionKey(requestor, for_node)
- : IntroductionKey(for_node, requestor);
-
- Ref<NodeLink> target_link;
- {
- absl::MutexLock lock(&mutex_);
- auto it = node_links_.find(for_node);
- if (it != node_links_.end()) {
- target_link = it->second;
-
- auto [intro_it, inserted] = in_progress_introductions_.insert(key);
- if (!inserted) {
- // We're already introducing the same two nodes, so drop this request.
+ const absl::optional<Connection> target_connection = GetConnection(for_node);
+ if (!target_connection) {
+ // We are not familiar with the requested node. Attempt to establish our own
+ // link to it first, then try again.
+ EstablishLink(for_node, [self = WrapRefCounted(this),
+ requestor = WrapRefCounted(&from_node_link),
+ name = for_node](NodeLink* link) {
+ if (!link) {
+ requestor->RejectIntroduction(name);
return;
}
- }
+
+ self->HandleIntroductionRequest(*requestor, name);
+ });
+ return;
}
- if (!target_link) {
- from_node_link.RejectIntroduction(for_node);
+ const bool is_target_in_network = !target_connection->broker;
+ const bool is_target_broker =
+ target_connection->link == target_connection->broker;
+ const bool is_requestor_broker =
+ from_node_link.remote_node_type() == Type::kBroker;
+ if (is_requestor_broker && is_target_broker) {
+ DLOG(ERROR) << "Invalid introduction request from broker "
+ << requestor.ToString() << " for broker "
+ << for_node.ToString();
return;
}
- DriverMemoryWithMapping buffer = NodeLinkMemory::AllocateMemory(driver_);
- auto [transport_for_target, transport_for_requestor] =
- DriverTransport::CreatePair(driver_, target_link->transport().get(),
- from_node_link.transport().get());
- target_link->AcceptIntroduction(
- requestor, LinkSide::kA, from_node_link.remote_protocol_version(),
- std::move(transport_for_target), buffer.memory.Clone());
- from_node_link.AcceptIntroduction(
- for_node, LinkSide::kB, target_link->remote_protocol_version(),
- std::move(transport_for_requestor), std::move(buffer.memory));
+ if (is_target_broker || is_requestor_broker || is_target_in_network ||
+ target_connection->broker->link_side().is_side_a()) {
+ // If one of the two nodes being introduced is a broker, or if the target
+ // is in-network (which implies the requestor is too, if it's not a broker)
+ // then we are the only node that can introduce these two nodes.
+ //
+ // Otherwise if this is an introduction between two non-brokers in separate
+ // networks, by convention we can only perform the introduction if we're on
+ // side A of the link between the two relevant brokers.
+ IntroduceRemoteNodes(from_node_link, *target_connection->link);
+ return;
+ }
- absl::MutexLock lock(&mutex_);
- in_progress_introductions_.erase(key);
+ // This is an introduction between two non-brokers in separate networks, and
+ // we (one of the networks' brokers) are on side B of the link to the other
+ // network's broker. This introduction is therefore the other broker's
+ // responsibility.
+ msg::RequestIndirectIntroduction request;
+ request.params().source_node = from_node_link.remote_node_name();
+ request.params().target_node = target_connection->link->remote_node_name();
+ target_connection->broker->Transmit(request);
}
void Node::AcceptIntroduction(NodeLink& from_node_link,
const NodeName& name,
LinkSide side,
+ Node::Type remote_node_type,
uint32_t remote_protocol_version,
Ref<DriverTransport> transport,
Ref<NodeLinkMemory> memory) {
@@ -247,14 +347,25 @@ void Node::AcceptIntroduction(NodeLink& from_node_link,
<< from_node_link.remote_node_name().ToString();
Ref<NodeLink> new_link = NodeLink::CreateInactive(
- WrapRefCounted(this), side, local_name, name, Type::kNormal,
+ WrapRefCounted(this), side, local_name, name, remote_node_type,
remote_protocol_version, transport, memory);
ABSL_ASSERT(new_link);
- std::vector<EstablishLinkCallback> callbacks;
+ std::unique_ptr<PendingIntroduction> pending_introduction;
{
absl::MutexLock lock(&mutex_);
- auto [link_it, inserted] = node_links_.insert({name, new_link});
+ if (type_ == Type::kNormal && !broker_link_) {
+ // If we've lost our broker connection, we should ignore any further
+ // introductions that arrive.
+ return;
+ }
+
+ auto [connection_it, inserted] =
+ connections_.insert({name,
+ {
+ .link = new_link,
+ .broker = WrapRefCounted(&from_node_link),
+ }});
if (!inserted) {
// If both nodes race to request an introduction to each other, the
// broker may send redundant introductions. It does however take care to
@@ -269,34 +380,39 @@ void Node::AcceptIntroduction(NodeLink& from_node_link,
// requested it.
auto it = pending_introductions_.find(name);
if (it != pending_introductions_.end()) {
- callbacks = std::move(it->second);
+ pending_introduction = std::move(it->second);
pending_introductions_.erase(it);
}
}
new_link->Activate();
- for (auto& callback : callbacks) {
- callback(new_link.get());
+ if (pending_introduction) {
+ pending_introduction->Finish(new_link.get());
}
}
-bool Node::CancelIntroduction(const NodeName& name) {
- std::vector<EstablishLinkCallback> callbacks;
+void Node::NotifyIntroductionFailed(NodeLink& from_broker,
+ const NodeName& name) {
+ std::unique_ptr<PendingIntroduction> failed_introduction;
{
absl::MutexLock lock(&mutex_);
auto it = pending_introductions_.find(name);
if (it == pending_introductions_.end()) {
- return false;
+ return;
}
- callbacks = std::move(it->second);
- pending_introductions_.erase(it);
- }
- for (auto& callback : callbacks) {
- callback(nullptr);
+ auto& intro = it->second;
+ intro->NotifyFailureFrom(from_broker);
+ if (!intro->failed()) {
+ // We're still waiting for replies from one or more other brokers.
+ return;
+ }
+
+ failed_introduction = std::move(intro);
+ pending_introductions_.erase(it);
}
- return true;
+ failed_introduction->Finish(nullptr);
}
bool Node::RelayMessage(const NodeName& from_node, msg::RelayMessage& relay) {
@@ -324,25 +440,29 @@ bool Node::AcceptRelayedMessage(msg::AcceptRelayedMessage& accept) {
return true;
}
-void Node::DropLink(const NodeName& name) {
+void Node::DropConnection(const OperationContext& context,
+ const NodeName& name) {
Ref<NodeLink> link;
+ std::vector<NodeName> pending_introductions;
bool lost_broker = false;
{
absl::MutexLock lock(&mutex_);
- auto it = node_links_.find(name);
- if (it == node_links_.end()) {
+ auto it = connections_.find(name);
+ if (it == connections_.end()) {
return;
}
- link = std::move(it->second);
- node_links_.erase(it);
+ link = std::move(it->second.link);
+ connections_.erase(it);
const NodeName& local_name = link->local_node_name();
DVLOG(4) << "Node " << local_name.ToString() << " dropping "
- << " link to " << link->remote_node_name().ToString();
+ << "link to " << link->remote_node_name().ToString();
if (link == broker_link_) {
DVLOG(4) << "Node " << local_name.ToString() << " lost its broker link";
broker_link_.reset();
lost_broker = true;
+ } else if (link->remote_node_type() == Type::kBroker) {
+ other_brokers_.erase(link->remote_node_name());
}
if (link == allocation_delegate_link_) {
@@ -350,12 +470,24 @@ void Node::DropLink(const NodeName& name) {
<< " lost its allocation delegate";
allocation_delegate_link_.reset();
}
+
+ // Accumulate the set of currently pending introductions. If any of them are
+ // awaiting a response from the dropped link, their expectations will be
+ // updated accordingly by NotifyIntroductionFailed() below.
+ pending_introductions.reserve(pending_introductions_.size());
+ for (auto& [target, intro] : pending_introductions_) {
+ pending_introductions.push_back(target);
+ }
}
- link->Deactivate();
+ link->Deactivate(context);
if (lost_broker) {
CancelAllIntroductions();
+ } else {
+ for (auto& target : pending_introductions) {
+ NotifyIntroductionFailed(*link, target);
+ }
}
}
@@ -374,17 +506,65 @@ void Node::WaitForBrokerLinkAsync(BrokerLinkCallback callback) {
callback(std::move(broker_link));
}
+bool Node::HandleIndirectIntroductionRequest(NodeLink& from_node_link,
+ const NodeName& our_node,
+ const NodeName& their_node) {
+ // Enforced by NodeLink before dispatching to this Node.
+ ABSL_ASSERT(type_ == Type::kBroker);
+ ABSL_ASSERT(from_node_link.remote_node_type() == Type::kBroker);
+ ABSL_ASSERT(from_node_link.link_side().is_side_a());
+
+ absl::optional<Connection> connection_to_their_node =
+ GetConnection(their_node);
+ if (!connection_to_their_node) {
+ // We need to establish our own direct connection to `their_node` before we
+ // can help introduce it to `our_node`.
+ EstablishLink(their_node, [self = WrapRefCounted(this),
+ their_broker = WrapRefCounted(&from_node_link),
+ our_node, their_node](NodeLink* link) {
+ if (!link) {
+ // If we could not get our own link to the identified node, then we
+ // can't complete the introduction request. Notify our own node of the
+ // failure in case they were awaiting such an introduction.
+ absl::optional<Connection> connection_to_our_node =
+ self->GetConnection(our_node);
+ if (connection_to_our_node) {
+ connection_to_our_node->link->RejectIntroduction(their_node);
+ }
+ return;
+ }
+ self->HandleIndirectIntroductionRequest(*their_broker, our_node,
+ their_node);
+ });
+ return true;
+ }
+
+ absl::optional<Connection> connection_to_our_node = GetConnection(our_node);
+ if (!connection_to_our_node) {
+ // We may have lost this connection for any number of reasons, but in any
+ // case we can't fulfill the request.
+ connection_to_their_node->link->RejectIntroduction(our_node);
+ return true;
+ }
+
+ IntroduceRemoteNodes(*connection_to_our_node->link,
+ *connection_to_their_node->link);
+ return true;
+}
+
void Node::ShutDown() {
- NodeLinkMap node_links;
+ ConnectionMap connections;
{
absl::MutexLock lock(&mutex_);
- std::swap(node_links_, node_links);
+ connections_.swap(connections);
broker_link_.reset();
allocation_delegate_link_.reset();
+ other_brokers_.clear();
}
- for (const auto& entry : node_links) {
- entry.second->Deactivate();
+ const OperationContext context{OperationContext::kAPICall};
+ for (const auto& entry : connections) {
+ entry.second.link->Deactivate(context);
}
CancelAllIntroductions();
@@ -396,12 +576,41 @@ void Node::CancelAllIntroductions() {
absl::MutexLock lock(&mutex_);
introductions.swap(pending_introductions_);
}
+ for (auto& [name, intro] : introductions) {
+ intro->Finish(nullptr);
+ }
+}
- for (auto& [name, callbacks] : introductions) {
- for (auto& callback : callbacks) {
- callback(nullptr);
+void Node::IntroduceRemoteNodes(NodeLink& first, NodeLink& second) {
+ // Ensure that no other thread does the same introduction concurrently.
+ const NodeName& first_name = first.remote_node_name();
+ const NodeName& second_name = second.remote_node_name();
+ const auto key = (first_name < second_name)
+ ? IntroductionKey(first_name, second_name)
+ : IntroductionKey(second_name, first_name);
+ {
+ absl::MutexLock lock(&mutex_);
+ auto [it, inserted] = in_progress_introductions_.insert(key);
+ if (!inserted) {
+ return;
}
}
+
+ DriverMemoryWithMapping buffer = NodeLinkMemory::AllocateMemory(driver_);
+ auto [transport_for_first_node, transport_for_second_node] =
+ DriverTransport::CreatePair(driver_, first.transport().get(),
+ second.transport().get());
+ first.AcceptIntroduction(second_name, LinkSide::kA, second.remote_node_type(),
+ second.remote_protocol_version(),
+ std::move(transport_for_first_node),
+ buffer.memory.Clone());
+ second.AcceptIntroduction(first_name, LinkSide::kB, first.remote_node_type(),
+ first.remote_protocol_version(),
+ std::move(transport_for_second_node),
+ std::move(buffer.memory));
+
+ absl::MutexLock lock(&mutex_);
+ in_progress_introductions_.erase(key);
}
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/node.h b/chromium/third_party/ipcz/src/ipcz/node.h
index 14bea6c7c52..ee9a223f62a 100644
--- a/chromium/third_party/ipcz/src/ipcz/node.h
+++ b/chromium/third_party/ipcz/src/ipcz/node.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,9 @@
#define IPCZ_SRC_IPCZ_NODE_H_
#include <functional>
+#include <memory>
+#include <utility>
+#include <vector>
#include "ipcz/api_object.h"
#include "ipcz/driver_memory.h"
@@ -13,9 +16,12 @@
#include "ipcz/link_side.h"
#include "ipcz/node_messages.h"
#include "ipcz/node_name.h"
+#include "ipcz/node_type.h"
+#include "ipcz/operation_context.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
#include "third_party/abseil-cpp/absl/synchronization/mutex.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/abseil-cpp/absl/types/span.h"
namespace ipcz {
@@ -29,17 +35,19 @@ class NodeLinkMemory;
// introduced to each other exclusively through such brokers.
class Node : public APIObjectImpl<Node, APIObject::kNode> {
public:
- enum class Type {
- // A broker node assigns its own name and is able to assign names to other
- // nodes upon connection. Brokers are trusted to introduce nodes to each
- // other upon request, and brokers may connect to other brokers in order to
- // share information and effectively bridge two node networks together.
- kBroker,
-
- // A "normal" (i.e. non-broker) node is assigned a permanent name by the
- // first broker node it connects to, and it can only make contact with other
- // nodes by requesting an introduction from that broker.
- kNormal,
+ using Type = NodeType;
+
+ // State regarding a connection to a single remote node.
+ struct Connection {
+ // The NodeLink used to communicate with the remote node.
+ Ref<NodeLink> link;
+
+ // The NodeLink used to communicate with the broker of the remote node's
+ // network. If the remote node belongs to the same network as the local
+ // node, then this is the same link the local node's `broker_link_`. If the
+ // local node *is* the broker for the remote node on `link`, then this link
+ // is null.
+ Ref<NodeLink> broker;
};
// Constructs a new node of the given `type`, using `driver` to support IPC.
@@ -69,30 +77,23 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
// Gets a reference to the node's broker link, if it has one.
Ref<NodeLink> GetBrokerLink();
- // Sets this node's broker link, which is used e.g. to make introduction
- // requests.
- //
- // This is called by a NodeConnector implementation after accepting a valid
- // handshake message from a broker node, and `link` will be used as this
- // node's permanent broker.
- //
- // Note that like any other NodeLink used by this Node, the same `link` must
- // also be registered via AddLink() to associate it with its remote Node's
- // name. This is also done by NodeConnector.
- void SetBrokerLink(Ref<NodeLink> link);
-
// Sets this node's assigned name as given by a broker. NodeConnector is
// responsible for calling on non-broker Nodes this after receiving the
// expected handshake from a broker. Must not be called on broker nodes, as
// they assign their own name at construction time.
void SetAssignedName(const NodeName& name);
- // Registers a new NodeLink for the given `remote_node_name`.
- bool AddLink(const NodeName& remote_node_name, Ref<NodeLink> link);
+ // Registers a new connection for the given `remote_node_name`.
+ bool AddConnection(const NodeName& remote_node_name, Connection connection);
+
+ // Returns a copy of the Connection to the remote node named by `name`, or
+ // null if this node has no connection to that node.
+ absl::optional<Node::Connection> GetConnection(const NodeName& name);
// Returns a reference to the NodeLink used by this Node to communicate with
// the remote node identified by `name`; or null if this node has no NodeLink
- // connected to that node.
+ // connected to that node. This is shorthand for GetConnection() in the common
+ // case where the caller only wants the underlying NodeLink.
Ref<NodeLink> GetLink(const NodeName& name);
// Generates a new random NodeName using this node's driver as a source of
@@ -138,14 +139,15 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
void AcceptIntroduction(NodeLink& from_node_link,
const NodeName& name,
LinkSide side,
+ Node::Type remote_node_type,
uint32_t remote_protocol_version,
Ref<DriverTransport> transport,
Ref<NodeLinkMemory> memory);
- // Handles a rejected introduction from the broker. This is called on a
- // non-broker node that previously requested an introduction to `name` if
- // the broker could not satisfy the request.
- bool CancelIntroduction(const NodeName& name);
+ // Handles a rejected introduction for the node named `name` from the
+ // identified broker. This is called on a node that previously requested an
+ // introduction if the broker is unable or unwilling to satisfy the request.
+ void NotifyIntroductionFailed(NodeLink& from_broker, const NodeName& name);
// Relays a message to its destination on behalf of `from_node`.
bool RelayMessage(const NodeName& from_node, msg::RelayMessage& relay);
@@ -154,8 +156,8 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
// the relay source directly.
bool AcceptRelayedMessage(msg::AcceptRelayedMessage& accept);
- // Drops this node's link to the named node, if one exists.
- void DropLink(const NodeName& name);
+ // Drops this node's connection to the named node, if one exists.
+ void DropConnection(const OperationContext& context, const NodeName& name);
// Asynchronously waits for this Node to acquire a broker link and then
// invokes `callback` with it. If this node already has a broker link then the
@@ -163,7 +165,17 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
using BrokerLinkCallback = std::function<void(Ref<NodeLink>)>;
void WaitForBrokerLinkAsync(BrokerLinkCallback callback);
+ // Processes a request for an indirect cross-network node introduction. The
+ // request was sent by `from_node_link` (a link to another broker) and is
+ // asking us to introduce `our_node` within our network to `their_node` in the
+ // the requestor's network.
+ bool HandleIndirectIntroductionRequest(NodeLink& from_node_link,
+ const NodeName& our_node,
+ const NodeName& their_node);
+
private:
+ class PendingIntroduction;
+
~Node() override;
// Deactivates all NodeLinks and their underlying driver transports in
@@ -174,6 +186,10 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
// failure.
void CancelAllIntroductions();
+ // Creates a new transport and link memory and sends introduction messages to
+ // introduce the remote node on `first` to the remote node on `second`.
+ void IntroduceRemoteNodes(NodeLink& first, NodeLink& second);
+
const Type type_;
const IpczDriver& driver_;
const IpczDriverHandle driver_node_;
@@ -186,7 +202,9 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
NodeName assigned_name_ ABSL_GUARDED_BY(mutex_);
// A link to the first broker this node connected to. If this link is broken,
- // the node will lose all its other links too.
+ // the node will lose all its other links too. This is always null on broker
+ // nodes, though brokers may keep track of links to other brokers within
+ // `other_brokers_`.
Ref<NodeLink> broker_link_ ABSL_GUARDED_BY(mutex_);
// A link over which all internal shared memory allocation is delegated. If
@@ -199,14 +217,14 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
// if this is a non-broker node. If this is a broker node, these links are
// either assigned by this node itself, or received from other brokers in the
// system.
- using NodeLinkMap = absl::flat_hash_map<NodeName, Ref<NodeLink>>;
- NodeLinkMap node_links_ ABSL_GUARDED_BY(mutex_);
+ using ConnectionMap = absl::flat_hash_map<NodeName, Connection>;
+ ConnectionMap connections_ ABSL_GUARDED_BY(mutex_);
- // A map of other nodes to which this node is waiting for an introduction from
- // `broker_link_`. Once such an introduction is received, all callbacks for
- // that NodeName are executed.
+ // A map of other nodes to which this node is waiting for an introduction,
+ // either from its own broker or (if we are a broker) all the other known
+ // brokers we're connected to.
using PendingIntroductionMap =
- absl::flat_hash_map<NodeName, std::vector<EstablishLinkCallback>>;
+ absl::flat_hash_map<NodeName, std::unique_ptr<PendingIntroduction>>;
PendingIntroductionMap pending_introductions_ ABSL_GUARDED_BY(mutex_);
// Nodes may race to request introductions to each other from the same broker.
@@ -243,6 +261,12 @@ class Node : public APIObjectImpl<Node, APIObject::kNode> {
// broker link.
std::vector<BrokerLinkCallback> broker_link_callbacks_
ABSL_GUARDED_BY(mutex_);
+
+ // Mapping of links to other known brokers in the system. This is the subset
+ // of `links_` which corresponds to remote broker nodes NOT in this node's own
+ // network. This map can only be non-empty on broker nodes.
+ absl::flat_hash_map<NodeName, Ref<NodeLink>> other_brokers_
+ ABSL_GUARDED_BY(mutex_);
};
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/node_connector.cc b/chromium/third_party/ipcz/src/ipcz/node_connector.cc
index fc44b57f135..41a64de551d 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_connector.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_connector.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,6 +14,7 @@
#include "ipcz/link_type.h"
#include "ipcz/node_link.h"
#include "ipcz/node_link_memory.h"
+#include "ipcz/operation_context.h"
#include "ipcz/portal.h"
#include "ipcz/remote_router_link.h"
#include "ipcz/router.h"
@@ -71,13 +72,12 @@ class NodeConnectorForBrokerToNonBroker : public NodeConnector {
<< broker_name_.ToString() << " from new node "
<< new_remote_node_name_.ToString();
- AcceptConnection(
- NodeLink::CreateActive(
- node_, LinkSide::kA, broker_name_, new_remote_node_name_,
- Node::Type::kNormal, connect.params().protocol_version, transport_,
- NodeLinkMemory::Create(node_,
- std::move(link_memory_allocation_.mapping))),
- LinkSide::kA, connect.params().num_initial_portals);
+ Ref<NodeLink> link = NodeLink::CreateActive(
+ node_, LinkSide::kA, broker_name_, new_remote_node_name_,
+ Node::Type::kNormal, connect.params().protocol_version, transport_,
+ NodeLinkMemory::Create(node_,
+ std::move(link_memory_allocation_.mapping)));
+ AcceptConnection({.link = link}, connect.params().num_initial_portals);
return true;
}
@@ -131,12 +131,11 @@ class NodeConnectorForNonBrokerToBroker : public NodeConnector {
connect.params().protocol_version, transport_,
NodeLinkMemory::Create(node_, buffer_memory.Map()));
node_->SetAssignedName(connect.params().receiver_name);
- node_->SetBrokerLink(new_link);
if ((flags_ & IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE) != 0) {
node_->SetAllocationDelegate(new_link);
}
- AcceptConnection(std::move(new_link), LinkSide::kB,
+ AcceptConnection({.link = new_link, .broker = new_link},
connect.params().num_initial_portals);
return true;
}
@@ -179,13 +178,13 @@ class NodeConnectorForReferrer : public NodeConnector {
broker_link_->ReferNonBroker(
std::move(transport_for_broker_), checked_cast<uint32_t>(num_portals()),
- [connector = WrapRefCounted(this)](
+ [connector = WrapRefCounted(this), broker = broker_link_](
Ref<NodeLink> link_to_referred_node,
uint32_t remote_num_initial_portals) {
if (link_to_referred_node) {
- connector->AcceptConnection(std::move(link_to_referred_node),
- LinkSide::kA,
- remote_num_initial_portals);
+ connector->AcceptConnection(
+ {.link = link_to_referred_node, .broker = broker},
+ remote_num_initial_portals);
} else {
connector->RejectConnection();
}
@@ -255,11 +254,14 @@ class NodeConnectorForReferredNonBroker : public NodeConnector {
broker_protocol_version, transport_,
NodeLinkMemory::Create(node_, broker_buffer.Map()));
node_->SetAssignedName(connect.params().name);
- node_->SetBrokerLink(broker_link);
if ((flags_ & IPCZ_CONNECT_NODE_TO_ALLOCATION_DELEGATE) != 0) {
node_->SetAllocationDelegate(broker_link);
}
- node_->AddLink(connect.params().broker_name, std::move(broker_link));
+ node_->AddConnection(connect.params().broker_name,
+ {
+ .link = broker_link,
+ .broker = broker_link,
+ });
const uint32_t referrer_protocol_version = std::min(
connect.params().referrer_protocol_version, msg::kProtocolVersion);
@@ -269,7 +271,7 @@ class NodeConnectorForReferredNonBroker : public NodeConnector {
referrer_protocol_version, std::move(referrer_transport),
NodeLinkMemory::Create(node_, referrer_buffer.Map()));
- AcceptConnection(referrer_link, LinkSide::kB,
+ AcceptConnection({.link = referrer_link, .broker = broker_link},
connect.params().num_initial_portals);
referrer_link->Activate();
return true;
@@ -324,7 +326,7 @@ class NodeConnectorForBrokerReferral : public NodeConnector {
node_, LinkSide::kA, broker_name_, referred_node_name_,
Node::Type::kNormal, protocol_version, transport_,
NodeLinkMemory::Create(node_, std::move(link_memory_.mapping)));
- AcceptConnection(link_to_referree, LinkSide::kA, /*num_remote_portals=*/0);
+ AcceptConnection({.link = link_to_referree}, /*num_remote_portals=*/0);
// Now we can create a new link to introduce both clients -- the referrer
// and the referree -- to each other.
@@ -391,6 +393,75 @@ class NodeConnectorForBrokerReferral : public NodeConnector {
NodeLinkMemory::AllocateMemory(node_->driver())};
};
+class NodeConnectorForBrokerToBroker : public NodeConnector {
+ public:
+ NodeConnectorForBrokerToBroker(Ref<Node> node,
+ Ref<DriverTransport> transport,
+ IpczConnectNodeFlags flags,
+ std::vector<Ref<Portal>> waiting_portals,
+ ConnectCallback callback)
+ : NodeConnector(std::move(node),
+ std::move(transport),
+ flags,
+ std::move(waiting_portals),
+ std::move(callback)),
+ link_memory_allocation_(
+ NodeLinkMemory::AllocateMemory(node_->driver())) {
+ ABSL_ASSERT(link_memory_allocation_.mapping.is_valid());
+ }
+
+ ~NodeConnectorForBrokerToBroker() override = default;
+
+ // NodeConnector:
+ bool Connect() override {
+ DVLOG(4) << "Sending direct ConnectFromBrokerToBroker from broker "
+ << local_name_.ToString() << " with " << num_portals()
+ << " initial portals";
+
+ ABSL_ASSERT(node_->type() == Node::Type::kBroker);
+ msg::ConnectFromBrokerToBroker connect;
+ connect.params().name = local_name_;
+ connect.params().protocol_version = msg::kProtocolVersion;
+ connect.params().num_initial_portals =
+ checked_cast<uint32_t>(num_portals());
+ connect.params().buffer = connect.AppendDriverObject(
+ link_memory_allocation_.memory.TakeDriverObject());
+ return IPCZ_RESULT_OK == transport_->Transmit(connect);
+ }
+
+ // NodeMessageListener overrides:
+ bool OnConnectFromBrokerToBroker(
+ msg::ConnectFromBrokerToBroker& connect) override {
+ const NodeName& remote_name = connect.params().name;
+ DVLOG(4) << "Accepting ConnectFromBrokerToBroker on broker "
+ << local_name_.ToString() << " from other broker "
+ << remote_name.ToString();
+
+ const LinkSide this_side =
+ remote_name < local_name_ ? LinkSide::kA : LinkSide::kB;
+ DriverMemory their_memory(
+ connect.TakeDriverObject(connect.params().buffer));
+ if (!their_memory.is_valid()) {
+ return false;
+ }
+
+ DriverMemoryMapping primary_buffer_mapping =
+ this_side.is_side_a() ? std::move(link_memory_allocation_.mapping)
+ : their_memory.Map();
+ Ref<NodeLink> link = NodeLink::CreateActive(
+ node_, this_side, local_name_, remote_name, Node::Type::kBroker,
+ connect.params().protocol_version, transport_,
+ NodeLinkMemory::Create(node_, std::move(primary_buffer_mapping)));
+ AcceptConnection({.link = link, .broker = link},
+ connect.params().num_initial_portals);
+ return true;
+ }
+
+ private:
+ const NodeName local_name_{node_->GetAssignedName()};
+ DriverMemoryWithMapping link_memory_allocation_;
+};
+
std::pair<Ref<NodeConnector>, IpczResult> CreateConnector(
Ref<Node> node,
Ref<DriverTransport> transport,
@@ -404,9 +475,10 @@ std::pair<Ref<NodeConnector>, IpczResult> CreateConnector(
const bool inherit_broker = (flags & IPCZ_CONNECT_NODE_INHERIT_BROKER) != 0;
if (from_broker) {
if (to_broker) {
- // TODO: Implement broker-to-broker connections.
- ABSL_ASSERT(false);
- return {nullptr, IPCZ_RESULT_INVALID_ARGUMENT};
+ return {MakeRefCounted<NodeConnectorForBrokerToBroker>(
+ std::move(node), std::move(transport), flags, initial_portals,
+ std::move(callback)),
+ IPCZ_RESULT_OK};
}
return {MakeRefCounted<NodeConnectorForBrokerToNonBroker>(
@@ -511,21 +583,20 @@ NodeConnector::NodeConnector(Ref<Node> node,
NodeConnector::~NodeConnector() = default;
-void NodeConnector::AcceptConnection(Ref<NodeLink> new_link,
- LinkSide link_side,
+void NodeConnector::AcceptConnection(Node::Connection connection,
uint32_t num_remote_portals) {
- node_->AddLink(new_link->remote_node_name(), new_link);
+ node_->AddConnection(connection.link->remote_node_name(), connection);
if (callback_) {
- callback_(new_link);
+ callback_(connection.link);
}
- EstablishWaitingPortals(std::move(new_link), link_side, num_remote_portals);
+ EstablishWaitingPortals(connection.link, num_remote_portals);
}
void NodeConnector::RejectConnection() {
if (callback_) {
callback_(nullptr);
}
- EstablishWaitingPortals(nullptr, LinkSide::kA, 0);
+ EstablishWaitingPortals(nullptr, 0);
if (transport_) {
transport_->Deactivate();
}
@@ -541,28 +612,30 @@ bool NodeConnector::ActivateTransport() {
}
void NodeConnector::EstablishWaitingPortals(Ref<NodeLink> to_link,
- LinkSide link_side,
size_t max_valid_portals) {
+ // All paths to this function come from a transport notification.
+ const OperationContext context{OperationContext::kTransportNotification};
+
ABSL_ASSERT(to_link != nullptr || max_valid_portals == 0);
const size_t num_valid_portals =
std::min(max_valid_portals, waiting_portals_.size());
for (size_t i = 0; i < num_valid_portals; ++i) {
const Ref<Router> router = waiting_portals_[i]->router();
Ref<RouterLink> link = to_link->AddRemoteRouterLink(
- SublinkId(i), to_link->memory().GetInitialRouterLinkState(i),
- LinkType::kCentral, link_side, router);
+ context, SublinkId(i), to_link->memory().GetInitialRouterLinkState(i),
+ LinkType::kCentral, to_link->link_side(), router);
if (link) {
- router->SetOutwardLink(std::move(link));
+ router->SetOutwardLink(context, std::move(link));
} else {
- router->AcceptRouteDisconnectedFrom(LinkType::kCentral);
+ router->AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
}
}
// Elicit immediate peer closure on any surplus portals that were established
// on this side of the link.
for (size_t i = num_valid_portals; i < waiting_portals_.size(); ++i) {
- waiting_portals_[i]->router()->AcceptRouteClosureFrom(LinkType::kCentral,
- SequenceNumber(0));
+ waiting_portals_[i]->router()->AcceptRouteClosureFrom(
+ context, LinkType::kCentral, SequenceNumber(0));
}
}
diff --git a/chromium/third_party/ipcz/src/ipcz/node_connector.h b/chromium/third_party/ipcz/src/ipcz/node_connector.h
index d1379431927..96d3dc228b0 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_connector.h
+++ b/chromium/third_party/ipcz/src/ipcz/node_connector.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,13 +12,13 @@
#include "ipcz/driver_transport.h"
#include "ipcz/ipcz.h"
#include "ipcz/link_side.h"
+#include "ipcz/node.h"
#include "ipcz/node_messages.h"
#include "third_party/abseil-cpp/absl/types/span.h"
#include "util/ref_counted.h"
namespace ipcz {
-class Node;
class NodeLink;
class Portal;
@@ -73,11 +73,9 @@ class NodeConnector : public msg::NodeMessageListener {
size_t num_portals() const { return waiting_portals_.size(); }
- // Invoked once by the implementation when it has completed the handshake.
- // `new_link` has already assumed ownership of the underlying transport and
- // is listening for incoming messages on it. Destroys `this`.
- void AcceptConnection(Ref<NodeLink> new_link,
- LinkSide link_side,
+ // Invoked once by the implementation when it has completed its handshake.
+ // Destroys `this`.
+ void AcceptConnection(Node::Connection connection,
uint32_t num_remote_portals);
// Invoked if the transport observes an error before receiving the expected
@@ -95,9 +93,7 @@ class NodeConnector : public msg::NodeMessageListener {
private:
bool ActivateTransport();
- void EstablishWaitingPortals(Ref<NodeLink> to_link,
- LinkSide link_side,
- size_t max_valid_portals);
+ void EstablishWaitingPortals(Ref<NodeLink> to_link, size_t max_valid_portals);
const ConnectCallback callback_;
};
diff --git a/chromium/third_party/ipcz/src/ipcz/node_connector_test.cc b/chromium/third_party/ipcz/src/ipcz/node_connector_test.cc
index 7bd3fe7cc3a..1d822d6ffec 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_connector_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_connector_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/node_link.cc b/chromium/third_party/ipcz/src/ipcz/node_link.cc
index 1835fcc43a9..0fb03fe5835 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_link.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_link.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -22,6 +22,7 @@
#include "ipcz/node_connector.h"
#include "ipcz/node_link_memory.h"
#include "ipcz/node_messages.h"
+#include "ipcz/operation_context.h"
#include "ipcz/parcel.h"
#include "ipcz/portal.h"
#include "ipcz/remote_router_link.h"
@@ -123,12 +124,13 @@ void NodeLink::Activate() {
}
Ref<RemoteRouterLink> NodeLink::AddRemoteRouterLink(
+ const OperationContext& context,
SublinkId sublink,
FragmentRef<RouterLinkState> link_state,
LinkType type,
LinkSide side,
Ref<Router> router) {
- auto link = RemoteRouterLink::Create(WrapRefCounted(this), sublink,
+ auto link = RemoteRouterLink::Create(context, WrapRefCounted(this), sublink,
std::move(link_state), type, side);
absl::MutexLock lock(&mutex_);
@@ -191,6 +193,7 @@ void NodeLink::RequestIntroduction(const NodeName& name) {
void NodeLink::AcceptIntroduction(const NodeName& name,
LinkSide side,
+ Node::Type remote_node_type,
uint32_t remote_protocol_version,
Ref<DriverTransport> transport,
DriverMemory memory) {
@@ -199,6 +202,7 @@ void NodeLink::AcceptIntroduction(const NodeName& name,
msg::AcceptIntroduction accept;
accept.params().name = name;
accept.params().link_side = side;
+ accept.params().remote_node_type = remote_node_type;
accept.params().remote_protocol_version = remote_protocol_version;
accept.params().transport =
accept.AppendDriverObject(transport->TakeDriverObject());
@@ -318,7 +322,7 @@ bool NodeLink::DispatchRelayedMessage(msg::AcceptRelayedMessage& accept) {
}
}
-void NodeLink::Deactivate() {
+void NodeLink::Deactivate(const OperationContext& context) {
{
absl::MutexLock lock(&mutex_);
if (activation_state_ != kActive) {
@@ -327,7 +331,7 @@ void NodeLink::Deactivate() {
activation_state_ = kDeactivated;
}
- OnTransportError();
+ HandleTransportError(context);
transport_->Deactivate();
memory_->SetNodeLink(nullptr);
}
@@ -432,9 +436,7 @@ bool NodeLink::OnNonBrokerReferralRejected(
}
bool NodeLink::OnRequestIntroduction(msg::RequestIntroduction& request) {
- // TODO: Support broker-to-broker introduction requests.
- if (remote_node_type_ != Node::Type::kNormal ||
- node()->type() != Node::Type::kBroker) {
+ if (node()->type() != Node::Type::kBroker) {
return false;
}
@@ -447,11 +449,6 @@ bool NodeLink::OnAcceptIntroduction(msg::AcceptIntroduction& accept) {
return false;
}
- if (node()->type() != Node::Type::kNormal) {
- // TODO: Support broker-to-broker introductions.
- return false;
- }
-
auto memory = DriverMemory(accept.TakeDriverObject(accept.params().memory));
if (!memory.is_valid()) {
return false;
@@ -466,8 +463,8 @@ bool NodeLink::OnAcceptIntroduction(msg::AcceptIntroduction& accept) {
accept.TakeDriverObject(accept.params().transport));
node()->AcceptIntroduction(
*this, accept.params().name, accept.params().link_side,
- accept.params().remote_protocol_version, std::move(transport),
- NodeLinkMemory::Create(node(), std::move(mapping)));
+ accept.params().remote_node_type, accept.params().remote_protocol_version,
+ std::move(transport), NodeLinkMemory::Create(node(), std::move(mapping)));
return true;
}
@@ -476,12 +473,21 @@ bool NodeLink::OnRejectIntroduction(msg::RejectIntroduction& reject) {
return false;
}
- if (node()->type() != Node::Type::kNormal) {
- // TODO: Support broker-to-broker introductions.
+ node()->NotifyIntroductionFailed(*this, reject.params().name);
+ return true;
+}
+
+bool NodeLink::OnRequestIndirectIntroduction(
+ msg::RequestIndirectIntroduction& request) {
+ // By convention only a broker on side B of a broker-to-broker link will send
+ // this message, and so only side-A broker-to-broker links can receive it.
+ if (remote_node_type_ != Node::Type::kBroker ||
+ node()->type() != Node::Type::kBroker || !link_side_.is_side_a()) {
return false;
}
- return node()->CancelIntroduction(reject.params().name);
+ return node()->HandleIndirectIntroductionRequest(
+ *this, request.params().target_node, request.params().source_node);
}
bool NodeLink::OnAddBlockBuffer(msg::AddBlockBuffer& add) {
@@ -609,8 +615,10 @@ bool NodeLink::OnRouteClosed(msg::RouteClosed& route_closed) {
return true;
}
+ const OperationContext context{OperationContext::kTransportNotification};
return sublink->receiver->AcceptRouteClosureFrom(
- sublink->router_link->GetType(), route_closed.params().sequence_length);
+ context, sublink->router_link->GetType(),
+ route_closed.params().sequence_length);
}
bool NodeLink::OnRouteDisconnected(msg::RouteDisconnected& route_closed) {
@@ -622,13 +630,15 @@ bool NodeLink::OnRouteDisconnected(msg::RouteDisconnected& route_closed) {
DVLOG(4) << "Accepting RouteDisconnected at "
<< sublink->router_link->Describe();
+ const OperationContext context{OperationContext::kTransportNotification};
return sublink->receiver->AcceptRouteDisconnectedFrom(
- sublink->router_link->GetType());
+ context, sublink->router_link->GetType());
}
-bool NodeLink::OnNotifyDataConsumed(msg::NotifyDataConsumed& notify) {
- if (Ref<Router> router = GetRouter(notify.params().sublink)) {
- router->NotifyPeerConsumedData();
+bool NodeLink::OnSnapshotPeerQueueState(msg::SnapshotPeerQueueState& snapshot) {
+ const OperationContext context{OperationContext::kTransportNotification};
+ if (Ref<Router> router = GetRouter(snapshot.params().sublink)) {
+ router->SnapshotPeerQueueState(context);
}
return true;
}
@@ -641,7 +651,8 @@ bool NodeLink::OnBypassPeer(msg::BypassPeer& bypass) {
// NOTE: This request is authenticated by the receiving Router, within
// BypassPeer().
- return sublink->receiver->BypassPeer(*sublink->router_link,
+ const OperationContext context{OperationContext::kTransportNotification};
+ return sublink->receiver->BypassPeer(context, *sublink->router_link,
bypass.params().bypass_target_node,
bypass.params().bypass_target_sublink);
}
@@ -674,8 +685,9 @@ bool NodeLink::OnAcceptBypassLink(msg::AcceptBypassLink& accept) {
return false;
}
+ const OperationContext context{OperationContext::kTransportNotification};
return receiver->AcceptBypassLink(
- *this, accept.params().new_sublink, std::move(link_state),
+ context, *this, accept.params().new_sublink, std::move(link_state),
accept.params().inbound_sequence_length_from_bypassed_link);
}
@@ -685,7 +697,8 @@ bool NodeLink::OnStopProxying(msg::StopProxying& stop) {
return true;
}
- return router->StopProxying(stop.params().inbound_sequence_length,
+ const OperationContext context{OperationContext::kTransportNotification};
+ return router->StopProxying(context, stop.params().inbound_sequence_length,
stop.params().outbound_sequence_length);
}
@@ -695,8 +708,9 @@ bool NodeLink::OnProxyWillStop(msg::ProxyWillStop& will_stop) {
return true;
}
+ const OperationContext context{OperationContext::kTransportNotification};
return router->NotifyProxyWillStop(
- will_stop.params().inbound_sequence_length);
+ context, will_stop.params().inbound_sequence_length);
}
bool NodeLink::OnBypassPeerWithLink(msg::BypassPeerWithLink& bypass) {
@@ -710,7 +724,9 @@ bool NodeLink::OnBypassPeerWithLink(msg::BypassPeerWithLink& bypass) {
if (link_state.is_null()) {
return false;
}
- return router->AcceptBypassLink(*this, bypass.params().new_sublink,
+
+ const OperationContext context{OperationContext::kTransportNotification};
+ return router->AcceptBypassLink(context, *this, bypass.params().new_sublink,
std::move(link_state),
bypass.params().inbound_sequence_length);
}
@@ -721,13 +737,15 @@ bool NodeLink::OnStopProxyingToLocalPeer(msg::StopProxyingToLocalPeer& stop) {
return true;
}
+ const OperationContext context{OperationContext::kTransportNotification};
return router->StopProxyingToLocalPeer(
- stop.params().outbound_sequence_length);
+ context, stop.params().outbound_sequence_length);
}
bool NodeLink::OnFlushRouter(msg::FlushRouter& flush) {
if (Ref<Router> router = GetRouter(flush.params().sublink)) {
- router->Flush(Router::kForceProxyBypassAttempt);
+ const OperationContext context{OperationContext::kTransportNotification};
+ router->Flush(context, Router::kForceProxyBypassAttempt);
}
return true;
}
@@ -782,6 +800,11 @@ bool NodeLink::OnAcceptRelayedMessage(msg::AcceptRelayedMessage& accept) {
}
void NodeLink::OnTransportError() {
+ const OperationContext context{OperationContext::kTransportNotification};
+ HandleTransportError(context);
+}
+
+void NodeLink::HandleTransportError(const OperationContext& context) {
SublinkMap sublinks;
{
absl::MutexLock lock(&mutex_);
@@ -792,11 +815,11 @@ void NodeLink::OnTransportError() {
DVLOG(4) << "NodeLink disconnection dropping "
<< sublink.router_link->Describe() << " which is bound to router "
<< sublink.receiver.get();
- sublink.receiver->NotifyLinkDisconnected(*sublink.router_link);
+ sublink.receiver->NotifyLinkDisconnected(context, *sublink.router_link);
}
Ref<NodeLink> self = WrapRefCounted(this);
- node_->DropLink(remote_node_name_);
+ node_->DropConnection(context, remote_node_name_);
}
void NodeLink::WaitForParcelFragmentToResolve(
@@ -915,17 +938,20 @@ bool NodeLink::AcceptCompleteParcel(SublinkId for_sublink, Parcel& parcel) {
<< for_sublink;
return true;
}
+
+ const OperationContext context{OperationContext::kTransportNotification};
+ parcel.set_remote_source(WrapRefCounted(this));
const LinkType link_type = sublink->router_link->GetType();
if (link_type.is_outward()) {
DVLOG(4) << "Accepting inbound " << parcel.Describe() << " at "
<< sublink->router_link->Describe();
- return sublink->receiver->AcceptInboundParcel(parcel);
+ return sublink->receiver->AcceptInboundParcel(context, parcel);
}
ABSL_ASSERT(link_type.is_peripheral_inward());
DVLOG(4) << "Accepting outbound " << parcel.Describe() << " at "
<< sublink->router_link->Describe();
- return sublink->receiver->AcceptOutboundParcel(parcel);
+ return sublink->receiver->AcceptOutboundParcel(context, parcel);
}
NodeLink::Sublink::Sublink(Ref<RemoteRouterLink> router_link,
diff --git a/chromium/third_party/ipcz/src/ipcz/node_link.h b/chromium/third_party/ipcz/src/ipcz/node_link.h
index 2b9bf420906..fcd412ace5e 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_link.h
+++ b/chromium/third_party/ipcz/src/ipcz/node_link.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -103,6 +103,7 @@ class NodeLink : public msg::NodeMessageListener {
// shared RouterLinkState structure for the new link. Only central links
// require a RouterLinkState.
Ref<RemoteRouterLink> AddRemoteRouterLink(
+ const OperationContext& context,
SublinkId sublink,
FragmentRef<RouterLinkState> link_state,
LinkType type,
@@ -137,6 +138,7 @@ class NodeLink : public msg::NodeMessageListener {
// construct a new NodeLink to that node.
void AcceptIntroduction(const NodeName& name,
LinkSide side,
+ Node::Type remote_node_type,
uint32_t remote_protocol_version,
Ref<DriverTransport> transport,
DriverMemory memory);
@@ -199,7 +201,7 @@ class NodeLink : public msg::NodeMessageListener {
// Must only be called on an activated NodeLink, either one which was created
// with CreateActive(), or one which was activated later by calling
// Activate().
- void Deactivate();
+ void Deactivate(const OperationContext& context);
// Finalizes serialization of DriverObjects within `message` and transmits it
// to the NodeLink's peer, either over the DriverTransport or through shared
@@ -235,13 +237,15 @@ class NodeLink : public msg::NodeMessageListener {
bool OnRequestIntroduction(msg::RequestIntroduction& request) override;
bool OnAcceptIntroduction(msg::AcceptIntroduction& accept) override;
bool OnRejectIntroduction(msg::RejectIntroduction& reject) override;
+ bool OnRequestIndirectIntroduction(
+ msg::RequestIndirectIntroduction& request) override;
bool OnAddBlockBuffer(msg::AddBlockBuffer& add) override;
bool OnAcceptParcel(msg::AcceptParcel& accept) override;
bool OnAcceptParcelDriverObjects(
msg::AcceptParcelDriverObjects& accept) override;
bool OnRouteClosed(msg::RouteClosed& route_closed) override;
bool OnRouteDisconnected(msg::RouteDisconnected& route_disconnected) override;
- bool OnNotifyDataConsumed(msg::NotifyDataConsumed& notify) override;
+ bool OnSnapshotPeerQueueState(msg::SnapshotPeerQueueState& snapshot) override;
bool OnBypassPeer(msg::BypassPeer& bypass) override;
bool OnAcceptBypassLink(msg::AcceptBypassLink& accept) override;
bool OnStopProxying(msg::StopProxying& stop) override;
@@ -255,6 +259,8 @@ class NodeLink : public msg::NodeMessageListener {
bool OnAcceptRelayedMessage(msg::AcceptRelayedMessage& accept) override;
void OnTransportError() override;
+ void HandleTransportError(const OperationContext& context);
+
// Invoked when we receive a Parcel whose data fragment resides in a buffer
// not yet known to the local node. This schedules the parcel for acceptance
// as soon as that buffer is available.
diff --git a/chromium/third_party/ipcz/src/ipcz/node_link_memory.cc b/chromium/third_party/ipcz/src/ipcz/node_link_memory.cc
index 598cd7ad647..0cfadfa02aa 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_link_memory.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_link_memory.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -27,8 +27,8 @@ namespace {
constexpr BufferId kPrimaryBufferId{0};
-// Fixed allocation size for each NodeLink's primary shared buffer.
-constexpr size_t kPrimaryBufferSize = 64 * 1024;
+// Fixed allocation size for each NodeLink's primary shared buffer. (2 MB)
+constexpr size_t kPrimaryBufferSize = 2 * 1024 * 1024;
// The front of the primary buffer is reserved for special current and future
// uses which require synchronous availability throughout a link's lifetime.
@@ -49,7 +49,7 @@ constexpr size_t kMinBlockAllocatorCapacity = 8;
// given fragment size within the BufferPool. This is not a hard cap on capacity
// per fragment size, but it sets a limit on how large the pool will grow
// automatically in response to failed allocation requests.
-constexpr size_t kMaxBlockAllocatorCapacityPerFragmentSize = 256 * 1024;
+constexpr size_t kMaxBlockAllocatorCapacityPerFragmentSize = 2 * 1024 * 1024;
// The minimum fragment size (in bytes) to support with dedicated BufferPool
// capacity. All fragment sizes are powers of two. Fragment allocations below
@@ -59,7 +59,7 @@ constexpr size_t kMinFragmentSize = 64;
// The maximum fragment size to support with dedicated BlockAllocator capacity
// within the BufferPool. Allocations beyond this size must fail or fall back
// onto a different allocation scheme which does not use a BlockAllocator.
-constexpr size_t kMaxFragmentSizeForBlockAllocation = 16 * 1024;
+constexpr size_t kMaxFragmentSizeForBlockAllocation = 1024 * 1024;
// The minimum fallback fragment size to attempt for best-effort allocations
// when the requested size cannot be accommodated.
@@ -118,11 +118,15 @@ struct IPCZ_ALIGN(8) NodeLinkMemory::PrimaryBuffer {
// Reserved memory for a series of fixed block allocators. Additional
// allocators may be adopted by a NodeLinkMemory over its lifetime, but these
// ones remain fixed within the primary buffer.
- std::array<uint8_t, 4096> mem_for_64_byte_blocks;
- std::array<uint8_t, 12288> mem_for_256_byte_blocks;
- std::array<uint8_t, 15360> mem_for_512_byte_blocks;
- std::array<uint8_t, 11264> mem_for_1024_byte_blocks;
- std::array<uint8_t, 16384> mem_for_2048_byte_blocks;
+ std::array<uint8_t, 64 * 64> mem_for_64_byte_blocks;
+ std::array<uint8_t, 256 * 48> mem_for_256_byte_blocks;
+ std::array<uint8_t, 512 * 30> mem_for_512_byte_blocks;
+ std::array<uint8_t, 1024 * 11> mem_for_1k_blocks;
+ std::array<uint8_t, 2048 * 8> mem_for_2k_blocks;
+ std::array<uint8_t, 4096 * 16> mem_for_4k_blocks;
+ std::array<uint8_t, 16384 * 16> mem_for_16k_blocks;
+ std::array<uint8_t, 32768 * 8> mem_for_32k_blocks;
+ std::array<uint8_t, 65536 * 22> mem_for_64k_blocks;
BlockAllocator block_allocator_64() {
return BlockAllocator(absl::MakeSpan(mem_for_64_byte_blocks), 64);
@@ -136,12 +140,28 @@ struct IPCZ_ALIGN(8) NodeLinkMemory::PrimaryBuffer {
return BlockAllocator(absl::MakeSpan(mem_for_512_byte_blocks), 512);
}
- BlockAllocator block_allocator_1024() {
- return BlockAllocator(absl::MakeSpan(mem_for_1024_byte_blocks), 1024);
+ BlockAllocator block_allocator_1k() {
+ return BlockAllocator(absl::MakeSpan(mem_for_1k_blocks), 1024);
}
- BlockAllocator block_allocator_2048() {
- return BlockAllocator(absl::MakeSpan(mem_for_2048_byte_blocks), 2048);
+ BlockAllocator block_allocator_2k() {
+ return BlockAllocator(absl::MakeSpan(mem_for_2k_blocks), 2 * 1024);
+ }
+
+ BlockAllocator block_allocator_4k() {
+ return BlockAllocator(absl::MakeSpan(mem_for_4k_blocks), 4 * 1024);
+ }
+
+ BlockAllocator block_allocator_16k() {
+ return BlockAllocator(absl::MakeSpan(mem_for_16k_blocks), 16 * 1024);
+ }
+
+ BlockAllocator block_allocator_32k() {
+ return BlockAllocator(absl::MakeSpan(mem_for_32k_blocks), 32 * 1024);
+ }
+
+ BlockAllocator block_allocator_64k() {
+ return BlockAllocator(absl::MakeSpan(mem_for_64k_blocks), 64 * 1024);
}
};
@@ -160,8 +180,12 @@ NodeLinkMemory::NodeLinkMemory(Ref<Node> node,
primary_buffer_.block_allocator_64(),
primary_buffer_.block_allocator_256(),
primary_buffer_.block_allocator_512(),
- primary_buffer_.block_allocator_1024(),
- primary_buffer_.block_allocator_2048(),
+ primary_buffer_.block_allocator_1k(),
+ primary_buffer_.block_allocator_2k(),
+ primary_buffer_.block_allocator_4k(),
+ primary_buffer_.block_allocator_16k(),
+ primary_buffer_.block_allocator_32k(),
+ primary_buffer_.block_allocator_64k(),
};
buffer_pool_.AddBlockBuffer(kPrimaryBufferId,
@@ -219,8 +243,12 @@ DriverMemoryWithMapping NodeLinkMemory::AllocateMemory(
primary_buffer.block_allocator_64().InitializeRegion();
primary_buffer.block_allocator_256().InitializeRegion();
primary_buffer.block_allocator_512().InitializeRegion();
- primary_buffer.block_allocator_1024().InitializeRegion();
- primary_buffer.block_allocator_2048().InitializeRegion();
+ primary_buffer.block_allocator_1k().InitializeRegion();
+ primary_buffer.block_allocator_2k().InitializeRegion();
+ primary_buffer.block_allocator_4k().InitializeRegion();
+ primary_buffer.block_allocator_16k().InitializeRegion();
+ primary_buffer.block_allocator_32k().InitializeRegion();
+ primary_buffer.block_allocator_64k().InitializeRegion();
return {std::move(memory), std::move(mapping)};
}
diff --git a/chromium/third_party/ipcz/src/ipcz/node_link_memory.h b/chromium/third_party/ipcz/src/ipcz/node_link_memory.h
index 88a1c3927bc..1eb43cb6ac3 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_link_memory.h
+++ b/chromium/third_party/ipcz/src/ipcz/node_link_memory.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/node_link_memory_test.cc b/chromium/third_party/ipcz/src/ipcz/node_link_memory_test.cc
index d3707f3e7f1..44ba853fa60 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_link_memory_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_link_memory_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -44,8 +44,9 @@ class NodeLinkMemoryTest : public testing::Test {
node_b_, LinkSide::kB, kTestNonBrokerName, kTestBrokerName,
Node::Type::kBroker, 0, transports.second,
NodeLinkMemory::Create(node_b_, buffer.memory.Map()));
- node_a_->AddLink(kTestNonBrokerName, link_a_);
- node_b_->AddLink(kTestBrokerName, link_b_);
+ node_a_->AddConnection(kTestNonBrokerName, {.link = link_a_});
+ node_b_->AddConnection(kTestBrokerName,
+ {.link = link_b_, .broker = link_a_});
link_a_->Activate();
link_b_->Activate();
}
@@ -201,15 +202,15 @@ TEST_F(NodeLinkMemoryTest, OversizedAllocation) {
TEST_F(NodeLinkMemoryTest, NewBlockSizes) {
// NodeLinkMemory begins life with a fixed set of block allocators available
- // for certain common block sizes. These are capped out at 2 kB blocks, but
+ // for certain common block sizes. These are capped out at 64 kB blocks, but
// NodeLinkMemory still supports block allocation of larger blocks as well --
- // at least up to 16 kB in size. Verify that we can trigger new capacity for
+ // at least up to 1 MB in size. Verify that we can trigger new capacity for
// such sizes by attempting to allocate them.
- constexpr size_t kPrettyBig = 16 * 1024;
+ constexpr size_t kPrettyBig = 512 * 1024;
Fragment fragment = memory_a().AllocateFragment(kPrettyBig);
- // No initial capacity for 16 kB fragments.
+ // No initial capacity for 256 kB fragments.
EXPECT_TRUE(fragment.is_null());
// But the failure above should have triggered expansion of capacity for that
diff --git a/chromium/third_party/ipcz/src/ipcz/node_link_test.cc b/chromium/third_party/ipcz/src/ipcz/node_link_test.cc
index 26f6c6bf113..29c26eb5775 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_link_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_link_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include "ipcz/link_side.h"
#include "ipcz/link_type.h"
#include "ipcz/node_link_memory.h"
+#include "ipcz/operation_context.h"
#include "ipcz/remote_router_link.h"
#include "ipcz/router.h"
#include "ipcz/sublink_id.h"
@@ -61,15 +62,21 @@ TEST_F(NodeLinkTest, BasicTransmission) {
Ref<Node> node1 = MakeRefCounted<Node>(Node::Type::kNormal, kDriver,
IPCZ_INVALID_DRIVER_HANDLE);
+ // The choice of OperationContext is arbitrary and irrelevant for this test.
+ const OperationContext context{OperationContext::kTransportNotification};
auto [link0, link1] = LinkNodes(node0, node1);
auto router0 = MakeRefCounted<Router>();
auto router1 = MakeRefCounted<Router>();
FragmentRef<RouterLinkState> link_state =
link0->memory().GetInitialRouterLinkState(0);
- router0->SetOutwardLink(link0->AddRemoteRouterLink(
- SublinkId(0), link_state, LinkType::kCentral, LinkSide::kA, router0));
- router1->SetOutwardLink(link1->AddRemoteRouterLink(
- SublinkId(0), link_state, LinkType::kCentral, LinkSide::kB, router1));
+ router0->SetOutwardLink(
+ context,
+ link0->AddRemoteRouterLink(context, SublinkId(0), link_state,
+ LinkType::kCentral, LinkSide::kA, router0));
+ router1->SetOutwardLink(
+ context,
+ link1->AddRemoteRouterLink(context, SublinkId(0), link_state,
+ LinkType::kCentral, LinkSide::kB, router1));
link_state->status = RouterLinkState::kStable;
EXPECT_FALSE(router1->IsPeerClosed());
@@ -77,8 +84,8 @@ TEST_F(NodeLinkTest, BasicTransmission) {
EXPECT_TRUE(router1->IsPeerClosed());
router1->CloseRoute();
- link0->Deactivate();
- link1->Deactivate();
+ link0->Deactivate(context);
+ link1->Deactivate(context);
}
} // namespace
diff --git a/chromium/third_party/ipcz/src/ipcz/node_messages.cc b/chromium/third_party/ipcz/src/ipcz/node_messages.cc
index 5396bb442cf..9941643a479 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_messages.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_messages.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/node_messages.h b/chromium/third_party/ipcz/src/ipcz/node_messages.h
index ed92d7a389c..790502e3e07 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_messages.h
+++ b/chromium/third_party/ipcz/src/ipcz/node_messages.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,6 +14,7 @@
#include "ipcz/link_side.h"
#include "ipcz/message.h"
#include "ipcz/node_name.h"
+#include "ipcz/node_type.h"
#include "ipcz/router_descriptor.h"
#include "ipcz/sequence_number.h"
#include "ipcz/sublink_id.h"
diff --git a/chromium/third_party/ipcz/src/ipcz/node_messages_generator.h b/chromium/third_party/ipcz/src/ipcz/node_messages_generator.h
index 65bc189a868..3d553baefb4 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_messages_generator.h
+++ b/chromium/third_party/ipcz/src/ipcz/node_messages_generator.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -183,11 +183,37 @@ IPCZ_MSG_BEGIN(NonBrokerReferralRejected, IPCZ_MSG_ID(6), IPCZ_MSG_VERSION(0))
IPCZ_MSG_PARAM(uint64_t, referral_id)
IPCZ_MSG_END()
-// Sent by a non-broker node to a broker node, asking the broker to introduce
-// the non-broker to the node identified by `name`. If the broker is willing and
-// able to comply with this request, it will send an AcceptIntroduction message
-// (see below) to both the sender of this message and the node identified by
-// `name`.
+// Sent from one broker to another to establish an initial link between two
+// distinct node networks. Once two brokers are connected their networks are
+// effectively merged and nodes in either network can become interconnected by
+// ipcz.
+IPCZ_MSG_BEGIN(ConnectFromBrokerToBroker, IPCZ_MSG_ID(7), IPCZ_MSG_VERSION(0))
+ // The name of the sending node.
+ IPCZ_MSG_PARAM(NodeName, name)
+
+ // The highest protocol version known and desired by the sending broker.
+ IPCZ_MSG_PARAM(uint32_t, protocol_version)
+
+ // The number of initial portals assumed by the sending broker on its end of
+ // the link established by this handshake.
+ IPCZ_MSG_PARAM(uint32_t, num_initial_portals)
+
+ // A primary buffer memory object which may be used to establish a
+ // NodeLinkMemory between the two brokers. Since each broker sends a memory
+ // object during this handshake, the one to use for the primary buffer is
+ // determined by whichever broker's name is the lesser of the two when
+ // compared numerically.
+ IPCZ_MSG_PARAM_DRIVER_OBJECT(buffer)
+IPCZ_MSG_END()
+
+// Sent to a broker to ask for an introduction to one of the non-broker nodes in
+// its own network. This may be sent either from a non-broker in the same
+// network, or a broker from another network.
+//
+// The non-broker to be introduced to the sender is identified by `name`. If the
+// broker is willing and able to comply with this request, it will send an
+// AcceptIntroduction message (see below) to both the sender of this message and
+// the node identified by `name`.
//
// If the broker does not know the node named `name`, it will send only a
// RejectIntroduction message back to the sender to indicate failure.
@@ -205,6 +231,9 @@ IPCZ_MSG_BEGIN(AcceptIntroduction, IPCZ_MSG_ID(11), IPCZ_MSG_VERSION(0))
// for the NodeLink it will establish over `transport`.
IPCZ_MSG_PARAM(LinkSide, link_side)
+ // Indicates the type of the remote node being introduced.
+ IPCZ_MSG_PARAM(NodeType, remote_node_type)
+
// Indicates the highest ipcz protocol version which the remote side of
// `transport` able and willing to use according to the broker.
IPCZ_MSG_PARAM(uint32_t, remote_protocol_version)
@@ -220,13 +249,27 @@ IPCZ_MSG_BEGIN(AcceptIntroduction, IPCZ_MSG_ID(11), IPCZ_MSG_VERSION(0))
IPCZ_MSG_PARAM_DRIVER_OBJECT(memory)
IPCZ_MSG_END()
-// Sent back to a non-broker if the broker did not recognzie the subject of an
-// introduction request.
+// Sent to a node in response to RequestIntroduction if the broker receiving
+// that message did not recognize or otherwise could not introduce the requested
+// node.
IPCZ_MSG_BEGIN(RejectIntroduction, IPCZ_MSG_ID(12), IPCZ_MSG_VERSION(0))
// The name of the node whose introduction cannot be fulfilled.
IPCZ_MSG_PARAM(NodeName, name)
IPCZ_MSG_END()
+// Sent from a broker to another broker to request that the receiving broker
+// introduce a named node in its own network to a named node in the sender's
+// network.
+IPCZ_MSG_BEGIN(RequestIndirectIntroduction,
+ IPCZ_MSG_ID(13),
+ IPCZ_MSG_VERSION(0))
+ // The name of the node to be introduced on the sender's own network.
+ IPCZ_MSG_PARAM(NodeName, source_node)
+
+ // The name of the node to be introduced on the recipient's own network.
+ IPCZ_MSG_PARAM(NodeName, target_node)
+IPCZ_MSG_END()
+
// Shares a new buffer to support allocation of blocks of `block_size` bytes.
// The sender must initialize an appropriate BlockAllocator within the buffer's
// memory before sending this message.
@@ -323,9 +366,9 @@ IPCZ_MSG_BEGIN(RouteDisconnected, IPCZ_MSG_ID(23), IPCZ_MSG_VERSION(0))
IPCZ_MSG_PARAM(SublinkId, sublink)
IPCZ_MSG_END()
-// Notifies a Router that the other side of its route has consumed some parcels
-// or parcel data from its inbound queue.
-IPCZ_MSG_BEGIN(NotifyDataConsumed, IPCZ_MSG_ID(24), IPCZ_MSG_VERSION(0))
+// Notifies a router that it may be interested in a recent change to its outward
+// peer's visible queue state.
+IPCZ_MSG_BEGIN(SnapshotPeerQueueState, IPCZ_MSG_ID(24), IPCZ_MSG_VERSION(0))
// Identifies the router to receive this message.
IPCZ_MSG_PARAM(SublinkId, sublink)
IPCZ_MSG_END()
diff --git a/chromium/third_party/ipcz/src/ipcz/node_name.cc b/chromium/third_party/ipcz/src/ipcz/node_name.cc
index d89aff365bf..f7aedb34bf9 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_name.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_name.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/node_name.h b/chromium/third_party/ipcz/src/ipcz/node_name.h
index 0b9fda9aff7..d2bd6ac4dc2 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_name.h
+++ b/chromium/third_party/ipcz/src/ipcz/node_name.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/node_test.cc b/chromium/third_party/ipcz/src/ipcz/node_test.cc
index eae23ac4d77..20ebb841559 100644
--- a/chromium/third_party/ipcz/src/ipcz/node_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/node_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -58,9 +58,8 @@ class NodeTest : public testing::Test {
node, LinkSide::kB, name, broker_name, Node::Type::kBroker, 0,
transports.second, NodeLinkMemory::Create(node, buffer.memory.Map()));
node->SetAssignedName(name);
- broker_->AddLink(name, broker_link);
- node->AddLink(broker_name, node_link);
- node->SetBrokerLink(node_link);
+ broker_->AddConnection(name, {.link = broker_link});
+ node->AddConnection(broker_name, {.link = node_link, .broker = node_link});
broker_link->Activate();
node_link->Activate();
}
diff --git a/chromium/third_party/ipcz/src/ipcz/node_type.h b/chromium/third_party/ipcz/src/ipcz/node_type.h
new file mode 100644
index 00000000000..8d245b84039
--- /dev/null
+++ b/chromium/third_party/ipcz/src/ipcz/node_type.h
@@ -0,0 +1,30 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPCZ_SRC_IPCZ_NODE_TYPE_H_
+#define IPCZ_SRC_IPCZ_NODE_TYPE_H_
+
+#include <cstdint>
+
+namespace ipcz {
+
+// Enumeration indicating the role a Node plays in its network of nodes. Note
+// that this is used by internal wire messages, so values must not be changed or
+// removed.
+enum class NodeType : uint8_t {
+ // A broker node assigns its own name and is able to assign names to other
+ // nodes upon connection. Brokers are trusted to introduce nodes to each
+ // other upon request, and brokers may connect to other brokers in order to
+ // share information and effectively bridge two node networks together.
+ kBroker,
+
+ // A "normal" (i.e. non-broker) node is assigned a permanent name by the
+ // first broker node it connects to, and it can only make contact with other
+ // nodes by requesting an introduction from that broker.
+ kNormal,
+};
+
+} // namespace ipcz
+
+#endif // IPCZ_SRC_IPCZ_NODE_TYPE_H_
diff --git a/chromium/third_party/ipcz/src/ipcz/operation_context.h b/chromium/third_party/ipcz/src/ipcz/operation_context.h
new file mode 100644
index 00000000000..0d6c0bac607
--- /dev/null
+++ b/chromium/third_party/ipcz/src/ipcz/operation_context.h
@@ -0,0 +1,46 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPCZ_SRC_IPCZ_OPERATION_CONTEXT_H_
+#define IPCZ_SRC_IPCZ_OPERATION_CONTEXT_H_
+
+namespace ipcz {
+
+// Structure to capture any relevant context regarding an ongoing ipcz
+// operation. This is plumbed throughout methods on Router and other related
+// objects as needed to provide context for any events emitted by ipcz.
+struct OperationContext {
+ // Indicates the nature of the innermost entry point into ipcz for the current
+ // call stack. For any call stack within ipcz which propagates an
+ // OperationContext, the correct EntryPoint can be deduced by walking up the
+ // stack until hitting either an API entry point (i.e. an explicit IpczAPI
+ // function invocation) OR a driver transport notification (i.e. an
+ // IpczTransportActivityHandler invocation.)
+ enum class EntryPoint {
+ // The current innermost stack frame entering ipcz is a direct IpczAPI call.
+ kAPICall,
+
+ // The current innermost stack frame entering ipcz is a driver transport
+ // activity notification.
+ kTransportNotification,
+ };
+
+ static constexpr EntryPoint kAPICall = EntryPoint::kAPICall;
+ static constexpr EntryPoint kTransportNotification =
+ EntryPoint::kTransportNotification;
+
+ explicit OperationContext(EntryPoint entry_point)
+ : entry_point_(entry_point) {}
+ OperationContext(const OperationContext&) = default;
+ OperationContext& operator=(const OperationContext&) = default;
+
+ bool is_api_call() const { return entry_point_ == kAPICall; }
+
+ private:
+ EntryPoint entry_point_;
+};
+
+} // namespace ipcz
+
+#endif // IPCZ_SRC_IPCZ_OPERATION_CONTEXT_H_
diff --git a/chromium/third_party/ipcz/src/ipcz/parcel.cc b/chromium/third_party/ipcz/src/ipcz/parcel.cc
index f5a62390b35..fa8ed8eb858 100644
--- a/chromium/third_party/ipcz/src/ipcz/parcel.cc
+++ b/chromium/third_party/ipcz/src/ipcz/parcel.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
#include <string>
#include <utility>
+#include "ipcz/node_link.h"
#include "ipcz/node_link_memory.h"
#include "third_party/abseil-cpp/absl/base/macros.h"
#include "third_party/abseil-cpp/absl/types/span.h"
@@ -26,6 +27,7 @@ Parcel::Parcel(SequenceNumber sequence_number)
// to explicitly clear the data and object views of the moved-from Parcel.
Parcel::Parcel(Parcel&& other)
: sequence_number_(other.sequence_number_),
+ remote_source_(std::move(other.remote_source_)),
inlined_data_(std::move(other.inlined_data_)),
data_fragment_(std::exchange(other.data_fragment_, {})),
data_fragment_memory_(
@@ -36,6 +38,7 @@ Parcel::Parcel(Parcel&& other)
Parcel& Parcel::operator=(Parcel&& other) {
sequence_number_ = other.sequence_number_;
+ remote_source_ = std::move(other.remote_source_);
inlined_data_ = std::move(other.inlined_data_);
data_fragment_ = std::exchange(other.data_fragment_, {});
data_fragment_memory_ = std::move(other.data_fragment_memory_);
@@ -72,7 +75,7 @@ void Parcel::AllocateData(size_t num_bytes,
ABSL_ASSERT(data_view_.empty());
Fragment fragment;
- if (memory) {
+ if (memory && num_bytes > 0) {
const size_t requested_fragment_size = num_bytes + sizeof(FragmentHeader);
if (allow_partial) {
fragment = memory->AllocateFragmentBestEffort(requested_fragment_size);
diff --git a/chromium/third_party/ipcz/src/ipcz/parcel.h b/chromium/third_party/ipcz/src/ipcz/parcel.h
index 6281efa3adf..20fe1ec5358 100644
--- a/chromium/third_party/ipcz/src/ipcz/parcel.h
+++ b/chromium/third_party/ipcz/src/ipcz/parcel.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -21,6 +21,7 @@
namespace ipcz {
+class NodeLink;
class NodeLinkMemory;
// Represents a parcel queued within a portal, either for inbound retrieval or
@@ -64,6 +65,11 @@ class Parcel {
// this returns false.
bool AdoptDataFragment(Ref<NodeLinkMemory> memory, const Fragment& fragment);
+ void set_remote_source(Ref<NodeLink> source) {
+ remote_source_ = std::move(source);
+ }
+ const Ref<NodeLink>& remote_source() const { return remote_source_; }
+
absl::Span<uint8_t> data_view() { return data_view_; }
absl::Span<const uint8_t> data_view() const { return data_view_; }
@@ -123,6 +129,10 @@ class Parcel {
SequenceNumber sequence_number_{0};
+ // If this Parcel was received from a remote node, this tracks the NodeLink
+ // which received it.
+ Ref<NodeLink> remote_source_;
+
// A copy of the parcel's data, owned by the Parcel itself. Used only if
// `data_fragment_` is null.
std::vector<uint8_t> inlined_data_;
diff --git a/chromium/third_party/ipcz/src/ipcz/parcel_queue.cc b/chromium/third_party/ipcz/src/ipcz/parcel_queue.cc
index 8ddaedceba6..3f8b0874585 100644
--- a/chromium/third_party/ipcz/src/ipcz/parcel_queue.cc
+++ b/chromium/third_party/ipcz/src/ipcz/parcel_queue.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,7 +16,7 @@ bool ParcelQueue::Consume(size_t num_bytes_consumed,
ABSL_ASSERT(p.data_size() >= num_bytes_consumed);
ABSL_ASSERT(p.num_objects() >= handles.size());
p.Consume(num_bytes_consumed, handles);
- ReduceNextElementSize(num_bytes_consumed);
+ PartiallyConsumeNextElement(num_bytes_consumed);
if (p.empty()) {
Parcel discarded;
const bool ok = Pop(discarded);
diff --git a/chromium/third_party/ipcz/src/ipcz/parcel_queue.h b/chromium/third_party/ipcz/src/ipcz/parcel_queue.h
index c531978005a..d4a26718da2 100644
--- a/chromium/third_party/ipcz/src/ipcz/parcel_queue.h
+++ b/chromium/third_party/ipcz/src/ipcz/parcel_queue.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/parcel_queue_test.cc b/chromium/third_party/ipcz/src/ipcz/parcel_queue_test.cc
index 3f65e932d24..5c5651019ae 100644
--- a/chromium/third_party/ipcz/src/ipcz/parcel_queue_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/parcel_queue_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/portal.cc b/chromium/third_party/ipcz/src/ipcz/portal.cc
index ce4268ded92..fd8d645078f 100644
--- a/chromium/third_party/ipcz/src/ipcz/portal.cc
+++ b/chromium/third_party/ipcz/src/ipcz/portal.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include "ipcz/api_object.h"
#include "ipcz/local_router_link.h"
+#include "ipcz/operation_context.h"
#include "ipcz/router.h"
#include "third_party/abseil-cpp/absl/types/span.h"
#include "util/log.h"
@@ -47,10 +48,11 @@ Portal::Pair Portal::CreatePair(Ref<Node> node) {
DVLOG(5) << "Created new portal pair with routers " << routers.first.get()
<< " and " << routers.second.get();
+ const OperationContext context{OperationContext::kAPICall};
auto links = LocalRouterLink::CreatePair(LinkType::kCentral, routers,
LocalRouterLink::kStable);
- routers.first->SetOutwardLink(std::move(links.first));
- routers.second->SetOutwardLink(std::move(links.second));
+ routers.first->SetOutwardLink(context, std::move(links.first));
+ routers.second->SetOutwardLink(context, std::move(links.second));
return {MakeRefCounted<Portal>(node, std::move(routers.first)),
MakeRefCounted<Portal>(node, std::move(routers.second))};
}
@@ -146,7 +148,7 @@ IpczResult Portal::BeginPut(IpczBeginPutFlags flags,
num_data_bytes = pending_parcel_->data_view().size();
if (data) {
- *data = pending_parcel_->data_view().data();
+ *data = num_data_bytes ? pending_parcel_->data_view().data() : nullptr;
}
return IPCZ_RESULT_OK;
}
@@ -207,9 +209,10 @@ IpczResult Portal::Get(IpczGetFlags flags,
void* data,
size_t* num_data_bytes,
IpczHandle* handles,
- size_t* num_handles) {
+ size_t* num_handles,
+ IpczHandle* validator) {
return router_->GetNextInboundParcel(flags, data, num_data_bytes, handles,
- num_handles);
+ num_handles, validator);
}
IpczResult Portal::BeginGet(const void** data,
@@ -233,14 +236,15 @@ IpczResult Portal::BeginGet(const void** data,
}
IpczResult Portal::CommitGet(size_t num_data_bytes_consumed,
- absl::Span<IpczHandle> handles) {
+ absl::Span<IpczHandle> handles,
+ IpczHandle* validator) {
absl::MutexLock lock(&mutex_);
if (!in_two_phase_get_) {
return IPCZ_RESULT_FAILED_PRECONDITION;
}
- IpczResult result =
- router_->CommitGetNextIncomingParcel(num_data_bytes_consumed, handles);
+ IpczResult result = router_->CommitGetNextIncomingParcel(
+ num_data_bytes_consumed, handles, validator);
if (result == IPCZ_RESULT_OK) {
in_two_phase_get_ = false;
}
diff --git a/chromium/third_party/ipcz/src/ipcz/portal.h b/chromium/third_party/ipcz/src/ipcz/portal.h
index a2662cc13ab..e646cad6727 100644
--- a/chromium/third_party/ipcz/src/ipcz/portal.h
+++ b/chromium/third_party/ipcz/src/ipcz/portal.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -61,12 +61,14 @@ class Portal : public APIObjectImpl<Portal, APIObject::kPortal> {
void* data,
size_t* num_data_bytes,
IpczHandle* handles,
- size_t* num_handles);
+ size_t* num_handles,
+ IpczHandle* validator);
IpczResult BeginGet(const void** data,
size_t* num_data_bytes,
size_t* num_handles);
IpczResult CommitGet(size_t num_data_bytes_consumed,
- absl::Span<IpczHandle> handles);
+ absl::Span<IpczHandle> handles,
+ IpczHandle* validator);
IpczResult AbortGet();
private:
diff --git a/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.cc b/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.cc
index cd4a2af315f..fa17e5db176 100644
--- a/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.cc
+++ b/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.h b/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.h
index 09c01f374c9..7238debb903 100644
--- a/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.h
+++ b/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc b/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
index ed33e61dc62..d5a2243a693 100644
--- a/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/remote_router_link.cc b/chromium/third_party/ipcz/src/ipcz/remote_router_link.cc
index ac468619666..a2dbc961d6c 100644
--- a/chromium/third_party/ipcz/src/ipcz/remote_router_link.cc
+++ b/chromium/third_party/ipcz/src/ipcz/remote_router_link.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -19,7 +19,8 @@
namespace ipcz {
-RemoteRouterLink::RemoteRouterLink(Ref<NodeLink> node_link,
+RemoteRouterLink::RemoteRouterLink(const OperationContext& context,
+ Ref<NodeLink> node_link,
SublinkId sublink,
FragmentRef<RouterLinkState> link_state,
LinkType type,
@@ -33,7 +34,7 @@ RemoteRouterLink::RemoteRouterLink(Ref<NodeLink> node_link,
ABSL_ASSERT(type.is_central() == !link_state.is_null());
if (type.is_central()) {
- SetLinkState(std::move(link_state));
+ SetLinkState(context, std::move(link_state));
}
}
@@ -41,16 +42,18 @@ RemoteRouterLink::~RemoteRouterLink() = default;
// static
Ref<RemoteRouterLink> RemoteRouterLink::Create(
+ const OperationContext& context,
Ref<NodeLink> node_link,
SublinkId sublink,
FragmentRef<RouterLinkState> link_state,
LinkType type,
LinkSide side) {
- return AdoptRef(new RemoteRouterLink(std::move(node_link), sublink,
+ return AdoptRef(new RemoteRouterLink(context, std::move(node_link), sublink,
std::move(link_state), type, side));
}
-void RemoteRouterLink::SetLinkState(FragmentRef<RouterLinkState> state) {
+void RemoteRouterLink::SetLinkState(const OperationContext& context,
+ FragmentRef<RouterLinkState> state) {
ABSL_ASSERT(type_.is_central());
ABSL_ASSERT(!state.is_null());
@@ -60,9 +63,9 @@ void RemoteRouterLink::SetLinkState(FragmentRef<RouterLinkState> state) {
FragmentDescriptor descriptor = state.fragment().descriptor();
memory->WaitForBufferAsync(
descriptor.buffer_id(),
- [self = WrapRefCounted(this), memory, descriptor] {
- self->SetLinkState(memory->AdoptFragmentRef<RouterLinkState>(
- memory->GetFragment(descriptor)));
+ [self = WrapRefCounted(this), memory, descriptor, context] {
+ self->SetLinkState(context, memory->AdoptFragmentRef<RouterLinkState>(
+ memory->GetFragment(descriptor)));
});
return;
}
@@ -72,10 +75,19 @@ void RemoteRouterLink::SetLinkState(FragmentRef<RouterLinkState> state) {
// SetLinkState() must be called with an addressable fragment only once.
ABSL_ASSERT(link_state_.load(std::memory_order_acquire) == nullptr);
- // The release when storing `link_state_` is balanced by an acquire in
- // GetLinkState().
link_state_fragment_ = std::move(state);
- link_state_.store(link_state_fragment_.get(), std::memory_order_release);
+
+ std::vector<std::function<void()>> callbacks;
+ {
+ absl::MutexLock lock(&mutex_);
+ // This store-release is balanced by a load-acquire in GetLinkState().
+ link_state_.store(link_state_fragment_.get(), std::memory_order_release);
+ link_state_callbacks_.swap(callbacks);
+ }
+
+ for (auto& callback : callbacks) {
+ callback();
+ }
// If this side of the link was already marked stable before the
// RouterLinkState was available, `side_is_stable_` will be true. In that
@@ -86,7 +98,7 @@ void RemoteRouterLink::SetLinkState(FragmentRef<RouterLinkState> state) {
MarkSideStable();
}
if (Ref<Router> router = node_link()->GetRouter(sublink_)) {
- router->Flush(Router::kForceProxyBypassAttempt);
+ router->Flush(context, Router::kForceProxyBypassAttempt);
}
}
@@ -98,6 +110,18 @@ RouterLinkState* RemoteRouterLink::GetLinkState() const {
return link_state_.load(std::memory_order_acquire);
}
+void RemoteRouterLink::WaitForLinkStateAsync(std::function<void()> callback) {
+ {
+ absl::MutexLock lock(&mutex_);
+ if (!link_state_.load(std::memory_order_relaxed)) {
+ link_state_callbacks_.push_back(std::move(callback));
+ return;
+ }
+ }
+
+ callback();
+}
+
Ref<Router> RemoteRouterLink::GetLocalPeer() {
return nullptr;
}
@@ -112,7 +136,8 @@ void RemoteRouterLink::AllocateParcelData(size_t num_bytes,
parcel.AllocateData(num_bytes, allow_partial, &node_link()->memory());
}
-void RemoteRouterLink::AcceptParcel(Parcel& parcel) {
+void RemoteRouterLink::AcceptParcel(const OperationContext& context,
+ Parcel& parcel) {
const absl::Span<Ref<APIObject>> objects = parcel.objects_view();
msg::AcceptParcel accept;
@@ -195,7 +220,14 @@ void RemoteRouterLink::AcceptParcel(Parcel& parcel) {
// Serialize attached objects. We accumulate the Routers of all attached
// portals, because we need to reference them again after transmission, with
// a 1:1 correspondence to the serialized RouterDescriptors.
- absl::InlinedVector<Ref<Router>, 4> routers_to_proxy;
+ absl::InlinedVector<Ref<Router>, 4> routers_to_proxy(num_portals);
+ absl::InlinedVector<RouterDescriptor, 4> descriptors(num_portals);
+
+ // Explicitly zero the descriptor memory since there may be padding bits
+ // within and we'll be copying the full contents into message data below.
+ memset(descriptors.data(), 0, descriptors.size() * sizeof(descriptors[0]));
+
+ size_t portal_index = 0;
for (size_t i = 0; i < objects.size(); ++i) {
APIObject& object = *objects[i];
@@ -204,8 +236,11 @@ void RemoteRouterLink::AcceptParcel(Parcel& parcel) {
handle_types[i] = HandleType::kPortal;
Ref<Router> router = Portal::FromObject(&object)->router();
- router->SerializeNewRouter(*node_link(), new_routers[i]);
- routers_to_proxy.push_back(std::move(router));
+ ABSL_ASSERT(portal_index < num_portals);
+ router->SerializeNewRouter(context, *node_link(),
+ descriptors[portal_index]);
+ routers_to_proxy[portal_index] = std::move(router);
+ ++portal_index;
break;
}
@@ -220,6 +255,11 @@ void RemoteRouterLink::AcceptParcel(Parcel& parcel) {
}
}
+ // Copy all the serialized router descriptors into the message. Our local
+ // copy will supply inputs for BeginProxyingToNewRouter() calls below.
+ memcpy(new_routers.data(), descriptors.data(),
+ new_routers.size() * sizeof(new_routers[0]));
+
if (must_split_parcel) {
msg::AcceptParcelDriverObjects accept_objects;
accept_objects.params().sublink = sublink_;
@@ -241,9 +281,10 @@ void RemoteRouterLink::AcceptParcel(Parcel& parcel) {
// Now that the parcel has been transmitted, it's safe to start proxying from
// any routers whose routes have just been extended to the destination.
- ABSL_ASSERT(routers_to_proxy.size() == new_routers.size());
+ ABSL_ASSERT(routers_to_proxy.size() == descriptors.size());
for (size_t i = 0; i < routers_to_proxy.size(); ++i) {
- routers_to_proxy[i]->BeginProxyingToNewRouter(*node_link(), new_routers[i]);
+ routers_to_proxy[i]->BeginProxyingToNewRouter(context, *node_link(),
+ descriptors[i]);
}
// Finally, a Parcel will normally close all attached objects when destroyed.
@@ -254,60 +295,36 @@ void RemoteRouterLink::AcceptParcel(Parcel& parcel) {
}
}
-void RemoteRouterLink::AcceptRouteClosure(SequenceNumber sequence_length) {
+void RemoteRouterLink::AcceptRouteClosure(const OperationContext& context,
+ SequenceNumber sequence_length) {
msg::RouteClosed route_closed;
route_closed.params().sublink = sublink_;
route_closed.params().sequence_length = sequence_length;
node_link()->Transmit(route_closed);
}
-size_t RemoteRouterLink::GetParcelCapacityInBytes(const IpczPutLimits& limits) {
- if (limits.max_queued_bytes == 0 || limits.max_queued_parcels == 0) {
- return 0;
- }
-
- RouterLinkState* state = GetLinkState();
- if (!state) {
- // This is only a best-effort estimate. With no link state yet, err on the
- // side of more data flow.
- return limits.max_queued_bytes;
- }
-
- const RouterLinkState::QueueState peer_queue =
- state->GetQueueState(side_.opposite());
- if (peer_queue.num_parcels >= limits.max_queued_parcels ||
- peer_queue.num_bytes >= limits.max_queued_bytes) {
- return 0;
+AtomicQueueState* RemoteRouterLink::GetPeerQueueState() {
+ if (auto* state = GetLinkState()) {
+ return &state->GetQueueState(side_.opposite());
}
-
- return limits.max_queued_bytes - peer_queue.num_bytes;
+ return nullptr;
}
-RouterLinkState::QueueState RemoteRouterLink::GetPeerQueueState() {
+AtomicQueueState* RemoteRouterLink::GetLocalQueueState() {
if (auto* state = GetLinkState()) {
- return state->GetQueueState(side_.opposite());
+ return &state->GetQueueState(side_);
}
- return {.num_parcels = 0, .num_bytes = 0};
-}
-
-bool RemoteRouterLink::UpdateInboundQueueState(size_t num_parcels,
- size_t num_bytes) {
- RouterLinkState* state = GetLinkState();
- return state && state->UpdateQueueState(side_, num_parcels, num_bytes);
-}
-
-void RemoteRouterLink::NotifyDataConsumed() {
- msg::NotifyDataConsumed notify;
- notify.params().sublink = sublink_;
- node_link()->Transmit(notify);
+ return nullptr;
}
-bool RemoteRouterLink::EnablePeerMonitoring(bool enable) {
- RouterLinkState* state = GetLinkState();
- return state && state->SetSideIsMonitoringPeer(side_, enable);
+void RemoteRouterLink::SnapshotPeerQueueState(const OperationContext& context) {
+ msg::SnapshotPeerQueueState snapshot;
+ snapshot.params().sublink = sublink_;
+ node_link()->Transmit(snapshot);
}
-void RemoteRouterLink::AcceptRouteDisconnected() {
+void RemoteRouterLink::AcceptRouteDisconnected(
+ const OperationContext& context) {
msg::RouteDisconnected route_disconnected;
route_disconnected.params().sublink = sublink_;
node_link()->Transmit(route_disconnected);
@@ -341,7 +358,8 @@ void RemoteRouterLink::Unlock() {
}
}
-bool RemoteRouterLink::FlushOtherSideIfWaiting() {
+bool RemoteRouterLink::FlushOtherSideIfWaiting(
+ const OperationContext& context) {
RouterLinkState* state = GetLinkState();
if (!state || !state->ResetWaitingBit(side_.opposite())) {
return false;
@@ -369,7 +387,8 @@ void RemoteRouterLink::Deactivate() {
node_link()->RemoveRemoteRouterLink(sublink_);
}
-void RemoteRouterLink::BypassPeer(const NodeName& bypass_target_node,
+void RemoteRouterLink::BypassPeer(const OperationContext& context,
+ const NodeName& bypass_target_node,
SublinkId bypass_target_sublink) {
msg::BypassPeer bypass;
bypass.params().sublink = sublink_;
@@ -379,7 +398,8 @@ void RemoteRouterLink::BypassPeer(const NodeName& bypass_target_node,
node_link()->Transmit(bypass);
}
-void RemoteRouterLink::StopProxying(SequenceNumber inbound_sequence_length,
+void RemoteRouterLink::StopProxying(const OperationContext& context,
+ SequenceNumber inbound_sequence_length,
SequenceNumber outbound_sequence_length) {
msg::StopProxying stop;
stop.params().sublink = sublink_;
@@ -388,7 +408,8 @@ void RemoteRouterLink::StopProxying(SequenceNumber inbound_sequence_length,
node_link()->Transmit(stop);
}
-void RemoteRouterLink::ProxyWillStop(SequenceNumber inbound_sequence_length) {
+void RemoteRouterLink::ProxyWillStop(const OperationContext& context,
+ SequenceNumber inbound_sequence_length) {
msg::ProxyWillStop will_stop;
will_stop.params().sublink = sublink_;
will_stop.params().inbound_sequence_length = inbound_sequence_length;
@@ -396,6 +417,7 @@ void RemoteRouterLink::ProxyWillStop(SequenceNumber inbound_sequence_length) {
}
void RemoteRouterLink::BypassPeerWithLink(
+ const OperationContext& context,
SublinkId new_sublink,
FragmentRef<RouterLinkState> new_link_state,
SequenceNumber inbound_sequence_length) {
@@ -409,6 +431,7 @@ void RemoteRouterLink::BypassPeerWithLink(
}
void RemoteRouterLink::StopProxyingToLocalPeer(
+ const OperationContext& context,
SequenceNumber outbound_sequence_length) {
msg::StopProxyingToLocalPeer stop;
stop.params().sublink = sublink_;
diff --git a/chromium/third_party/ipcz/src/ipcz/remote_router_link.h b/chromium/third_party/ipcz/src/ipcz/remote_router_link.h
index 0eddf338c00..970bf550579 100644
--- a/chromium/third_party/ipcz/src/ipcz/remote_router_link.h
+++ b/chromium/third_party/ipcz/src/ipcz/remote_router_link.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,8 @@
#define IPCZ_SRC_IPCZ_REMOTE_ROUTER_LINK_H_
#include <atomic>
+#include <functional>
+#include <vector>
#include "ipcz/fragment_ref.h"
#include "ipcz/link_side.h"
@@ -13,6 +15,7 @@
#include "ipcz/router_link.h"
#include "ipcz/router_link_state.h"
#include "ipcz/sublink_id.h"
+#include "third_party/abseil-cpp/absl/synchronization/mutex.h"
#include "util/ref_counted.h"
namespace ipcz {
@@ -39,7 +42,8 @@ class RemoteRouterLink : public RouterLink {
// of link it is -- which for remote links must be either kCentral,
// kPeripheralInward, or kPeripheralOutward. If the link is kCentral, a
// non-null `link_state` must be provided for the link's RouterLinkState.
- static Ref<RemoteRouterLink> Create(Ref<NodeLink> node_link,
+ static Ref<RemoteRouterLink> Create(const OperationContext& context,
+ Ref<NodeLink> node_link,
SublinkId sublink,
FragmentRef<RouterLinkState> link_state,
LinkType type,
@@ -51,40 +55,46 @@ class RemoteRouterLink : public RouterLink {
// RouterLink:
LinkType GetType() const override;
RouterLinkState* GetLinkState() const override;
+ void WaitForLinkStateAsync(std::function<void()> callback) override;
Ref<Router> GetLocalPeer() override;
RemoteRouterLink* AsRemoteRouterLink() override;
void AllocateParcelData(size_t num_bytes,
bool allow_partial,
Parcel& parcel) override;
- void AcceptParcel(Parcel& parcel) override;
- void AcceptRouteClosure(SequenceNumber sequence_length) override;
- void AcceptRouteDisconnected() override;
- size_t GetParcelCapacityInBytes(const IpczPutLimits& limits) override;
- RouterLinkState::QueueState GetPeerQueueState() override;
- bool UpdateInboundQueueState(size_t num_parcels, size_t num_bytes) override;
- void NotifyDataConsumed() override;
- bool EnablePeerMonitoring(bool enable) override;
+ void AcceptParcel(const OperationContext& context, Parcel& parcel) override;
+ void AcceptRouteClosure(const OperationContext& context,
+ SequenceNumber sequence_length) override;
+ void AcceptRouteDisconnected(const OperationContext& context) override;
+ AtomicQueueState* GetPeerQueueState() override;
+ AtomicQueueState* GetLocalQueueState() override;
+ void SnapshotPeerQueueState(const OperationContext& context) override;
void MarkSideStable() override;
bool TryLockForBypass(const NodeName& bypass_request_source) override;
bool TryLockForClosure() override;
void Unlock() override;
- bool FlushOtherSideIfWaiting() override;
+ bool FlushOtherSideIfWaiting(const OperationContext& context) override;
bool CanNodeRequestBypass(const NodeName& bypass_request_source) override;
- void BypassPeer(const NodeName& bypass_target_node,
+ void BypassPeer(const OperationContext& context,
+ const NodeName& bypass_target_node,
SublinkId bypass_request_sublink) override;
- void StopProxying(SequenceNumber inbound_sequence_length,
+ void StopProxying(const OperationContext& context,
+ SequenceNumber inbound_sequence_length,
SequenceNumber outbound_sequence_length) override;
- void ProxyWillStop(SequenceNumber inbound_sequence_length) override;
- void BypassPeerWithLink(SublinkId new_sublink,
+ void ProxyWillStop(const OperationContext& context,
+ SequenceNumber inbound_sequence_length) override;
+ void BypassPeerWithLink(const OperationContext& context,
+ SublinkId new_sublink,
FragmentRef<RouterLinkState> new_link_state,
SequenceNumber inbound_sequence_length) override;
void StopProxyingToLocalPeer(
+ const OperationContext& context,
SequenceNumber outbound_sequence_length) override;
void Deactivate() override;
std::string Describe() const override;
private:
- RemoteRouterLink(Ref<NodeLink> node_link,
+ RemoteRouterLink(const OperationContext& context,
+ Ref<NodeLink> node_link,
SublinkId sublink,
FragmentRef<RouterLinkState> link_state,
LinkType type,
@@ -94,7 +104,8 @@ class RemoteRouterLink : public RouterLink {
// Sets this link's RouterLinkState. `state` must be pending or addressable
// and this must be a central link.
- void SetLinkState(FragmentRef<RouterLinkState> state);
+ void SetLinkState(const OperationContext& context,
+ FragmentRef<RouterLinkState> state);
const Ref<NodeLink> node_link_;
const SublinkId sublink_;
@@ -118,6 +129,11 @@ class RemoteRouterLink : public RouterLink {
// that value indefinitely, so any non-null value loaded from this field is
// safe to dereference for the duration of the RemoteRouterLink's lifetime.
std::atomic<RouterLinkState*> link_state_{nullptr};
+
+ // Set of callbacks to be invoked as soon as this link has a RouterLinkState.
+ absl::Mutex mutex_;
+ std::vector<std::function<void()>> link_state_callbacks_
+ ABSL_GUARDED_BY(mutex_);
};
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/route_edge.cc b/chromium/third_party/ipcz/src/ipcz/route_edge.cc
index 5b6a37171e4..836d65c799b 100644
--- a/chromium/third_party/ipcz/src/ipcz/route_edge.cc
+++ b/chromium/third_party/ipcz/src/ipcz/route_edge.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/route_edge.h b/chromium/third_party/ipcz/src/ipcz/route_edge.h
index 372ad2cf4c7..278d11bd925 100644
--- a/chromium/third_party/ipcz/src/ipcz/route_edge.h
+++ b/chromium/third_party/ipcz/src/ipcz/route_edge.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/route_edge_test.cc b/chromium/third_party/ipcz/src/ipcz/route_edge_test.cc
index 8d84a242b75..39a9469404c 100644
--- a/chromium/third_party/ipcz/src/ipcz/route_edge_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/route_edge_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/router.cc b/chromium/third_party/ipcz/src/ipcz/router.cc
index eae86db2c20..ba698426f23 100644
--- a/chromium/third_party/ipcz/src/ipcz/router.cc
+++ b/chromium/third_party/ipcz/src/ipcz/router.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,12 +9,15 @@
#include <cstring>
#include <utility>
+#include "ipcz/atomic_queue_state.h"
#include "ipcz/ipcz.h"
#include "ipcz/local_router_link.h"
#include "ipcz/node_link.h"
+#include "ipcz/operation_context.h"
#include "ipcz/remote_router_link.h"
#include "ipcz/sequence_number.h"
#include "ipcz/trap_event_dispatcher.h"
+#include "ipcz/validator.h"
#include "third_party/abseil-cpp/absl/base/macros.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
#include "third_party/abseil-cpp/absl/synchronization/mutex.h"
@@ -96,6 +99,12 @@ bool Router::IsOnCentralRemoteLink() {
void Router::QueryStatus(IpczPortalStatus& status) {
absl::MutexLock lock(&mutex_);
+ AtomicQueueState::QueryResult result;
+ if (auto* state = GetPeerQueueState()) {
+ result = state->Query({.monitor_parcels = false, .monitor_bytes = false});
+ }
+
+ UpdateStatusForPeerQueueState(result);
const size_t size = std::min(status.size, status_.size);
memcpy(&status, &status_, size);
status.size = size;
@@ -136,7 +145,8 @@ IpczResult Router::SendOutboundParcel(Parcel& parcel) {
outbound_parcels_.GetCurrentSequenceLength();
parcel.set_sequence_number(sequence_number);
if (outward_edge_.primary_link() &&
- outbound_parcels_.MaybeSkipSequenceNumber(sequence_number)) {
+ outbound_parcels_.SkipElement(sequence_number,
+ parcel.data_view().size())) {
link = outward_edge_.primary_link();
} else {
// If there are no unsent parcels ahead of this one in the outbound
@@ -151,28 +161,30 @@ IpczResult Router::SendOutboundParcel(Parcel& parcel) {
}
}
+ const OperationContext context{OperationContext::kAPICall};
if (link) {
- link->AcceptParcel(parcel);
+ link->AcceptParcel(context, parcel);
} else {
- Flush();
+ Flush(context);
}
return IPCZ_RESULT_OK;
}
void Router::CloseRoute() {
+ const OperationContext context{OperationContext::kAPICall};
TrapEventDispatcher dispatcher;
Ref<RouterLink> link;
{
absl::MutexLock lock(&mutex_);
outbound_parcels_.SetFinalSequenceLength(
outbound_parcels_.GetCurrentSequenceLength());
- traps_.RemoveAll(dispatcher);
+ traps_.RemoveAll(context, dispatcher);
}
-
- Flush();
+ Flush(context);
}
-void Router::SetOutwardLink(Ref<RouterLink> link) {
+void Router::SetOutwardLink(const OperationContext& context,
+ Ref<RouterLink> link) {
ABSL_ASSERT(link);
{
@@ -192,12 +204,12 @@ void Router::SetOutwardLink(Ref<RouterLink> link) {
if (link) {
// If the link wasn't adopted, this Router has already been disconnected.
- link->AcceptRouteDisconnected();
+ link->AcceptRouteDisconnected(context);
link->Deactivate();
return;
}
- Flush(kForceProxyBypassAttempt);
+ Flush(context, kForceProxyBypassAttempt);
}
size_t Router::GetOutboundCapacityInBytes(const IpczPutLimits& limits) {
@@ -205,45 +217,32 @@ size_t Router::GetOutboundCapacityInBytes(const IpczPutLimits& limits) {
return 0;
}
- size_t num_queued_bytes = 0;
- Ref<RouterLink> link;
- {
- absl::MutexLock lock(&mutex_);
- if (outbound_parcels_.GetNumAvailableElements() >=
- limits.max_queued_parcels) {
- return 0;
- }
- if (outbound_parcels_.GetTotalAvailableElementSize() >
- limits.max_queued_bytes) {
- return 0;
- }
+ const OperationContext context{OperationContext::kAPICall};
+ SnapshotPeerQueueState(context);
- num_queued_bytes = outbound_parcels_.GetTotalAvailableElementSize();
- link = outward_edge_.primary_link();
+ absl::MutexLock lock(&mutex_);
+ if (status_.num_remote_parcels >= limits.max_queued_parcels ||
+ status_.num_remote_bytes >= limits.max_queued_bytes) {
+ return 0;
}
- size_t link_capacity =
- link ? link->GetParcelCapacityInBytes(limits) : limits.max_queued_bytes;
- if (link_capacity <= num_queued_bytes) {
+ if (outbound_parcels_.GetNumAvailableElements() >=
+ limits.max_queued_parcels - status_.num_remote_parcels) {
return 0;
}
- return link_capacity - num_queued_bytes;
-}
-
-size_t Router::GetInboundCapacityInBytes(const IpczPutLimits& limits) {
- absl::MutexLock lock(&mutex_);
- const size_t num_queued_parcels = inbound_parcels_.GetNumAvailableElements();
- const size_t num_queued_bytes =
- inbound_parcels_.GetTotalAvailableElementSize();
- if (num_queued_bytes >= limits.max_queued_bytes ||
- num_queued_parcels >= limits.max_queued_parcels) {
+ const size_t num_bytes_pending =
+ outbound_parcels_.GetTotalAvailableElementSize();
+ const size_t available_capacity =
+ limits.max_queued_bytes - status_.num_remote_bytes;
+ if (num_bytes_pending >= available_capacity) {
return 0;
}
- return limits.max_queued_bytes - num_queued_bytes;
+ return available_capacity - num_bytes_pending;
}
-bool Router::AcceptInboundParcel(Parcel& parcel) {
+bool Router::AcceptInboundParcel(const OperationContext& context,
+ Parcel& parcel) {
TrapEventDispatcher dispatcher;
{
absl::MutexLock lock(&mutex_);
@@ -258,22 +257,17 @@ bool Router::AcceptInboundParcel(Parcel& parcel) {
// If this is a terminal router, we may have trap events to fire.
status_.num_local_parcels = inbound_parcels_.GetNumAvailableElements();
status_.num_local_bytes = inbound_parcels_.GetTotalAvailableElementSize();
- traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kNewLocalParcel,
- dispatcher);
-
- const Ref<RouterLink>& outward_link = outward_edge_.primary_link();
- if (outward_link && outward_link->GetType().is_central()) {
- outward_link->UpdateInboundQueueState(status_.num_local_parcels,
- status_.num_local_bytes);
- }
+ traps_.UpdatePortalStatus(
+ context, status_, TrapSet::UpdateReason::kNewLocalParcel, dispatcher);
}
}
- Flush();
+ Flush(context);
return true;
}
-bool Router::AcceptOutboundParcel(Parcel& parcel) {
+bool Router::AcceptOutboundParcel(const OperationContext& context,
+ Parcel& parcel) {
{
absl::MutexLock lock(&mutex_);
@@ -294,11 +288,12 @@ bool Router::AcceptOutboundParcel(Parcel& parcel) {
}
}
- Flush();
+ Flush(context);
return true;
}
-bool Router::AcceptRouteClosureFrom(LinkType link_type,
+bool Router::AcceptRouteClosureFrom(const OperationContext& context,
+ LinkType link_type,
SequenceNumber sequence_length) {
TrapEventDispatcher dispatcher;
{
@@ -316,8 +311,10 @@ bool Router::AcceptRouteClosureFrom(LinkType link_type,
if (inbound_parcels_.IsSequenceFullyConsumed()) {
status_.flags |= IPCZ_PORTAL_STATUS_DEAD;
}
- traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kPeerClosed,
- dispatcher);
+ status_.num_remote_bytes = 0;
+ status_.num_remote_parcels = 0;
+ traps_.UpdatePortalStatus(
+ context, status_, TrapSet::UpdateReason::kPeerClosed, dispatcher);
}
} else if (link_type.is_peripheral_inward()) {
if (!outbound_parcels_.SetFinalSequenceLength(sequence_length)) {
@@ -334,11 +331,12 @@ bool Router::AcceptRouteClosureFrom(LinkType link_type,
}
}
- Flush();
+ Flush(context);
return true;
}
-bool Router::AcceptRouteDisconnectedFrom(LinkType link_type) {
+bool Router::AcceptRouteDisconnectedFrom(const OperationContext& context,
+ LinkType link_type) {
TrapEventDispatcher dispatcher;
absl::InlinedVector<Ref<RouterLink>, 4> forwarding_links;
{
@@ -369,53 +367,82 @@ bool Router::AcceptRouteDisconnectedFrom(LinkType link_type) {
if (inbound_parcels_.IsSequenceFullyConsumed()) {
status_.flags |= IPCZ_PORTAL_STATUS_DEAD;
}
- traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kPeerClosed,
- dispatcher);
+ status_.num_remote_parcels = 0;
+ status_.num_remote_bytes = 0;
+ traps_.UpdatePortalStatus(context, status_,
+ TrapSet::UpdateReason::kPeerClosed, dispatcher);
}
}
for (const Ref<RouterLink>& link : forwarding_links) {
if (link) {
DVLOG(4) << "Forwarding disconnection over " << link->Describe();
- link->AcceptRouteDisconnected();
+ link->AcceptRouteDisconnected(context);
link->Deactivate();
}
}
- Flush();
+ Flush(context);
return true;
}
-void Router::NotifyPeerConsumedData() {
+void Router::SnapshotPeerQueueState(const OperationContext& context) {
TrapEventDispatcher dispatcher;
- {
- absl::MutexLock lock(&mutex_);
- const Ref<RouterLink>& outward_link = outward_edge_.primary_link();
- if (!outward_link || !outward_link->GetType().is_central() ||
- inward_edge_) {
- return;
- }
+ absl::ReleasableMutexLock lock(&mutex_);
+ Ref<RouterLink> outward_link = outward_edge_.primary_link();
+ if (!outward_link || !outward_link->GetType().is_central() || inward_edge_) {
+ return;
+ }
- const RouterLinkState::QueueState peer_state =
- outward_link->GetPeerQueueState();
- status_.num_remote_parcels = peer_state.num_parcels;
- status_.num_remote_bytes = peer_state.num_bytes;
- traps_.UpdatePortalStatus(status_, TrapSet::UpdateReason::kRemoteActivity,
- dispatcher);
+ AtomicQueueState* peer_state = outward_link->GetPeerQueueState();
+ if (!peer_state) {
+ lock.Release();
+ // Try again after we have RouterLinkState access.
+ outward_link->WaitForLinkStateAsync([self = WrapRefCounted(this), context] {
+ self->SnapshotPeerQueueState(context);
+ });
+ return;
+ }
- if (!traps_.need_remote_state()) {
- outward_link->EnablePeerMonitoring(false);
- }
+ // Start with a cheaper snapshot, which may be good enough.
+ const AtomicQueueState::QueryResult state =
+ peer_state->Query({.monitor_parcels = false, .monitor_bytes = false});
+ UpdateStatusForPeerQueueState(state);
+ traps_.UpdatePortalStatus(context, status_,
+ TrapSet::UpdateReason::kRemoteActivity, dispatcher);
+ if (!traps_.need_remote_state()) {
+ return;
}
+
+ const bool monitor_sequence_length =
+ traps_.need_remote_parcels() && !state.num_parcels_consumed.monitored;
+ const bool monitor_num_bytes =
+ traps_.need_remote_bytes() && !state.num_bytes_consumed.monitored;
+ if (!monitor_sequence_length && !monitor_num_bytes) {
+ return;
+ }
+
+ // We have at least one trap interested in remote queue state, the caller
+ // requested monitoring, and the state isn't currently being monitored. Take
+ // another snapshot, this time flipping any appropriate monitor bits.
+ UpdateStatusForPeerQueueState(peer_state->Query({
+ .monitor_parcels = traps_.need_remote_parcels(),
+ .monitor_bytes = traps_.need_remote_bytes(),
+ }));
+ traps_.UpdatePortalStatus(context, status_,
+ TrapSet::UpdateReason::kRemoteActivity, dispatcher);
}
IpczResult Router::GetNextInboundParcel(IpczGetFlags flags,
void* data,
size_t* num_bytes,
IpczHandle* handles,
- size_t* num_handles) {
+ size_t* num_handles,
+ IpczHandle* validator) {
+ const OperationContext context{OperationContext::kAPICall};
TrapEventDispatcher dispatcher;
Ref<RouterLink> link_to_notify;
+ Ref<NodeLink> remote_source;
{
absl::MutexLock lock(&mutex_);
if (inbound_parcels_.IsSequenceFullyConsumed()) {
@@ -447,6 +474,10 @@ IpczResult Router::GetNextInboundParcel(IpczGetFlags flags,
return IPCZ_RESULT_RESOURCE_EXHAUSTED;
}
+ if (validator) {
+ remote_source = p.remote_source();
+ }
+
memcpy(data, p.data_view().data(), data_size);
const bool ok = inbound_parcels_.Consume(
data_size, absl::MakeSpan(handles, handles_size));
@@ -457,20 +488,23 @@ IpczResult Router::GetNextInboundParcel(IpczGetFlags flags,
if (inbound_parcels_.IsSequenceFullyConsumed()) {
status_.flags |= IPCZ_PORTAL_STATUS_DEAD;
}
- traps_.UpdatePortalStatus(
- status_, TrapSet::UpdateReason::kLocalParcelConsumed, dispatcher);
-
- const Ref<RouterLink>& outward_link = outward_edge_.primary_link();
- if (outward_link && outward_link->GetType().is_central() &&
- outward_link->UpdateInboundQueueState(status_.num_local_parcels,
- status_.num_local_bytes)) {
- link_to_notify = outward_link;
+ traps_.UpdatePortalStatus(context, status_,
+ TrapSet::UpdateReason::kLocalParcelConsumed,
+ dispatcher);
+ if (RefreshLocalQueueState()) {
+ link_to_notify = outward_edge_.primary_link();
}
}
if (link_to_notify) {
- link_to_notify->NotifyDataConsumed();
+ link_to_notify->SnapshotPeerQueueState(context);
+ }
+
+ if (validator) {
+ *validator = Validator::ReleaseAsHandle(
+ MakeRefCounted<Validator>(std::move(remote_source)));
}
+
return IPCZ_RESULT_OK;
}
@@ -505,8 +539,11 @@ IpczResult Router::BeginGetNextIncomingParcel(const void** data,
}
IpczResult Router::CommitGetNextIncomingParcel(size_t num_data_bytes_consumed,
- absl::Span<IpczHandle> handles) {
+ absl::Span<IpczHandle> handles,
+ IpczHandle* validator) {
+ const OperationContext context{OperationContext::kAPICall};
Ref<RouterLink> link_to_notify;
+ Ref<NodeLink> remote_source;
TrapEventDispatcher dispatcher;
{
absl::MutexLock lock(&mutex_);
@@ -523,6 +560,10 @@ IpczResult Router::CommitGetNextIncomingParcel(size_t num_data_bytes_consumed,
return IPCZ_RESULT_OUT_OF_RANGE;
}
+ if (validator) {
+ remote_source = p.remote_source();
+ }
+
const bool ok = inbound_parcels_.Consume(num_data_bytes_consumed, handles);
ABSL_ASSERT(ok);
@@ -531,19 +572,21 @@ IpczResult Router::CommitGetNextIncomingParcel(size_t num_data_bytes_consumed,
if (inbound_parcels_.IsSequenceFullyConsumed()) {
status_.flags |= IPCZ_PORTAL_STATUS_DEAD;
}
- traps_.UpdatePortalStatus(
- status_, TrapSet::UpdateReason::kLocalParcelConsumed, dispatcher);
-
- const Ref<RouterLink>& outward_link = outward_edge_.primary_link();
- if (outward_link && outward_link->GetType().is_central() &&
- outward_link->UpdateInboundQueueState(status_.num_local_parcels,
- status_.num_local_bytes)) {
- link_to_notify = outward_link;
+ traps_.UpdatePortalStatus(context, status_,
+ TrapSet::UpdateReason::kLocalParcelConsumed,
+ dispatcher);
+ if (RefreshLocalQueueState()) {
+ link_to_notify = outward_edge_.primary_link();
}
}
if (link_to_notify) {
- link_to_notify->NotifyDataConsumed();
+ link_to_notify->SnapshotPeerQueueState(context);
+ }
+
+ if (validator) {
+ *validator = Validator::ReleaseAsHandle(
+ MakeRefCounted<Validator>(std::move(remote_source)));
}
return IPCZ_RESULT_OK;
@@ -554,46 +597,42 @@ IpczResult Router::Trap(const IpczTrapConditions& conditions,
uint64_t context,
IpczTrapConditionFlags* satisfied_condition_flags,
IpczPortalStatus* status) {
- const bool need_remote_state =
- (conditions.flags & (IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS |
- IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES)) != 0;
- {
- absl::MutexLock lock(&mutex_);
- const Ref<RouterLink>& outward_link = outward_edge_.primary_link();
- if (need_remote_state) {
- status_.num_remote_parcels = outbound_parcels_.GetNumAvailableElements();
- status_.num_remote_bytes =
- outbound_parcels_.GetTotalAvailableElementSize();
-
- if (outward_link && outward_link->GetType().is_central()) {
- const RouterLinkState::QueueState peer_state =
- outward_link->GetPeerQueueState();
- status_.num_remote_parcels =
- SaturatedAdd(status_.num_remote_parcels,
- static_cast<size_t>(peer_state.num_parcels));
- status_.num_remote_bytes =
- SaturatedAdd(status_.num_remote_bytes,
- static_cast<size_t>(peer_state.num_bytes));
- }
- }
-
- const bool already_monitoring_remote_state = traps_.need_remote_state();
- IpczResult result = traps_.Add(conditions, handler, context, status_,
- satisfied_condition_flags, status);
- if (result != IPCZ_RESULT_OK || !need_remote_state) {
- return result;
- }
+ absl::MutexLock lock(&mutex_);
- if (!already_monitoring_remote_state) {
- outward_link->EnablePeerMonitoring(true);
+ const bool need_remote_parcels =
+ (conditions.flags & IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS) != 0;
+ const bool need_remote_bytes =
+ (conditions.flags & IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES) != 0;
+ if (need_remote_parcels || need_remote_bytes) {
+ if (AtomicQueueState* peer_state = GetPeerQueueState()) {
+ const AtomicQueueState::QueryResult state =
+ peer_state->Query({.monitor_parcels = false, .monitor_bytes = false});
+ UpdateStatusForPeerQueueState(state);
+
+ // If the status already meets some conditions and would block trap
+ // installation, OR if it's already being monitored for changes, we can
+ // just go ahead and install the trap. Otherwise we have to re-query and
+ // set any monitoring bits ourselves.
+ const bool monitor_parcels =
+ need_remote_parcels && !state.num_parcels_consumed.monitored;
+ const bool monitor_bytes =
+ need_remote_bytes && !state.num_bytes_consumed.monitored;
+ if (!TrapSet::GetSatisfiedConditions(conditions, status_) &&
+ (monitor_parcels || monitor_bytes)) {
+ UpdateStatusForPeerQueueState(
+ peer_state->Query({.monitor_parcels = need_remote_parcels,
+ .monitor_bytes = need_remote_bytes}));
+ }
+ } else {
+ status_.num_remote_parcels =
+ outbound_parcels_.GetCurrentSequenceLength().value();
+ status_.num_remote_bytes = saturated_cast<size_t>(
+ outbound_parcels_.GetTotalElementSizeQueuedSoFar());
}
}
- // Safeguard against races between remote state changes and the new trap being
- // installed above. Only reached if the new trap monitors remote state.
- ABSL_ASSERT(need_remote_state);
- NotifyPeerConsumedData();
- return IPCZ_RESULT_OK;
+ return traps_.Add(conditions, handler, context, status_,
+ satisfied_condition_flags, status);
}
IpczResult Router::MergeRoute(const Ref<Router>& other) {
@@ -627,23 +666,33 @@ IpczResult Router::MergeRoute(const Ref<Router>& other) {
other->bridge_->SetPrimaryLink(std::move(links.second));
}
- Flush();
+ const OperationContext context{OperationContext::kAPICall};
+ Flush(context);
return IPCZ_RESULT_OK;
}
// static
Ref<Router> Router::Deserialize(const RouterDescriptor& descriptor,
NodeLink& from_node_link) {
+ // All Router deserialization occurs as a direct result of some transport
+ // notification.
+ const OperationContext context{OperationContext::kTransportNotification};
+
bool disconnected = false;
auto router = MakeRefCounted<Router>();
+ Ref<RemoteRouterLink> new_outward_link;
{
absl::MutexLock lock(&router->mutex_);
- router->outbound_parcels_.ResetInitialSequenceNumber(
- descriptor.next_outgoing_sequence_number);
- router->inbound_parcels_.ResetInitialSequenceNumber(
- descriptor.next_incoming_sequence_number);
+ router->outbound_parcels_.ResetSequence(
+ descriptor.next_outgoing_sequence_number,
+ descriptor.num_bytes_produced);
+ router->inbound_parcels_.ResetSequence(
+ descriptor.next_incoming_sequence_number,
+ descriptor.num_bytes_consumed);
if (descriptor.peer_closed) {
router->status_.flags |= IPCZ_PORTAL_STATUS_PEER_CLOSED;
+ router->status_.num_remote_parcels = 0;
+ router->status_.num_remote_bytes = 0;
if (!router->inbound_parcels_.SetFinalSequenceLength(
descriptor.closed_peer_sequence_length)) {
return nullptr;
@@ -653,126 +702,352 @@ Ref<Router> Router::Deserialize(const RouterDescriptor& descriptor,
}
}
- Ref<RemoteRouterLink> new_link = from_node_link.AddRemoteRouterLink(
- descriptor.new_sublink, nullptr, LinkType::kPeripheralOutward,
- LinkSide::kB, router);
- if (new_link) {
- router->outward_edge_.SetPrimaryLink(std::move(new_link));
+ if (descriptor.proxy_already_bypassed) {
+ // When split from a local peer, our remote counterpart (our remote peer's
+ // former local peer) will use this link to forward parcels it already
+ // received from our peer. This link decays like any other decaying link
+ // once its usefulness has expired.
+ //
+ // The sequence length toward this link is the current outbound sequence
+ // length, which is to say, we will not be sending any parcels that way.
+ // The sequence length from the link is whatever had already been sent
+ // to our counterpart back on the peer's node.
+ Ref<RemoteRouterLink> new_decaying_link =
+ from_node_link.AddRemoteRouterLink(
+ context, descriptor.new_decaying_sublink, nullptr,
+ LinkType::kPeripheralOutward, LinkSide::kB, router);
+ if (!new_decaying_link) {
+ return nullptr;
+ }
+ router->outward_edge_.SetPrimaryLink(std::move(new_decaying_link));
+ router->outward_edge_.BeginPrimaryLinkDecay();
+ router->outward_edge_.set_length_to_decaying_link(
+ router->outbound_parcels_.current_sequence_number());
+ router->outward_edge_.set_length_from_decaying_link(
+ descriptor.decaying_incoming_sequence_length > SequenceNumber(0)
+ ? descriptor.decaying_incoming_sequence_length
+ : descriptor.next_incoming_sequence_number);
+
+ new_outward_link = from_node_link.AddRemoteRouterLink(
+ context, descriptor.new_sublink,
+ from_node_link.memory().AdoptFragmentRef<RouterLinkState>(
+ from_node_link.memory().GetFragment(
+ descriptor.new_link_state_fragment)),
+ LinkType::kCentral, LinkSide::kB, router);
+ if (!new_outward_link) {
+ return nullptr;
+ }
+ router->outward_edge_.SetPrimaryLink(new_outward_link);
DVLOG(4) << "Route extended from "
<< from_node_link.remote_node_name().ToString() << " to "
<< from_node_link.local_node_name().ToString() << " via sublink "
- << descriptor.new_sublink;
- } else if (!descriptor.peer_closed) {
- // The new portal is DOA, either because the associated NodeLink is dead,
- // or the sublink ID was already in use. The latter implies a bug or bad
- // behavior, but it should be harmless to ignore beyond this point.
- disconnected = true;
+ << descriptor.new_sublink << " and decaying sublink "
+ << descriptor.new_decaying_sublink;
+ } else {
+ if (!descriptor.new_link_state_fragment.is_null()) {
+ // No RouterLinkState fragment should be provided for this new
+ // peripheral link.
+ return nullptr;
+ }
+ new_outward_link = from_node_link.AddRemoteRouterLink(
+ context, descriptor.new_sublink, nullptr,
+ LinkType::kPeripheralOutward, LinkSide::kB, router);
+ if (new_outward_link) {
+ router->outward_edge_.SetPrimaryLink(new_outward_link);
+
+ DVLOG(4) << "Route extended from "
+ << from_node_link.remote_node_name().ToString() << " to "
+ << from_node_link.local_node_name().ToString()
+ << " via sublink " << descriptor.new_sublink;
+ } else if (!descriptor.peer_closed) {
+ // The new portal is DOA, either because the associated NodeLink is
+ // dead, or the sublink ID was already in use. The latter implies a bug
+ // or bad behavior, but it should be harmless to ignore beyond this
+ // point.
+ disconnected = true;
+ }
}
}
if (disconnected) {
DVLOG(4) << "Disconnected new Router immediately after deserialization";
- router->AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+ router->AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralOutward);
+ } else if (descriptor.proxy_peer_node_name.is_valid()) {
+ // The source router rolled some peer bypass details into our descriptor to
+ // avoid some IPC overhead. We can begin bypassing the proxy now.
+ ABSL_ASSERT(new_outward_link);
+ router->BypassPeer(context, *new_outward_link,
+ descriptor.proxy_peer_node_name,
+ descriptor.proxy_peer_sublink);
}
- router->Flush(kForceProxyBypassAttempt);
+
+ router->Flush(context, kForceProxyBypassAttempt);
return router;
}
-void Router::SerializeNewRouter(NodeLink& to_node_link,
+void Router::SerializeNewRouter(const OperationContext& context,
+ NodeLink& to_node_link,
RouterDescriptor& descriptor) {
TrapEventDispatcher dispatcher;
- const SublinkId new_sublink = to_node_link.memory().AllocateSublinkIds(1);
- descriptor.new_sublink = new_sublink;
+ Ref<Router> local_peer;
+ bool initiate_proxy_bypass = false;
{
absl::MutexLock lock(&mutex_);
- traps_.RemoveAll(dispatcher);
+ traps_.RemoveAll(context, dispatcher);
+ local_peer = outward_edge_.GetLocalPeer();
+ initiate_proxy_bypass = outward_edge_.primary_link() &&
+ outward_edge_.primary_link()->TryLockForBypass(
+ to_node_link.remote_node_name());
+ }
- descriptor.next_outgoing_sequence_number =
- outbound_parcels_.GetCurrentSequenceLength();
- descriptor.next_incoming_sequence_number =
- inbound_parcels_.current_sequence_number();
+ if (local_peer && initiate_proxy_bypass &&
+ SerializeNewRouterWithLocalPeer(context, to_node_link, descriptor,
+ local_peer)) {
+ return;
+ }
- // Initialize an inward edge but with no link yet. This ensures that we
- // don't look like a terminal router while waiting for a link to be set,
- // which can only happen after `descriptor` is transmitted.
- inward_edge_.emplace();
+ SerializeNewRouterAndConfigureProxy(context, to_node_link, descriptor,
+ initiate_proxy_bypass);
+}
- if (status_.flags & IPCZ_PORTAL_STATUS_PEER_CLOSED) {
- descriptor.peer_closed = true;
- descriptor.closed_peer_sequence_length =
- *inbound_parcels_.final_sequence_length();
+bool Router::SerializeNewRouterWithLocalPeer(const OperationContext& context,
+ NodeLink& to_node_link,
+ RouterDescriptor& descriptor,
+ Ref<Router> local_peer) {
+ MultiMutexLock lock(&mutex_, &local_peer->mutex_);
+ if (local_peer->outward_edge_.GetLocalPeer() != this) {
+ // If the peer was closed, its link to us may already be invalidated.
+ return false;
+ }
- // Ensure that the new edge decays its link as soon as it has one, since
- // we know the link will not be used.
- inward_edge_->BeginPrimaryLinkDecay();
- inward_edge_->set_length_to_decaying_link(
- *inbound_parcels_.final_sequence_length());
- inward_edge_->set_length_from_decaying_link(
- outbound_parcels_.current_sequence_number());
- }
+ FragmentRef<RouterLinkState> new_link_state =
+ to_node_link.memory().TryAllocateRouterLinkState();
+ if (!new_link_state.is_addressable()) {
+ // If we couldn't allocate a RouterLinkState for a new central link, then
+ // we can't replace the central link yet. Fall back to the proxying case.
+ return false;
+ }
- // Once `descriptor` is transmitted to the destination node and the new
- // Router is created there, it may immediately begin transmitting messages
- // back to this node regarding `new_sublink`. We establish a new
- // RemoteRouterLink now and register it to `new_sublink` on `to_node_link`,
- // so that any such incoming messages are routed to `this`.
- //
- // NOTE: We do not yet provide `this` itself with a reference to the new
- // RemoteRouterLink, because it's not yet safe for us to send messages to
- // the remote node regarding `new_sublink`. `descriptor` must be transmitted
- // first.
- Ref<RemoteRouterLink> new_link = to_node_link.AddRemoteRouterLink(
- new_sublink, nullptr, LinkType::kPeripheralInward, LinkSide::kA,
- WrapRefCounted(this));
+ const SequenceNumber proxy_inbound_sequence_length =
+ local_peer->outbound_parcels_.current_sequence_number();
- DVLOG(4) << "Router " << this << " extending route with tentative new "
- << new_link->Describe();
- }
+ // The local peer no longer needs its link to us. We'll give it a new
+ // outward link in BeginProxyingToNewRouter() after this descriptor is
+ // transmitted.
+ local_peer->outward_edge_.ReleasePrimaryLink();
+
+ // The primary new sublink to the destination node will act as the route's
+ // new central link between our local peer and the new remote router.
+ //
+ // An additional sublink is allocated to act as a decaying inward link from
+ // this router to the new one, so we can forward any inbound parcels that have
+ // already been queued here.
+ const SublinkId new_sublink = to_node_link.memory().AllocateSublinkIds(2);
+ const SublinkId decaying_sublink = SublinkId(new_sublink.value() + 1);
+
+ // Register the new routes on the NodeLink. Note that we don't provide them to
+ // any routers yet since we don't want the routers using them until this
+ // descriptor is transmitted to its destination node. The links will be
+ // adopted after transmission in BeginProxyingToNewRouter().
+ Ref<RouterLink> new_link = to_node_link.AddRemoteRouterLink(
+ context, new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
+ local_peer);
+
+ to_node_link.AddRemoteRouterLink(context, decaying_sublink, nullptr,
+ LinkType::kPeripheralInward, LinkSide::kA,
+ WrapRefCounted(this));
+
+ descriptor.new_sublink = new_sublink;
+ descriptor.new_link_state_fragment = new_link_state.release().descriptor();
+ descriptor.new_decaying_sublink = decaying_sublink;
+ descriptor.proxy_already_bypassed = true;
+ descriptor.next_outgoing_sequence_number =
+ outbound_parcels_.GetCurrentSequenceLength();
+ descriptor.num_bytes_produced =
+ outbound_parcels_.total_consumed_element_size();
+ descriptor.next_incoming_sequence_number =
+ inbound_parcels_.current_sequence_number();
+ descriptor.num_bytes_consumed =
+ inbound_parcels_.total_consumed_element_size();
+ descriptor.decaying_incoming_sequence_length = proxy_inbound_sequence_length;
+
+ DVLOG(4) << "Splitting local pair to move router with outbound sequence "
+ << "length " << descriptor.next_outgoing_sequence_number
+ << " and current inbound sequence number "
+ << descriptor.next_incoming_sequence_number;
+
+ if (inbound_parcels_.final_sequence_length()) {
+ descriptor.peer_closed = true;
+ descriptor.closed_peer_sequence_length =
+ *inbound_parcels_.final_sequence_length();
+ }
+
+ // Initialize an inward edge that will immediately begin decaying once it has
+ // a link (established in BeginProxyingToNewRouter()).
+ inward_edge_.emplace();
+ inward_edge_->BeginPrimaryLinkDecay();
+ inward_edge_->set_length_to_decaying_link(proxy_inbound_sequence_length);
+ inward_edge_->set_length_from_decaying_link(
+ outbound_parcels_.GetCurrentSequenceLength());
+ return true;
}
-void Router::BeginProxyingToNewRouter(NodeLink& to_node_link,
- const RouterDescriptor& descriptor) {
- // Acquire a reference to the RemoteRouterLink created by an earlier call to
- // SerializeNewRouter(). If the NodeLink has already been disconnected, this
- // may be null.
- if (auto new_sublink = to_node_link.GetSublink(descriptor.new_sublink)) {
- Ref<RemoteRouterLink> new_router_link = new_sublink->router_link;
- {
- absl::MutexLock lock(&mutex_);
- ABSL_ASSERT(inward_edge_);
+void Router::SerializeNewRouterAndConfigureProxy(
+ const OperationContext& context,
+ NodeLink& to_node_link,
+ RouterDescriptor& descriptor,
+ bool initiate_proxy_bypass) {
+ const SublinkId new_sublink = to_node_link.memory().AllocateSublinkIds(1);
- // If the new router has already been closed or disconnected, we will
- // discard the new link to it.
- if (!outbound_parcels_.final_sequence_length() && !is_disconnected_) {
- DVLOG(4) << "Router " << this << " will proxy to new router over "
- << new_router_link->Describe();
+ absl::MutexLock lock(&mutex_);
+ descriptor.new_sublink = new_sublink;
+ descriptor.new_link_state_fragment = FragmentDescriptor();
+ descriptor.proxy_already_bypassed = false;
+ descriptor.next_outgoing_sequence_number =
+ outbound_parcels_.GetCurrentSequenceLength();
+ descriptor.num_bytes_produced =
+ outbound_parcels_.total_consumed_element_size();
+ descriptor.next_incoming_sequence_number =
+ inbound_parcels_.current_sequence_number();
+ descriptor.num_bytes_consumed =
+ inbound_parcels_.total_consumed_element_size();
+
+ // Initialize an inward edge but with no link yet. This ensures that we
+ // don't look like a terminal router while waiting for a link to be set,
+ // which can only happen after `descriptor` is transmitted.
+ inward_edge_.emplace();
+
+ if (status_.flags & IPCZ_PORTAL_STATUS_PEER_CLOSED) {
+ descriptor.peer_closed = true;
+ descriptor.closed_peer_sequence_length =
+ *inbound_parcels_.final_sequence_length();
+
+ // Ensure that the new edge decays its link as soon as it has one, since
+ // we know the link will not be used.
+ inward_edge_->BeginPrimaryLinkDecay();
+ inward_edge_->set_length_to_decaying_link(
+ *inbound_parcels_.final_sequence_length());
+ inward_edge_->set_length_from_decaying_link(
+ outbound_parcels_.current_sequence_number());
+ } else if (initiate_proxy_bypass && outward_edge_.primary_link()) {
+ RemoteRouterLink* remote_link =
+ outward_edge_.primary_link()->AsRemoteRouterLink();
+ if (remote_link) {
+ descriptor.proxy_peer_node_name =
+ remote_link->node_link()->remote_node_name();
+ descriptor.proxy_peer_sublink = remote_link->sublink();
+ DVLOG(4) << "Will initiate proxy bypass immediately on deserialization "
+ << "with peer at " << descriptor.proxy_peer_node_name.ToString()
+ << " and peer route to proxy on sublink "
+ << descriptor.proxy_peer_sublink;
- inward_edge_->SetPrimaryLink(std::move(new_router_link));
+ inward_edge_->BeginPrimaryLinkDecay();
+ outward_edge_.BeginPrimaryLinkDecay();
+ } else {
+ // The link was locked in anticipation of initiating a proxy bypass, but
+ // that's no longer going to happen.
+ outward_edge_.primary_link()->Unlock();
+ }
+ }
+
+ // Once `descriptor` is transmitted to the destination node and the new
+ // Router is created there, it may immediately begin transmitting messages
+ // back to this node regarding `new_sublink`. We establish a new
+ // RemoteRouterLink now and register it to `new_sublink` on `to_node_link`,
+ // so that any such incoming messages are routed to `this`.
+ //
+ // NOTE: We do not yet provide `this` itself with a reference to the new
+ // RemoteRouterLink, because it's not yet safe for us to send messages to
+ // the remote node regarding `new_sublink`. `descriptor` must be transmitted
+ // first.
+ Ref<RemoteRouterLink> new_link = to_node_link.AddRemoteRouterLink(
+ context, new_sublink, nullptr, LinkType::kPeripheralInward, LinkSide::kA,
+ WrapRefCounted(this));
+ DVLOG(4) << "Router " << this << " extending route with tentative new "
+ << new_link->Describe();
+}
- Ref<RouterLink> outward_link = outward_edge_.primary_link();
- if (outward_link && outward_edge_.is_stable() &&
- inward_edge_->is_stable()) {
- outward_link->MarkSideStable();
- }
+void Router::BeginProxyingToNewRouter(const OperationContext& context,
+ NodeLink& to_node_link,
+ const RouterDescriptor& descriptor) {
+ Ref<RouterLink> peer_link;
+ Ref<Router> local_peer;
+
+ // Acquire references to RemoteRouterLink(s) created by an earlier call to
+ // SerializeNewRouter(). If the NodeLink has already been disconnected, these
+ // may be null.
+ auto new_sublink = to_node_link.GetSublink(descriptor.new_sublink);
+ auto new_decaying_sublink =
+ to_node_link.GetSublink(descriptor.new_decaying_sublink);
+ if (!new_sublink) {
+ Flush(context, kForceProxyBypassAttempt);
+ return;
+ }
+
+ Ref<RemoteRouterLink> new_primary_link = new_sublink->router_link;
+ Ref<RemoteRouterLink> new_decaying_link;
+ {
+ absl::MutexLock lock(&mutex_);
+ ABSL_ASSERT(inward_edge_);
+
+ if (descriptor.proxy_already_bypassed) {
+ peer_link = outward_edge_.ReleasePrimaryLink();
+ local_peer = peer_link ? peer_link->GetLocalPeer() : nullptr;
+ new_decaying_link =
+ new_decaying_sublink ? new_decaying_sublink->router_link : nullptr;
+ }
+
+ if (local_peer && new_decaying_link && !is_disconnected_) {
+ // We've already bypassed this router. Use the new decaying link for our
+ // inward edge in case we need to forward parcels to the new router. The
+ // new primary link will be adopted by our peer further below.
+ inward_edge_->SetPrimaryLink(std::move(new_decaying_link));
+ } else if (!outbound_parcels_.final_sequence_length() &&
+ !new_decaying_link && !is_disconnected_) {
+ DVLOG(4) << "Router " << this << " will proxy to new router over "
+ << new_primary_link->Describe();
+ inward_edge_->SetPrimaryLink(std::move(new_primary_link));
+
+ Ref<RouterLink> outward_link = outward_edge_.primary_link();
+ if (outward_link && outward_edge_.is_stable() &&
+ inward_edge_->is_stable()) {
+ outward_link->MarkSideStable();
}
}
+ }
- if (new_router_link) {
- // The link was not adopted, so deactivate and discard it.
- DVLOG(4) << "Dropping link to new router " << new_router_link->Describe();
- new_router_link->AcceptRouteDisconnected();
- new_router_link->Deactivate();
- return;
- }
+ if (local_peer && new_primary_link && !new_decaying_link) {
+ // If we have a `local_peer` and no decaying link, this means the decaying
+ // link was successfully adopted for our own inward edge; and the primary
+ // link is therefore meant to serve as our local peer's new outward link
+ // directly to the new remote router.
+ local_peer->SetOutwardLink(context, std::move(new_primary_link));
+ }
+
+ // New links were not adopted, implying that the new router has already been
+ // closed or disconnected.
+ if (new_primary_link) {
+ DVLOG(4) << "Dropping link to new router " << new_primary_link->Describe();
+ new_primary_link->AcceptRouteDisconnected(context);
+ new_primary_link->Deactivate();
+ }
+ if (new_decaying_link) {
+ DVLOG(4) << "Dropping link to new router " << new_decaying_link->Describe();
+ new_decaying_link->AcceptRouteDisconnected(context);
+ new_decaying_link->Deactivate();
}
// We may have inbound parcels queued which need to be forwarded to the new
// Router, so give them a chance to be flushed out.
- Flush(kForceProxyBypassAttempt);
+ Flush(context, kForceProxyBypassAttempt);
+ if (local_peer) {
+ local_peer->Flush(context, kForceProxyBypassAttempt);
+ }
}
-bool Router::BypassPeer(RemoteRouterLink& requestor,
+bool Router::BypassPeer(const OperationContext& context,
+ RemoteRouterLink& requestor,
const NodeName& bypass_target_node,
SublinkId bypass_target_sublink) {
NodeLink& from_node_link = *requestor.node_link();
@@ -804,7 +1079,7 @@ bool Router::BypassPeer(RemoteRouterLink& requestor,
from_node_link.node()->GetLink(bypass_target_node);
if (link_to_bypass_target) {
return BypassPeerWithNewRemoteLink(
- requestor, *link_to_bypass_target, bypass_target_sublink,
+ context, requestor, *link_to_bypass_target, bypass_target_sublink,
link_to_bypass_target->memory().TryAllocateRouterLinkState());
}
@@ -812,25 +1087,28 @@ bool Router::BypassPeer(RemoteRouterLink& requestor,
from_node_link.node()->EstablishLink(
bypass_target_node,
[router = WrapRefCounted(this), requestor = WrapRefCounted(&requestor),
- bypass_target_sublink](NodeLink* link_to_bypass_target) {
+ bypass_target_sublink, context](NodeLink* link_to_bypass_target) {
if (!link_to_bypass_target) {
DLOG(ERROR) << "Disconnecting Router due to failed introduction";
- router->AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+ router->AcceptRouteDisconnectedFrom(context,
+ LinkType::kPeripheralOutward);
return;
}
router->BypassPeerWithNewRemoteLink(
- *requestor, *link_to_bypass_target, bypass_target_sublink,
+ context, *requestor, *link_to_bypass_target,
+ bypass_target_sublink,
link_to_bypass_target->memory().TryAllocateRouterLinkState());
});
return true;
}
// The second case is when the proxy's outward peer lives on our own node.
- return BypassPeerWithNewLocalLink(requestor, bypass_target_sublink);
+ return BypassPeerWithNewLocalLink(context, requestor, bypass_target_sublink);
}
bool Router::AcceptBypassLink(
+ const OperationContext& context,
NodeLink& new_node_link,
SublinkId new_sublink,
FragmentRef<RouterLinkState> new_link_state,
@@ -873,7 +1151,7 @@ bool Router::AcceptBypassLink(
// By convention the initiator of a bypass assumes side A of the bypass
// link, so we assume side B.
new_link = new_node_link.AddRemoteRouterLink(
- new_sublink, std::move(new_link_state), LinkType::kCentral,
+ context, new_sublink, std::move(new_link_state), LinkType::kCentral,
LinkSide::kB, WrapRefCounted(this));
if (new_link) {
@@ -891,7 +1169,7 @@ bool Router::AcceptBypassLink(
}
if (!new_link) {
- AcceptRouteDisconnectedFrom(LinkType::kCentral);
+ AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
return true;
}
@@ -899,20 +1177,21 @@ bool Router::AcceptBypassLink(
// If the new link goes to the same place as the old link, we only need
// to tell the proxy there to stop proxying. It has already conspired with
// its local outward peer.
- old_link->StopProxyingToLocalPeer(length_to_proxy_from_us);
+ old_link->StopProxyingToLocalPeer(context, length_to_proxy_from_us);
} else {
// Otherwise, tell the proxy to stop proxying and let its inward peer (our
// new outward peer) know that the proxy will stop.
- old_link->StopProxying(length_to_proxy_from_us,
+ old_link->StopProxying(context, length_to_proxy_from_us,
inbound_sequence_length_from_bypassed_link);
- new_link->ProxyWillStop(length_to_proxy_from_us);
+ new_link->ProxyWillStop(context, length_to_proxy_from_us);
}
- Flush();
+ Flush(context);
return true;
}
-bool Router::StopProxying(SequenceNumber inbound_sequence_length,
+bool Router::StopProxying(const OperationContext& context,
+ SequenceNumber inbound_sequence_length,
SequenceNumber outbound_sequence_length) {
Ref<Router> bridge_peer;
{
@@ -965,14 +1244,15 @@ bool Router::StopProxying(SequenceNumber inbound_sequence_length,
outbound_sequence_length);
}
- Flush();
+ Flush(context);
if (bridge_peer) {
- bridge_peer->Flush();
+ bridge_peer->Flush(context);
}
return true;
}
-bool Router::NotifyProxyWillStop(SequenceNumber inbound_sequence_length) {
+bool Router::NotifyProxyWillStop(const OperationContext& context,
+ SequenceNumber inbound_sequence_length) {
{
absl::MutexLock lock(&mutex_);
if (outward_edge_.is_stable()) {
@@ -988,11 +1268,12 @@ bool Router::NotifyProxyWillStop(SequenceNumber inbound_sequence_length) {
outward_edge_.set_length_from_decaying_link(inbound_sequence_length);
}
- Flush();
+ Flush(context);
return true;
}
-bool Router::StopProxyingToLocalPeer(SequenceNumber outbound_sequence_length) {
+bool Router::StopProxyingToLocalPeer(const OperationContext& context,
+ SequenceNumber outbound_sequence_length) {
Ref<Router> local_peer;
Ref<Router> bridge_peer;
{
@@ -1072,15 +1353,16 @@ bool Router::StopProxyingToLocalPeer(SequenceNumber outbound_sequence_length) {
return false;
}
- Flush();
- local_peer->Flush();
+ Flush(context);
+ local_peer->Flush(context);
if (bridge_peer) {
- bridge_peer->Flush();
+ bridge_peer->Flush(context);
}
return true;
}
-void Router::NotifyLinkDisconnected(RemoteRouterLink& link) {
+void Router::NotifyLinkDisconnected(const OperationContext& context,
+ RemoteRouterLink& link) {
{
absl::MutexLock lock(&mutex_);
if (outward_edge_.primary_link() == &link) {
@@ -1099,13 +1381,13 @@ void Router::NotifyLinkDisconnected(RemoteRouterLink& link) {
}
if (link.GetType().is_outward()) {
- AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+ AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralOutward);
} else {
- AcceptRouteDisconnectedFrom(LinkType::kPeripheralInward);
+ AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralInward);
}
}
-void Router::Flush(FlushBehavior behavior) {
+void Router::Flush(const OperationContext& context, FlushBehavior behavior) {
Ref<RouterLink> outward_link;
Ref<RouterLink> inward_link;
Ref<RouterLink> bridge_link;
@@ -1120,6 +1402,8 @@ void Router::Flush(FlushBehavior behavior) {
bool inward_link_decayed = false;
bool outward_link_decayed = false;
bool dropped_last_decaying_link = false;
+ bool snapshot_peer_queue_state = false;
+ bool peer_needs_local_state_update = false;
ParcelsToFlush parcels_to_flush;
{
absl::MutexLock lock(&mutex_);
@@ -1132,6 +1416,8 @@ void Router::Flush(FlushBehavior behavior) {
decaying_inward_link =
inward_edge_ ? inward_edge_->decaying_link() : nullptr;
on_central_link = outward_link && outward_link->GetType().is_central();
+ snapshot_peer_queue_state = on_central_link && traps_.need_remote_state();
+ peer_needs_local_state_update = on_central_link && RefreshLocalQueueState();
if (bridge_) {
// Bridges have either a primary link or decaying link, but never both.
bridge_link = bridge_->primary_link() ? bridge_->primary_link()
@@ -1233,7 +1519,7 @@ void Router::Flush(FlushBehavior behavior) {
}
for (ParcelToFlush& parcel : parcels_to_flush) {
- parcel.link->AcceptParcel(parcel.parcel);
+ parcel.link->AcceptParcel(context, parcel.parcel);
}
if (outward_link_decayed) {
@@ -1246,26 +1532,29 @@ void Router::Flush(FlushBehavior behavior) {
if (bridge_link && outward_link && !inward_link && !decaying_inward_link &&
!decaying_outward_link) {
- MaybeStartBridgeBypass();
+ MaybeStartBridgeBypass(context);
}
if (dead_outward_link) {
if (final_outward_sequence_length) {
- dead_outward_link->AcceptRouteClosure(*final_outward_sequence_length);
+ dead_outward_link->AcceptRouteClosure(context,
+ *final_outward_sequence_length);
}
dead_outward_link->Deactivate();
}
if (dead_inward_link) {
if (final_inward_sequence_length) {
- dead_inward_link->AcceptRouteClosure(*final_inward_sequence_length);
+ dead_inward_link->AcceptRouteClosure(context,
+ *final_inward_sequence_length);
}
dead_inward_link->Deactivate();
}
if (dead_bridge_link) {
if (final_inward_sequence_length) {
- dead_bridge_link->AcceptRouteClosure(*final_inward_sequence_length);
+ dead_bridge_link->AcceptRouteClosure(context,
+ *final_inward_sequence_length);
}
}
@@ -1274,21 +1563,95 @@ void Router::Flush(FlushBehavior behavior) {
return;
}
+ if (snapshot_peer_queue_state) {
+ SnapshotPeerQueueState(context);
+ }
+
+ if (peer_needs_local_state_update) {
+ outward_link->SnapshotPeerQueueState(context);
+ }
+
if (!dropped_last_decaying_link && behavior != kForceProxyBypassAttempt) {
// No relevant state changes, so there are no new bypass opportunities.
return;
}
- if (inward_link && MaybeStartSelfBypass()) {
+ if (inward_link && MaybeStartSelfBypass(context)) {
return;
}
if (outward_link) {
- outward_link->FlushOtherSideIfWaiting();
+ outward_link->FlushOtherSideIfWaiting(context);
}
}
-bool Router::MaybeStartSelfBypass() {
+AtomicQueueState* Router::GetPeerQueueState() {
+ if (!outward_edge_.primary_link()) {
+ return nullptr;
+ }
+
+ if (!outward_edge_.primary_link()->GetType().is_central()) {
+ return nullptr;
+ }
+
+ return outward_edge_.primary_link()->GetPeerQueueState();
+}
+
+bool Router::RefreshLocalQueueState() {
+ const Ref<RouterLink>& outward_link = outward_edge_.primary_link();
+ if (!outward_link) {
+ return false;
+ }
+
+ auto* state = outward_link->GetLocalQueueState();
+ if (!state) {
+ return false;
+ }
+
+ const uint64_t num_parcels_consumed =
+ inbound_parcels_.current_sequence_number().value();
+ const uint64_t num_bytes_consumed =
+ inbound_parcels_.total_consumed_element_size();
+ if (last_queue_update_ &&
+ last_queue_update_->num_parcels_consumed == num_parcels_consumed &&
+ last_queue_update_->num_bytes_consumed == num_bytes_consumed) {
+ // If our current status doesn't differ in some way from the last time we
+ // updated the local AtomicQueueState, there's nothing to do.
+ return false;
+ }
+
+ last_queue_update_ = AtomicQueueState::UpdateValue{
+ .num_parcels_consumed = num_parcels_consumed,
+ .num_bytes_consumed = num_bytes_consumed,
+ };
+ return state->Update(*last_queue_update_);
+}
+
+void Router::UpdateStatusForPeerQueueState(
+ const AtomicQueueState::QueryResult& state) {
+ // The consumed amounts should never exceed produced amounts. If they do,
+ // treat them as zero.
+ const uint64_t num_parcels_produced =
+ outbound_parcels_.GetCurrentSequenceLength().value();
+ uint64_t num_parcels_consumed = 0;
+ if (state.num_parcels_consumed.value <= num_parcels_produced) {
+ num_parcels_consumed = state.num_parcels_consumed.value;
+ }
+
+ const uint64_t num_bytes_produced =
+ outbound_parcels_.GetTotalElementSizeQueuedSoFar();
+ uint64_t num_bytes_consumed = 0;
+ if (state.num_bytes_consumed.value <= num_bytes_produced) {
+ num_bytes_consumed = state.num_bytes_consumed.value;
+ }
+
+ status_.num_remote_parcels =
+ saturated_cast<size_t>(num_parcels_produced - num_parcels_consumed);
+ status_.num_remote_bytes =
+ saturated_cast<size_t>(num_bytes_produced - num_bytes_consumed);
+}
+
+bool Router::MaybeStartSelfBypass(const OperationContext& context) {
Ref<RemoteRouterLink> remote_inward_link;
Ref<RemoteRouterLink> remote_outward_link;
Ref<Router> local_outward_peer;
@@ -1343,7 +1706,7 @@ bool Router::MaybeStartSelfBypass() {
<< remote_outward_link->Describe();
remote_inward_link->BypassPeer(
- remote_outward_link->node_link()->remote_node_name(),
+ context, remote_outward_link->node_link()->remote_node_name(),
remote_outward_link->sublink());
return true;
}
@@ -1352,22 +1715,24 @@ bool Router::MaybeStartSelfBypass() {
// establish the bypass link immediately and send it to the remote inward
// peer.
return StartSelfBypassToLocalPeer(
- *local_outward_peer, *remote_inward_link,
+ context, *local_outward_peer, *remote_inward_link,
remote_inward_link->node_link()->memory().TryAllocateRouterLinkState());
}
bool Router::StartSelfBypassToLocalPeer(
+ const OperationContext& context,
Router& local_outward_peer,
RemoteRouterLink& inward_link,
FragmentRef<RouterLinkState> new_link_state) {
if (new_link_state.is_null()) {
NodeLinkMemory& memory = inward_link.node_link()->memory();
memory.AllocateRouterLinkState(
- [router = WrapRefCounted(this),
+ [router = WrapRefCounted(this), context,
local_outward_peer = WrapRefCounted(&local_outward_peer),
inward_link = WrapRefCounted(&inward_link)](
FragmentRef<RouterLinkState> new_link_state) {
- router->StartSelfBypassToLocalPeer(*local_outward_peer, *inward_link,
+ router->StartSelfBypassToLocalPeer(context, *local_outward_peer,
+ *inward_link,
std::move(new_link_state));
});
return true;
@@ -1408,25 +1773,26 @@ bool Router::StartSelfBypassToLocalPeer(
inward_edge_->set_length_to_decaying_link(length_from_outward_peer);
new_link = inward_link.node_link()->AddRemoteRouterLink(
- new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
+ context, new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
WrapRefCounted(&local_outward_peer));
}
if (!new_link) {
- AcceptRouteDisconnectedFrom(LinkType::kCentral);
+ AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
return false;
}
// Inform our inward peer on another node that they can bypass us using the
// new link we just created to our own outward local peer. Once that message
// is sent, it's safe for that local peer to adopt the new link.
- inward_link.BypassPeerWithLink(new_sublink, std::move(new_link_state),
+ inward_link.BypassPeerWithLink(context, new_sublink,
+ std::move(new_link_state),
length_from_outward_peer);
- local_outward_peer.SetOutwardLink(std::move(new_link));
+ local_outward_peer.SetOutwardLink(context, std::move(new_link));
return true;
}
-void Router::MaybeStartBridgeBypass() {
+void Router::MaybeStartBridgeBypass(const OperationContext& context) {
Ref<Router> first_bridge = WrapRefCounted(this);
Ref<Router> second_bridge;
{
@@ -1501,7 +1867,7 @@ void Router::MaybeStartBridgeBypass() {
second_bridge->bridge_->BeginPrimaryLinkDecay();
}
second_remote_link->BypassPeer(
- first_remote_link->node_link()->remote_node_name(),
+ context, first_remote_link->node_link()->remote_node_name(),
first_remote_link->sublink());
return;
}
@@ -1512,10 +1878,12 @@ void Router::MaybeStartBridgeBypass() {
// it's a bit more complex than the cases above and below.
if (!second_local_peer) {
StartBridgeBypassFromLocalPeer(
+ context,
second_remote_link->node_link()->memory().TryAllocateRouterLinkState());
return;
} else if (!first_local_peer) {
second_bridge->StartBridgeBypassFromLocalPeer(
+ context,
first_remote_link->node_link()->memory().TryAllocateRouterLinkState());
return;
}
@@ -1568,13 +1936,14 @@ void Router::MaybeStartBridgeBypass() {
second_local_peer->outward_edge_.SetPrimaryLink(std::move(links.second));
}
- first_bridge->Flush();
- second_bridge->Flush();
- first_local_peer->Flush();
- second_local_peer->Flush();
+ first_bridge->Flush(context);
+ second_bridge->Flush(context);
+ first_local_peer->Flush(context);
+ second_local_peer->Flush(context);
}
void Router::StartBridgeBypassFromLocalPeer(
+ const OperationContext& context,
FragmentRef<RouterLinkState> link_state) {
Ref<Router> local_peer;
Ref<Router> other_bridge;
@@ -1609,9 +1978,10 @@ void Router::StartBridgeBypassFromLocalPeer(
// We need a new RouterLinkState on the remote link before we can complete
// this operation.
remote_link->node_link()->memory().AllocateRouterLinkState(
- [router = WrapRefCounted(this)](FragmentRef<RouterLinkState> state) {
+ [router = WrapRefCounted(this),
+ context](FragmentRef<RouterLinkState> state) {
if (!state.is_null()) {
- router->StartBridgeBypassFromLocalPeer(std::move(state));
+ router->StartBridgeBypassFromLocalPeer(context, std::move(state));
}
});
return;
@@ -1627,7 +1997,8 @@ void Router::StartBridgeBypassFromLocalPeer(
const SublinkId bypass_sublink =
node_link_to_peer->memory().AllocateSublinkIds(1);
Ref<RemoteRouterLink> new_link = node_link_to_peer->AddRemoteRouterLink(
- bypass_sublink, link_state, LinkType::kCentral, LinkSide::kA, local_peer);
+ context, bypass_sublink, link_state, LinkType::kCentral, LinkSide::kA,
+ local_peer);
{
MultiMutexLock lock(&mutex_, &other_bridge->mutex_, &local_peer->mutex_);
@@ -1653,15 +2024,16 @@ void Router::StartBridgeBypassFromLocalPeer(
other_bridge_edge.set_length_from_decaying_link(length_from_local_peer);
}
- remote_link->BypassPeerWithLink(bypass_sublink, std::move(link_state),
- length_from_local_peer);
- local_peer->SetOutwardLink(std::move(new_link));
- Flush();
- other_bridge->Flush();
- local_peer->Flush();
+ remote_link->BypassPeerWithLink(
+ context, bypass_sublink, std::move(link_state), length_from_local_peer);
+ local_peer->SetOutwardLink(context, std::move(new_link));
+ Flush(context);
+ other_bridge->Flush(context);
+ local_peer->Flush(context);
}
bool Router::BypassPeerWithNewRemoteLink(
+ const OperationContext& context,
RemoteRouterLink& requestor,
NodeLink& node_link,
SublinkId bypass_target_sublink,
@@ -1671,9 +2043,9 @@ bool Router::BypassPeerWithNewRemoteLink(
// RouterLinkState.
node_link.memory().AllocateRouterLinkState(
[router = WrapRefCounted(this), requestor = WrapRefCounted(&requestor),
- node_link = WrapRefCounted(&node_link),
+ node_link = WrapRefCounted(&node_link), context,
bypass_target_sublink](FragmentRef<RouterLinkState> new_link_state) {
- router->BypassPeerWithNewRemoteLink(*requestor, *node_link,
+ router->BypassPeerWithNewRemoteLink(context, *requestor, *node_link,
bypass_target_sublink,
std::move(new_link_state));
});
@@ -1700,16 +2072,16 @@ bool Router::BypassPeerWithNewRemoteLink(
length_to_decaying_link = outbound_parcels_.current_sequence_number();
outward_edge_.set_length_to_decaying_link(length_to_decaying_link);
- new_link = node_link.AddRemoteRouterLink(new_sublink, new_link_state,
- LinkType::kCentral, LinkSide::kA,
- WrapRefCounted(this));
+ new_link = node_link.AddRemoteRouterLink(
+ context, new_sublink, new_link_state, LinkType::kCentral, LinkSide::kA,
+ WrapRefCounted(this));
}
if (!new_link) {
// The NodeLink was disconnected before we could create a new link for
// this Router. This is not the requestor's fault, so it's not treated as
// an error.
- AcceptRouteDisconnectedFrom(LinkType::kCentral);
+ AcceptRouteDisconnectedFrom(context, LinkType::kCentral);
return true;
}
@@ -1729,11 +2101,12 @@ bool Router::BypassPeerWithNewRemoteLink(
// above message. Otherwise the router might race on another thread to send
// messages via `new_sublink`, and the remote node would have no idea where
// to route them.
- SetOutwardLink(std::move(new_link));
+ SetOutwardLink(context, std::move(new_link));
return true;
}
-bool Router::BypassPeerWithNewLocalLink(RemoteRouterLink& requestor,
+bool Router::BypassPeerWithNewLocalLink(const OperationContext& context,
+ RemoteRouterLink& requestor,
SublinkId bypass_target_sublink) {
NodeLink& from_node_link = *requestor.node_link();
const Ref<Router> new_local_peer =
@@ -1741,7 +2114,7 @@ bool Router::BypassPeerWithNewLocalLink(RemoteRouterLink& requestor,
if (!new_local_peer) {
// The peer may have already been destroyed or disconnected from the proxy
// by the time we get here.
- AcceptRouteDisconnectedFrom(LinkType::kPeripheralOutward);
+ AcceptRouteDisconnectedFrom(context, LinkType::kPeripheralOutward);
return true;
}
@@ -1789,11 +2162,11 @@ bool Router::BypassPeerWithNewLocalLink(RemoteRouterLink& requestor,
new_local_peer->outward_edge_.SetPrimaryLink(std::move(links.second));
}
- link_from_new_local_peer_to_proxy->StopProxying(length_from_proxy_to_us,
- length_to_proxy_from_us);
+ link_from_new_local_peer_to_proxy->StopProxying(
+ context, length_from_proxy_to_us, length_to_proxy_from_us);
- Flush();
- new_local_peer->Flush();
+ Flush(context);
+ new_local_peer->Flush(context);
return true;
}
diff --git a/chromium/third_party/ipcz/src/ipcz/router.h b/chromium/third_party/ipcz/src/ipcz/router.h
index 092e7a61583..eb43fb5f076 100644
--- a/chromium/third_party/ipcz/src/ipcz/router.h
+++ b/chromium/third_party/ipcz/src/ipcz/router.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include "ipcz/fragment_ref.h"
#include "ipcz/ipcz.h"
+#include "ipcz/operation_context.h"
#include "ipcz/parcel_queue.h"
#include "ipcz/route_edge.h"
#include "ipcz/router_descriptor.h"
@@ -23,6 +24,7 @@
namespace ipcz {
+class AtomicQueueState;
class NodeLink;
class RemoteRouterLink;
struct RouterLinkState;
@@ -104,7 +106,8 @@ class Router : public RefCounted {
// in active use by another Router, as `this` Router may already be in a
// transitional state and must be able to block decay around `link` from
// within this call.
- void SetOutwardLink(Ref<RouterLink> link);
+ void SetOutwardLink(const OperationContext& context,
+ const Ref<RouterLink> link);
// Returns a best-effort estimation of the maximum parcel size (in bytes) that
// can be sent outward from this router without the receiving portal exceeding
@@ -117,23 +120,27 @@ class Router : public RefCounted {
size_t GetInboundCapacityInBytes(const IpczPutLimits& limits);
// Accepts an inbound parcel from the outward edge of this router, either to
- // queue it for retrieval or forward it further inward.
- bool AcceptInboundParcel(Parcel& parcel);
+ // queue it for retrieval or forward it further inward. `source` indicates
+ // whether the parcel is arriving as a direct result of some local ipcz API
+ // call, or if it came from a remote node.
+ bool AcceptInboundParcel(const OperationContext& context, Parcel& parcel);
// Accepts an outbound parcel here from some other Router. The parcel is
// transmitted immediately or queued for later transmission over the Router's
// outward link. Called only on proxying Routers.
- bool AcceptOutboundParcel(Parcel& parcel);
+ bool AcceptOutboundParcel(const OperationContext& context, Parcel& parcel);
// Accepts notification that the other end of the route has been closed and
// that the closed end transmitted a total of `sequence_length` parcels before
- // closing.
- bool AcceptRouteClosureFrom(LinkType link_type,
+ // closing. `source` indicates whether the portal's peer was closed locally,
+ // or if we were notified of its closure from a remote node.
+ bool AcceptRouteClosureFrom(const OperationContext& context,
+ LinkType link_type,
SequenceNumber sequence_length);
- // Informs this router that its outward peer consumed some inbound parcels or
- // parcel data.
- void NotifyPeerConsumedData();
+ // Queries the remote peer's queue state and performs any local state upates
+ // needed to reflect it. `source` indicates why the snapshot is being taken.
+ void SnapshotPeerQueueState(const OperationContext& context);
// Accepts notification from a link bound to this Router that some node along
// the route (in the direction of that link) has been disconnected, e.g. due
@@ -142,14 +149,16 @@ class Router : public RefCounted {
// deliver the complete sequence of parcels transmitted from that end of the
// route. `link_type` specifies the type of link which is propagating the
// notification to this rouer.
- bool AcceptRouteDisconnectedFrom(LinkType link_type);
+ bool AcceptRouteDisconnectedFrom(const OperationContext& context,
+ LinkType link_type);
// Retrieves the next available inbound parcel from this Router, if present.
IpczResult GetNextInboundParcel(IpczGetFlags flags,
void* data,
size_t* num_bytes,
IpczHandle* handles,
- size_t* num_handles);
+ size_t* num_handles,
+ IpczHandle* validator);
// Begins a two-phase retrieval of the next available inbound parcel.
IpczResult BeginGetNextIncomingParcel(const void** data,
@@ -160,7 +169,8 @@ class Router : public RefCounted {
// consuming some (possibly all) bytes and handles from that parcel. Once a
// parcel is fully consumed, it's removed from the inbound queue.
IpczResult CommitGetNextIncomingParcel(size_t num_data_bytes_consumed,
- absl::Span<IpczHandle> handles);
+ absl::Span<IpczHandle> handles,
+ IpczHandle* validator);
// Attempts to install a new trap on this Router, to invoke `handler` as soon
// as one or more conditions in `conditions` is met. This method effectively
@@ -184,12 +194,15 @@ class Router : public RefCounted {
// Serializes a description of a new Router which will be used to extend this
// Router's route across `to_node_link` by introducing a new Router on the
// remote node.
- void SerializeNewRouter(NodeLink& to_node_link, RouterDescriptor& descriptor);
+ void SerializeNewRouter(const OperationContext& context,
+ NodeLink& to_node_link,
+ RouterDescriptor& descriptor);
// Configures this Router to begin proxying incoming parcels toward (and
// outgoing parcels from) the Router described by `descriptor`, living on the
// remote node of `to_node_link`.
- void BeginProxyingToNewRouter(NodeLink& to_node_link,
+ void BeginProxyingToNewRouter(const OperationContext& context,
+ NodeLink& to_node_link,
const RouterDescriptor& descriptor);
// Notifies this router that it should reach out to its outward peer's own
@@ -218,7 +231,8 @@ class Router : public RefCounted {
// invalid. Note that a return value of true does not necessarily imply that
// bypass was or will be successful (e.g. it may silently fail due to lost
// node connections).
- bool BypassPeer(RemoteRouterLink& requestor,
+ bool BypassPeer(const OperationContext& context,
+ RemoteRouterLink& requestor,
const NodeName& bypass_target_node,
SublinkId bypass_target_sublink);
@@ -242,6 +256,7 @@ class Router : public RefCounted {
// RouterLinkState's `allowed_bypass_request_source` field. This method
// authenticates the request accordingly.
bool AcceptBypassLink(
+ const OperationContext& context,
NodeLink& new_node_link,
SublinkId new_sublink,
FragmentRef<RouterLinkState> new_link_state,
@@ -254,7 +269,8 @@ class Router : public RefCounted {
//
// Returns true if and only if this router is a proxy with decaying inward and
// outward links. Otherwise returns false, indicating an invalid request.
- bool StopProxying(SequenceNumber inbound_sequence_length,
+ bool StopProxying(const OperationContext& context,
+ SequenceNumber inbound_sequence_length,
SequenceNumber outbound_sequence_length);
// Configures the final length of the inbound parcel sequence coming from the
@@ -265,7 +281,8 @@ class Router : public RefCounted {
// Returns true if this router has a decaying outward link -- implying that
// its outward peer is a proxy -- or the router has been disconnected.
// Otherwise the request is invalid and this returns false.
- bool NotifyProxyWillStop(SequenceNumber inbound_sequence_length);
+ bool NotifyProxyWillStop(const OperationContext& context,
+ SequenceNumber inbound_sequence_length);
// Configures the final sequence length of outbound parcels to expect on this
// proxying Router's decaying inward link. Once this is set and the decaying
@@ -273,7 +290,8 @@ class Router : public RefCounted {
//
// Returns true if the request is valid, meaning that this Router is a proxy
// whose outward peer is local to the same node. Otherwise this returns false.
- bool StopProxyingToLocalPeer(SequenceNumber outbound_sequence_length);
+ bool StopProxyingToLocalPeer(const OperationContext& context,
+ SequenceNumber outbound_sequence_length);
// Notifies this Router that one of its links has been disconnected from a
// remote node. The link is identified by a combination of a specific NodeLink
@@ -287,7 +305,8 @@ class Router : public RefCounted {
// For a proxying router which is generally only kept alive by the links
// which are bound to it, this call will typically be followed by imminent
// destruction of this Router once the caller releases its own reference.
- void NotifyLinkDisconnected(RemoteRouterLink& link);
+ void NotifyLinkDisconnected(const OperationContext& context,
+ RemoteRouterLink& link);
// Flushes any inbound or outbound parcels, as well as any route closure
// notifications. RouterLinks which are no longer needed for the operation of
@@ -309,12 +328,32 @@ class Router : public RefCounted {
// invoke Flush() may also elicit state changes that can unblock a bypass
// operation. These operatoins may specify kForceProxyBypassAttempt in such
// cases.
+ //
+ // `source` indicates why the flush is occurring.
enum FlushBehavior { kDefault, kForceProxyBypassAttempt };
- void Flush(FlushBehavior behavior = kDefault);
+ void Flush(const OperationContext& context,
+ FlushBehavior behavior = kDefault);
private:
~Router() override;
+ // Returns a handle to the outward peer's queue state, if available. Otherwise
+ // returns null.
+ AtomicQueueState* GetPeerQueueState() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+
+ // Updates the AtomicQueueState shared with this Router's outward peer, based
+ // on the current portal status. Any monitor bit set by the remote peer is
+ // reset, and this returns the value of that bit prior to the reset. If this
+ // returns true, the caller is responsible for notifying the remote peer about
+ // a state change.
+ [[nodiscard]] bool RefreshLocalQueueState()
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+
+ // Updates this Router's status to reflect how many parcels and total bytes of
+ // parcel data remain on the remote peer's inbound queue.
+ void UpdateStatusForPeerQueueState(const AtomicQueueState::QueryResult& state)
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+
// Attempts to initiate bypass of this router by its peers, and ultimately to
// remove this router from its route.
//
@@ -322,7 +361,7 @@ class Router : public RefCounted {
// last decaying link, or if Flush() was called with kForceProxyBypassAttempt,
// indicating that some significant state has changed on the route which might
// unblock our bypass.
- bool MaybeStartSelfBypass();
+ bool MaybeStartSelfBypass(const OperationContext& context);
// Starts bypass of this Router when its outward peer lives on the same node.
// This must only be called once the central link is already locked. If
@@ -333,7 +372,8 @@ class Router : public RefCounted {
// Returns true if and only if self-bypass has been initiated by reaching out
// to this router's inward peer with with a BypassPeer() or
// BypassPeerWithLink() request. Otherwise returns false.
- bool StartSelfBypassToLocalPeer(Router& local_outward_peer,
+ bool StartSelfBypassToLocalPeer(const OperationContext& context,
+ Router& local_outward_peer,
RemoteRouterLink& inward_link,
FragmentRef<RouterLinkState> new_link_state);
@@ -342,7 +382,7 @@ class Router : public RefCounted {
// other side. This method will attempt to lock this Router's outward link as
// well as the outward link of this Router's bridge peer. If either fails,
// both are left unlocked and this operation cannot yet proceed.
- void MaybeStartBridgeBypass();
+ void MaybeStartBridgeBypass(const OperationContext& context);
// Starts bypass of this Router, which must be on a bridge link and must have
// a local outward peer link. The router on the other side of the bridge must
@@ -350,7 +390,8 @@ class Router : public RefCounted {
// establish a new remote link to that peer to bypass the entire bridge. If
// `link_state` is null, the operation will be deferred until a fragment can
// be allocated.
- void StartBridgeBypassFromLocalPeer(FragmentRef<RouterLinkState> link_state);
+ void StartBridgeBypassFromLocalPeer(const OperationContext& context,
+ FragmentRef<RouterLinkState> link_state);
// Attempts to bypass the link identified by `requestor` in favor of a new
// link that runs over `node_link`. If `new_link_state` is non-null, it will
@@ -358,7 +399,8 @@ class Router : public RefCounted {
// will be allocated asynchronously before proceeding.
//
// Returns true if and only if this request was valid.
- bool BypassPeerWithNewRemoteLink(RemoteRouterLink& requestor,
+ bool BypassPeerWithNewRemoteLink(const OperationContext& context,
+ RemoteRouterLink& requestor,
NodeLink& node_link,
SublinkId bypass_target_sublink,
FragmentRef<RouterLinkState> new_link_state);
@@ -368,15 +410,42 @@ class Router : public RefCounted {
// NodeLink as `requestor`.
//
// Returns true if and only if this request was valid.
- bool BypassPeerWithNewLocalLink(RemoteRouterLink& requestor,
+ bool BypassPeerWithNewLocalLink(const OperationContext& context,
+ RemoteRouterLink& requestor,
SublinkId bypass_target_sublink);
+ // Optimized Router serialization case when the Router's peer is local to the
+ // same node and the existing (local) central link can be replaced with a new
+ // remote link, without establishing an intermediate proxy. Returns true on
+ // success, or false indicating that the caller must fall back onto the slower
+ // Router serialization path defined below.
+ bool SerializeNewRouterWithLocalPeer(const OperationContext& context,
+ NodeLink& to_node_link,
+ RouterDescriptor& descriptor,
+ Ref<Router> local_peer);
+
+ // Default Router serialization case when the serializing Router must stay
+ // behind as an intermediate proxy between its (remote) peer and the newly
+ // established Router that will result from this serialization. As an
+ // optimization, `initiate_proxy_bypass` may be true if the serializing router
+ // is on the central link and was able to lock that link for bypass prior to
+ // serialization.
+ void SerializeNewRouterAndConfigureProxy(const OperationContext& context,
+ NodeLink& to_node_link,
+ RouterDescriptor& descriptor,
+ bool initiate_proxy_bypass);
+
absl::Mutex mutex_;
// The current computed portal status to be reflected by a portal controlling
// this router, iff this is a terminal router.
IpczPortalStatus status_ ABSL_GUARDED_BY(mutex_) = {sizeof(status_)};
+ // A local cache of the most recently stored value for our own local
+ // AtomicQueueState.
+ absl::optional<AtomicQueueState::UpdateValue> last_queue_update_
+ ABSL_GUARDED_BY(mutex_);
+
// A set of traps installed via a controlling portal where applicable. These
// traps are notified about any interesting state changes within the router.
TrapSet traps_ ABSL_GUARDED_BY(mutex_);
diff --git a/chromium/third_party/ipcz/src/ipcz/router_descriptor.cc b/chromium/third_party/ipcz/src/ipcz/router_descriptor.cc
index 3e0676a8674..4dbfbe39d2c 100644
--- a/chromium/third_party/ipcz/src/ipcz/router_descriptor.cc
+++ b/chromium/third_party/ipcz/src/ipcz/router_descriptor.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/router_descriptor.h b/chromium/third_party/ipcz/src/ipcz/router_descriptor.h
index 2e472ed2443..9cb539b0d57 100644
--- a/chromium/third_party/ipcz/src/ipcz/router_descriptor.h
+++ b/chromium/third_party/ipcz/src/ipcz/router_descriptor.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -31,18 +31,45 @@ struct IPCZ_ALIGN(8) RouterDescriptor {
// end.
SequenceNumber closed_peer_sequence_length;
- // A new sublink and RouterLinkState fragment allocated by the sender on the
- // NodeLink which sends this descriptor. The sublink is used as a peripheral
- // link, inward to (and outward from) the new router.
+ // A new sublink allocated by the sender on the NodeLink which sends this
+ // descriptor. The sublink may be used as a peripheral link, inward to (and
+ // outward from) the new router, or it may be used the route's central link
+ // if and only if `proxy_already_bypassed` is true below. In the latter case,
+ // `new_link_state_fragment` must be valid and is used as the new central
+ // link's RouterLinkState.
SublinkId new_sublink;
+ FragmentDescriptor new_link_state_fragment;
+
+ // When `proxy_already_bypassed` is true below, this is another new sublink
+ // allocated by the sender on the NodeLink which sends this descriptor. This
+ // sublink is used as peripheral link to the new router's outward -- peer back
+ // on the sending node -- as a way for that router to forward any inbound
+ // parcels that were still queued or in flight when this router was
+ // serialized.
+ SublinkId new_decaying_sublink;
// The SequenceNumber of the next outbound parcel which can be produced by
// this router.
SequenceNumber next_outgoing_sequence_number;
+ // The total number of outgoing bytes produced by the router's portal so far.
+ uint64_t num_bytes_produced;
+
// The SequenceNumber of the next inbound parcel expected by this router.
SequenceNumber next_incoming_sequence_number;
+ // The total length of the sequence of parcels expected on the decaying link
+ // established by `new_decaying_sublink`, if and only if
+ // `proxy_already_bypassed` is true. The decaying link is expected to receive
+ // only parcels between `next_incoming_sequence_number` (inclusive) and
+ // `decaying_incoming_sequence_length` (exclusive). If those fields are equal
+ // then the decaying link should be ignored and `new_decaying_sublink` may
+ // not be valid.
+ SequenceNumber decaying_incoming_sequence_length;
+
+ // The total number of incoming bytes consumed from router's portal so far.
+ uint64_t num_bytes_consumed;
+
// Indicates that the other end of the route is already known to be closed.
// In this case sending any new outbound parcels from this router would be
// pointless, but there may still be in-flight parcels to receive from the
@@ -50,6 +77,27 @@ struct IPCZ_ALIGN(8) RouterDescriptor {
// parcels sent from that end, and `next_incoming_sequence_number` can be used
// to determine whether there are any parcels left to receive.
bool peer_closed : 1;
+
+ // Indicates that, as an optimization, the sender was able to circumvent the
+ // usual process of first establishing a peripheral link and then initiating
+ // proxy bypass. Instead the outward peer of this new router is already
+ // configured to route messages directly to the new router, and its former
+ // (and local) outward peer is configured to proxy any previously queued or
+ // in-flight messages to us over the decaying link described above.
+ bool proxy_already_bypassed : 1;
+
+ // Reserved padding out to the next 8-byte boundary.
+ uint8_t reserved0[7];
+
+ // These fields are set if and only if proxy bypass should be initiated
+ // immediately on deserialization of the new Router. The deserializing node
+ // must contact `proxy_peer_node_name` with the name of the node who sent this
+ // descriptor, along with `proxy_peer_sublink` (an existing sublink
+ // between those two nodes, identifying the link we want to bypass). These
+ // fields may be set as an optimization to avoid additional messaging overhead
+ // in the common case of transferring a yet-unused portal.
+ NodeName proxy_peer_node_name;
+ SublinkId proxy_peer_sublink;
};
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/router_link.h b/chromium/third_party/ipcz/src/ipcz/router_link.h
index fb5ae27486c..a8031b3a2c0 100644
--- a/chromium/third_party/ipcz/src/ipcz/router_link.h
+++ b/chromium/third_party/ipcz/src/ipcz/router_link.h
@@ -1,13 +1,20 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IPCZ_SRC_IPCZ_ROUTER_LINK_H_
#define IPCZ_SRC_IPCZ_ROUTER_LINK_H_
+#include <cstddef>
+#include <functional>
+#include <string>
+#include <utility>
+
+#include "ipcz/atomic_queue_state.h"
#include "ipcz/fragment_ref.h"
#include "ipcz/link_type.h"
#include "ipcz/node_name.h"
+#include "ipcz/operation_context.h"
#include "ipcz/router_link_state.h"
#include "ipcz/sequence_number.h"
#include "ipcz/sublink_id.h"
@@ -39,6 +46,10 @@ class RouterLink : public RefCounted {
// returns null.
virtual RouterLinkState* GetLinkState() const = 0;
+ // Runs `callback` as soon as this RouterLink has a RouterLinkState. If the
+ // link already has a RouterLinkState then `callback` is invoked immediately.
+ virtual void WaitForLinkStateAsync(std::function<void()> callback) = 0;
+
// Returns the Router on the other end of this link, if this is a
// LocalRouterLink. Otherwise returns null.
virtual Ref<Router> GetLocalPeer() = 0;
@@ -59,43 +70,33 @@ class RouterLink : public RefCounted {
// Passes a parcel to the Router on the other side of this link to be queued
// and/or router further.
- virtual void AcceptParcel(Parcel& parcel) = 0;
+ virtual void AcceptParcel(const OperationContext& context,
+ Parcel& parcel) = 0;
// Notifies the Router on the other side of the link that the route has been
// closed from this side. `sequence_length` is the total number of parcels
// transmitted from the closed side before it was closed.
- virtual void AcceptRouteClosure(SequenceNumber sequence_length) = 0;
+ virtual void AcceptRouteClosure(const OperationContext& context,
+ SequenceNumber sequence_length) = 0;
// Notifies the Router on the other side of the link that the route has been
// unexpectedly disconnected from this side. Unlike clean route closure above,
// in this case we don't know the final sequence length and can't guarantee
// delivery of any further parcels.
- virtual void AcceptRouteDisconnected() = 0;
-
- // Returns a best-effort estimation of how much new parcel data can be
- // transmitted across the link before one or more limits described by `limits`
- // would be exceeded on the receiving portal.
- virtual size_t GetParcelCapacityInBytes(const IpczPutLimits& limits) = 0;
+ virtual void AcceptRouteDisconnected(const OperationContext& context) = 0;
- // Returns a best-effort snapshot of the last known state of the inbound
- // parcel queue on the other side of this link. This is only meaningful for
- // central links.
- virtual RouterLinkState::QueueState GetPeerQueueState() = 0;
-
- // Updates the QueueState for this side of the link, returning true if and
- // only if the other side wants to be notified about the update.
- virtual bool UpdateInboundQueueState(size_t num_parcels,
- size_t num_bytes) = 0;
+ // Returns the AtomicQueueState for the other side of this link if available.
+ // Otherwise returns null.
+ virtual AtomicQueueState* GetPeerQueueState() = 0;
- // Notifies the other side that this side has consumed some parcels or parcel
- // data from its inbound queue. Should only be called on central links when
- // the other side has expressed interest in such notifications.
- virtual void NotifyDataConsumed() = 0;
+ // Returns the AtomicQueueState for this side of the link if available.
+ // Otherwise returns null.
+ virtual AtomicQueueState* GetLocalQueueState() = 0;
- // Controls whether the caller's side of the link is interested in being
- // notified about data consumption on the opposite side of the link. Returns
- // the previous value of this bit.
- virtual bool EnablePeerMonitoring(bool enable) = 0;
+ // Notifies the other side that this side has updated its visible queue state
+ // in some way which may be interesting to them. This should be called
+ // sparingly to avoid redundant IPC traffic and redundant idle wakes.
+ virtual void SnapshotPeerQueueState(const OperationContext& context) = 0;
// Signals that this side of the link is in a stable state suitable for one
// side or the other to lock the link, either for bypass or closure
@@ -130,7 +131,7 @@ class RouterLink : public RefCounted {
// itself as waiting for both sides of the link to become stable, and both
// sides of the link are stable. Returns true if and only if a flush was
// actually issued to the other side.
- virtual bool FlushOtherSideIfWaiting() = 0;
+ virtual bool FlushOtherSideIfWaiting(const OperationContext& context) = 0;
// Indicates whether this link can be bypassed by a request from the named
// node to one side of the link. True if and only if the proxy on the other
@@ -142,7 +143,8 @@ class RouterLink : public RefCounted {
// on this side. `bypass_target_node` is the name node where the router's
// outward peer lives, and `bypass_target_sublink` identifies the link between
// that router and the router on the other side of this link.
- virtual void BypassPeer(const NodeName& bypass_target_node,
+ virtual void BypassPeer(const OperationContext& context,
+ const NodeName& bypass_target_node,
SublinkId bypass_target_sublink) = 0;
// Informs the router on the other side of this link about when it can drop
@@ -152,14 +154,16 @@ class RouterLink : public RefCounted {
// `outbound_sequence_length` is the final length of the parcel sequence the
// router must expect to receive from its inward peer and forward to its
// outward peer.
- virtual void StopProxying(SequenceNumber inbound_sequence_length,
+ virtual void StopProxying(const OperationContext& context,
+ SequenceNumber inbound_sequence_length,
SequenceNumber outbound_sequence_length) = 0;
// Informs the router on the other side of this link that the router it most
// recently bypassed will stop sending it parcels once the router's inbound
// sequence length reaches `inbound_sequence_length`, at which point the
// router's link to the proxy can be dropped.
- virtual void ProxyWillStop(SequenceNumber inbound_sequence_length) = 0;
+ virtual void ProxyWillStop(const OperationContext& context,
+ SequenceNumber inbound_sequence_length) = 0;
// Informs the router on the other side of this link that its outward peer
// (and the router on this side of this link) can be bypassed, and provides a
@@ -167,7 +171,8 @@ class RouterLink : public RefCounted {
// `new_link_state` is a freshly allocated RouterLinkState fragment for the
// new link, and `inbound_sequence_length` is the current inbound sequence
// length of the router on this side of the link.
- virtual void BypassPeerWithLink(SublinkId new_sublink,
+ virtual void BypassPeerWithLink(const OperationContext& context,
+ SublinkId new_sublink,
FragmentRef<RouterLinkState> new_link_state,
SequenceNumber inbound_sequence_length) = 0;
@@ -179,6 +184,7 @@ class RouterLink : public RefCounted {
// router on this side of the link at the moment it switches to the new link
// for its outward transmissions.
virtual void StopProxyingToLocalPeer(
+ const OperationContext& context,
SequenceNumber outbound_sequence_length) = 0;
// Deactivates this RouterLink to sever any binding it may have to a specific
diff --git a/chromium/third_party/ipcz/src/ipcz/router_link_state.cc b/chromium/third_party/ipcz/src/ipcz/router_link_state.cc
index 70e842dc0c8..441b6d4720c 100644
--- a/chromium/third_party/ipcz/src/ipcz/router_link_state.cc
+++ b/chromium/third_party/ipcz/src/ipcz/router_link_state.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -125,38 +125,8 @@ bool RouterLinkState::ResetWaitingBit(LinkSide side) {
return true;
}
-RouterLinkState::QueueState RouterLinkState::GetQueueState(
- LinkSide side) const {
- return {
- .num_parcels = SelectBySide(side, num_parcels_on_a, num_parcels_on_b)
- .load(std::memory_order_relaxed),
- .num_bytes = SelectBySide(side, num_bytes_on_a, num_bytes_on_b)
- .load(std::memory_order_relaxed),
- };
-}
-
-bool RouterLinkState::UpdateQueueState(LinkSide side,
- size_t num_parcels,
- size_t num_bytes) {
- StoreSaturated(SelectBySide(side, num_parcels_on_a, num_parcels_on_b),
- num_parcels);
- StoreSaturated(SelectBySide(side, num_bytes_on_a, num_bytes_on_b), num_bytes);
- const uint32_t other_side_monitoring_this_side =
- SelectBySide(side, kSideBMonitoringSideA, kSideAMonitoringSideB);
- return (status.load(std::memory_order_relaxed) &
- other_side_monitoring_this_side) != 0;
-}
-
-bool RouterLinkState::SetSideIsMonitoringPeer(LinkSide side,
- bool is_monitoring) {
- const uint32_t monitoring_bit =
- SelectBySide(side, kSideAMonitoringSideB, kSideBMonitoringSideA);
- uint32_t expected = kStable;
- while (!status.compare_exchange_weak(expected, expected | monitoring_bit,
- std::memory_order_relaxed,
- std::memory_order_relaxed)) {
- }
- return (expected & monitoring_bit) != 0;
+AtomicQueueState& RouterLinkState::GetQueueState(LinkSide side) {
+ return SelectBySide(side, side_a_queue_state, side_b_queue_state);
}
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/router_link_state.h b/chromium/third_party/ipcz/src/ipcz/router_link_state.h
index 0d1ae54e1b0..b6336887737 100644
--- a/chromium/third_party/ipcz/src/ipcz/router_link_state.h
+++ b/chromium/third_party/ipcz/src/ipcz/router_link_state.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include <cstdint>
#include <type_traits>
+#include "ipcz/atomic_queue_state.h"
#include "ipcz/ipcz.h"
#include "ipcz/link_side.h"
#include "ipcz/node_name.h"
@@ -62,13 +63,6 @@ struct IPCZ_ALIGN(8) RouterLinkState : public RefCountedFragment {
static constexpr Status kLockedBySideA = 1 << 4;
static constexpr Status kLockedBySideB = 1 << 5;
- // Set if the link on either side A or B wishes to be notified when parcels
- // or parcel data are consumed by the other side. In practice these are only
- // set when a router has a trap installed to monitor such conditions, which
- // applications may leverage to e.g. implement a back-pressure mechanism.
- static constexpr Status kSideAMonitoringSideB = 1 << 6;
- static constexpr Status kSideBMonitoringSideA = 1 << 7;
-
std::atomic<Status> status{kUnstable};
// In a situation with three routers A-B-C and a central link between A and
@@ -78,16 +72,14 @@ struct IPCZ_ALIGN(8) RouterLinkState : public RefCountedFragment {
// validate that C is an appropriate source of such a bypass request.
NodeName allowed_bypass_request_source;
- // These fields approximate the number of parcels and data bytes received and
- // queued for retrieval on each side of this link. Values here are saturated
- // if the actual values would exceed the max uint32_t value.
- std::atomic<uint32_t> num_parcels_on_a{0};
- std::atomic<uint32_t> num_bytes_on_a{0};
- std::atomic<uint32_t> num_parcels_on_b{0};
- std::atomic<uint32_t> num_bytes_on_b{0};
+ // An approximation of the queue state on each side of the link. These are
+ // used both for best-effort querying of remote conditions as well as for
+ // reliable synchronization against remote activity.
+ AtomicQueueState side_a_queue_state;
+ AtomicQueueState side_b_queue_state;
// More reserved slots, padding out this structure to 64 bytes.
- uint32_t reserved1[6] = {0};
+ uint32_t reserved1[2] = {0};
bool is_locked_by(LinkSide side) const {
Status s = status.load(std::memory_order_relaxed);
@@ -124,24 +116,9 @@ struct IPCZ_ALIGN(8) RouterLinkState : public RefCountedFragment {
// still unstable.
bool ResetWaitingBit(LinkSide side);
- // Returns a snapshot of the inbound parcel queue state on the given side of
+ // Returns a view of the inbound parcel queue state for the given `side` of
// this link.
- struct QueueState {
- uint32_t num_parcels;
- uint32_t num_bytes;
- };
- QueueState GetQueueState(LinkSide side) const;
-
- // Updates the queue state for the given side of this link. Values which
- // exceed 2**32-1 are clamped to that value. Returns true if and only if the
- // opposite side of the link wants to be notified about this update.
- bool UpdateQueueState(LinkSide side, size_t num_parcels, size_t num_bytes);
-
- // Sets an appropriate bit to indicate whether the router on the given side of
- // this link should notify the opposite side after consuming inbound parcels
- // or parcel data. Returns the previous value of the relevant bit, which may
- // be the same as the old value.
- bool SetSideIsMonitoringPeer(LinkSide side, bool is_monitoring);
+ AtomicQueueState& GetQueueState(LinkSide side);
};
// The size of this structure is fixed at 64 bytes to ensure that it fits the
diff --git a/chromium/third_party/ipcz/src/ipcz/router_link_test.cc b/chromium/third_party/ipcz/src/ipcz/router_link_test.cc
index a90dffea75d..36c23ffa78e 100644
--- a/chromium/third_party/ipcz/src/ipcz/router_link_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/router_link_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -17,6 +17,7 @@
#include "ipcz/node.h"
#include "ipcz/node_link.h"
#include "ipcz/node_name.h"
+#include "ipcz/operation_context.h"
#include "ipcz/remote_router_link.h"
#include "ipcz/router.h"
#include "ipcz/router_link_state.h"
@@ -58,8 +59,9 @@ class TestNodePair {
node_b_, LinkSide::kB, kTestNonBrokerName, kTestBrokerName,
Node::Type::kBroker, 0, transports.second,
NodeLinkMemory::Create(node_b_, buffer.memory.Map()));
- node_a_->AddLink(kTestNonBrokerName, node_link_a_);
- node_b_->AddLink(kTestBrokerName, node_link_b_);
+ node_a_->AddConnection(kTestNonBrokerName, {.link = node_link_a_});
+ node_b_->AddConnection(kTestBrokerName,
+ {.link = node_link_b_, .broker = node_link_b_});
}
~TestNodePair() {
@@ -84,13 +86,17 @@ class TestNodePair {
FragmentRef<RouterLinkState> a_state,
Ref<Router> b,
FragmentRef<RouterLinkState> b_state) {
+ // The choice of OperationContext is arbitrary and irrelevant for this test.
+ const OperationContext context{OperationContext::kTransportNotification};
const SublinkId sublink = node_link_a_->memory().AllocateSublinkIds(1);
- Ref<RemoteRouterLink> a_link = node_link_a_->AddRemoteRouterLink(
- sublink, std::move(a_state), LinkType::kCentral, LinkSide::kA, a);
- Ref<RemoteRouterLink> b_link = node_link_b_->AddRemoteRouterLink(
- sublink, std::move(b_state), LinkType::kCentral, LinkSide::kB, b);
- a->SetOutwardLink(a_link);
- b->SetOutwardLink(b_link);
+ Ref<RemoteRouterLink> a_link =
+ node_link_a_->AddRemoteRouterLink(context, sublink, std::move(a_state),
+ LinkType::kCentral, LinkSide::kA, a);
+ Ref<RemoteRouterLink> b_link =
+ node_link_b_->AddRemoteRouterLink(context, sublink, std::move(b_state),
+ LinkType::kCentral, LinkSide::kB, b);
+ a->SetOutwardLink(context, a_link);
+ b->SetOutwardLink(context, b_link);
return {a_link, b_link};
}
@@ -125,12 +131,14 @@ class RouterLinkTest : public testing::Test,
public testing::WithParamInterface<RouterLinkTestMode> {
public:
void SetUp() override {
+ // The choice of OperationContext is arbitrary and irrelevant for this test.
+ const OperationContext context{OperationContext::kTransportNotification};
switch (GetParam()) {
case RouterLinkTestMode::kLocal:
std::tie(a_link_, b_link_) =
LocalRouterLink::CreatePair(LinkType::kCentral, {a_, b_});
- a_->SetOutwardLink(a_link_);
- b_->SetOutwardLink(b_link_);
+ a_->SetOutwardLink(context, a_link_);
+ b_->SetOutwardLink(context, b_link_);
break;
case RouterLinkTestMode::kRemote: {
@@ -222,9 +230,11 @@ TEST_P(RouterLinkTest, FlushOtherSideIfWaiting) {
link_state().status = RouterLinkState::kUnstable;
// FlushOtherSideIfWaiting() does nothing if the other side is not, in fact,
- // waiting for something.
- EXPECT_FALSE(a_link().FlushOtherSideIfWaiting());
- EXPECT_FALSE(b_link().FlushOtherSideIfWaiting());
+ // waiting for something. The choice of OperationContext is arbitrary and
+ // irrelevant for this test.
+ const OperationContext context{OperationContext::kTransportNotification};
+ EXPECT_FALSE(a_link().FlushOtherSideIfWaiting(context));
+ EXPECT_FALSE(b_link().FlushOtherSideIfWaiting(context));
EXPECT_EQ(RouterLinkState::kUnstable, link_status());
// Mark B stable and try to lock the link. Since A is not yet stable, this
@@ -239,7 +249,7 @@ TEST_P(RouterLinkTest, FlushOtherSideIfWaiting) {
a_link().MarkSideStable();
EXPECT_EQ(RouterLinkState::kStable | RouterLinkState::kSideBWaiting,
link_status());
- EXPECT_TRUE(a_link().FlushOtherSideIfWaiting());
+ EXPECT_TRUE(a_link().FlushOtherSideIfWaiting(context));
EXPECT_EQ(RouterLinkState::kStable, link_status());
}
diff --git a/chromium/third_party/ipcz/src/ipcz/sequence_number.h b/chromium/third_party/ipcz/src/ipcz/sequence_number.h
index 7400faf1a56..189049cc2b2 100644
--- a/chromium/third_party/ipcz/src/ipcz/sequence_number.h
+++ b/chromium/third_party/ipcz/src/ipcz/sequence_number.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/sequenced_queue.h b/chromium/third_party/ipcz/src/ipcz/sequenced_queue.h
index c2de7f75cd5..860e0887063 100644
--- a/chromium/third_party/ipcz/src/ipcz/sequenced_queue.h
+++ b/chromium/third_party/ipcz/src/ipcz/sequenced_queue.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,11 +6,13 @@
#define IPCZ_SRC_IPCZ_SEQUENCED_QUEUE_H_
#include <cstddef>
+#include <cstdint>
#include <vector>
#include "ipcz/sequence_number.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "util/safe_math.h"
namespace ipcz {
@@ -90,6 +92,11 @@ class SequencedQueue {
return base_sequence_number_;
}
+ // The total size of all element from this queue so far.
+ uint64_t total_consumed_element_size() const {
+ return total_consumed_element_size_;
+ }
+
// The final length of the sequence that can be popped from this queue. Null
// if a final length has not yet been set. If the final length is N, then the
// last ordered element that can be pushed to or popped from the queue has a
@@ -124,6 +131,13 @@ class SequencedQueue {
return entries_[0]->total_span_size;
}
+ // Returns the total size of all elements previously popped from this queue,
+ // plus the total size of all elemenets currently ready for popping.
+ uint64_t GetTotalElementSizeQueuedSoFar() const {
+ return CheckAdd(total_consumed_element_size_,
+ static_cast<uint64_t>(GetTotalAvailableElementSize()));
+ }
+
// Returns the total length of the contiguous sequence already pushed and/or
// popped from this queue so far. This is essentially
// `current_sequence_number()` plus `GetNumAvailableElements()`. If
@@ -213,24 +227,29 @@ class SequencedQueue {
return !HasNextElement() && !ExpectsMoreElements();
}
- // Resets this queue to start at the initial SequenceNumber `n`. Must be
- // called only on an empty queue and only when the caller can be sure they
- // won't want to push any elements with a SequenceNumber below `n`.
- void ResetInitialSequenceNumber(SequenceNumber n) {
+ // Resets this queue to a state which behaves as if a sequence of parcels of
+ // length `n` has already been pushed and popped from the queue, with a total
+ // cumulative element size of `total_consumed_element_size`. Must be called
+ // only on an empty queue and only when the caller can be sure they won't want
+ // to push any elements with a SequenceNumber below `n`.
+ void ResetSequence(SequenceNumber n, uint64_t total_consumed_element_size) {
ABSL_ASSERT(num_entries_ == 0);
base_sequence_number_ = n;
+ total_consumed_element_size_ = total_consumed_element_size;
}
// Attempts to skip SequenceNumber `n` in the sequence by advancing the
// current SequenceNumber by one. Returns true on success and false on
- // failure.
+ // failure. `element_size` is the size of the skipped element as it would have
+ // been reported by ElementTraits::GetElementSize() if the element in question
+ // were actually pushed into the queue.
//
// This can only succeed when `current_sequence_number()` is equal to `n`, no
- // entry for SequenceNumber `n` is already in the queue, and the `n` is less
+ // entry for SequenceNumber `n` is already in the queue, and n` is less than
// the final sequence length if applicable. Success is equivalent to pushing
// and immediately popping element `n` except that it does not grow, shrink,
// or otherwise modify the queue's underlying storage.
- bool MaybeSkipSequenceNumber(SequenceNumber n) {
+ bool SkipElement(SequenceNumber n, size_t element_size) {
if (base_sequence_number_ != n || HasNextElement() ||
(final_sequence_length_ && *final_sequence_length_ <= n)) {
return false;
@@ -240,6 +259,8 @@ class SequencedQueue {
if (num_entries_ != 0) {
entries_.remove_prefix(1);
}
+ total_consumed_element_size_ = CheckAdd(
+ total_consumed_element_size_, static_cast<uint64_t>(element_size));
return true;
}
@@ -307,13 +328,13 @@ class SequencedQueue {
base_sequence_number_ = SequenceNumber{base_sequence_number_.value() + 1};
// Make sure the next queued entry has up-to-date accounting, if present.
+ const size_t element_size = ElementTraits::GetElementSize(element);
if (entries_.size() > 1 && entries_[1]) {
Entry& next = *entries_[1];
next.span_start = head.span_start;
next.span_end = head.span_end;
next.num_entries_in_span = head.num_entries_in_span - 1;
- next.total_span_size =
- head.total_span_size - ElementTraits::GetElementSize(element);
+ next.total_span_size = head.total_span_size - element_size;
size_t tail_index = next.span_end.value() - sequence_number.value();
if (tail_index > 1) {
@@ -333,6 +354,8 @@ class SequencedQueue {
entries_ = EntryView(storage_.data(), entries_.size());
}
+ total_consumed_element_size_ = CheckAdd(
+ total_consumed_element_size_, static_cast<uint64_t>(element_size));
return true;
}
@@ -344,10 +367,16 @@ class SequencedQueue {
}
protected:
- void ReduceNextElementSize(size_t amount) {
+ // Adjusts the recorded size of the element at the head of this queue, as if
+ // the element were partially consumed. After this call, the value returned by
+ // GetTotalAvailableElementSize() will be decreased by `amount`, and the value
+ // returned by total_consumed_element_size() will increase by the same.
+ void PartiallyConsumeNextElement(size_t amount) {
ABSL_ASSERT(HasNextElement());
ABSL_ASSERT(entries_[0]->total_span_size >= amount);
entries_[0]->total_span_size -= amount;
+ total_consumed_element_size_ =
+ CheckAdd(total_consumed_element_size_, static_cast<uint64_t>(amount));
}
private:
@@ -556,6 +585,10 @@ class SequencedQueue {
// The number of slots in `entries_` which are actually occupied.
size_t num_entries_ = 0;
+ // Tracks the sum of the element sizes of every element fully or partially
+ // consumed from the queue so far.
+ uint64_t total_consumed_element_size_ = 0;
+
// The final length of the sequence to be enqueued, if known.
absl::optional<SequenceNumber> final_sequence_length_;
};
diff --git a/chromium/third_party/ipcz/src/ipcz/sequenced_queue_test.cc b/chromium/third_party/ipcz/src/ipcz/sequenced_queue_test.cc
index 54ed16f9a0e..2b5113e126a 100644
--- a/chromium/third_party/ipcz/src/ipcz/sequenced_queue_test.cc
+++ b/chromium/third_party/ipcz/src/ipcz/sequenced_queue_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -181,35 +181,66 @@ TEST(SequencedQueueTest, FullyConsumed) {
EXPECT_TRUE(q.IsSequenceFullyConsumed());
}
-TEST(SequencedQueueTest, MaybeSkipSequenceNumber) {
- TestQueue q;
+TEST(SequencedQueueTest, SkipElement) {
+ TestQueueWithSize q;
const std::string kEntry = "woot";
- EXPECT_TRUE(q.MaybeSkipSequenceNumber(SequenceNumber(0)));
- EXPECT_FALSE(q.MaybeSkipSequenceNumber(SequenceNumber(0)));
+ constexpr size_t kTestElementSize = 42;
+
+ // Skipping an element should update accounting appropriately.
+ EXPECT_TRUE(q.SkipElement(SequenceNumber(0), kTestElementSize));
+ EXPECT_EQ(0u, q.GetTotalAvailableElementSize());
+ EXPECT_EQ(kTestElementSize, q.GetTotalElementSizeQueuedSoFar());
+
+ // We can't skip or push an element that's already been skipped.
+ EXPECT_FALSE(q.SkipElement(SequenceNumber(0), kTestElementSize));
EXPECT_FALSE(q.Push(SequenceNumber(0), kEntry));
+
+ // And we can't skip an element that's already been pushed.
EXPECT_TRUE(q.Push(SequenceNumber(1), kEntry));
- EXPECT_FALSE(q.MaybeSkipSequenceNumber(SequenceNumber(1)));
+ EXPECT_FALSE(q.SkipElement(SequenceNumber(1), 7));
+ EXPECT_EQ(kEntry.size(), q.GetTotalAvailableElementSize());
+ EXPECT_EQ(kEntry.size() + kTestElementSize,
+ q.GetTotalElementSizeQueuedSoFar());
std::string s;
EXPECT_TRUE(q.Pop(s));
+ EXPECT_EQ(0u, q.GetTotalAvailableElementSize());
+ EXPECT_EQ(kEntry.size() + kTestElementSize,
+ q.GetTotalElementSizeQueuedSoFar());
- // Skip ahead to SequenceNumber 4.
- EXPECT_TRUE(q.MaybeSkipSequenceNumber(SequenceNumber(2)));
- EXPECT_TRUE(q.MaybeSkipSequenceNumber(SequenceNumber(3)));
+ // Skip ahead past SequenceNumber 2 and 3.
+ EXPECT_TRUE(q.SkipElement(SequenceNumber(2), kTestElementSize));
+ EXPECT_EQ(0u, q.GetTotalAvailableElementSize());
+ EXPECT_EQ(kEntry.size() + kTestElementSize * 2,
+ q.GetTotalElementSizeQueuedSoFar());
+ EXPECT_TRUE(q.SkipElement(SequenceNumber(3), kTestElementSize));
+ EXPECT_EQ(0u, q.GetTotalAvailableElementSize());
+ EXPECT_EQ(kEntry.size() + kTestElementSize * 3,
+ q.GetTotalElementSizeQueuedSoFar());
+
+ // SequenceNumber 4 can now be pushed while 2 and 3 cannot.
EXPECT_FALSE(q.Push(SequenceNumber(2), kEntry));
EXPECT_FALSE(q.Push(SequenceNumber(3), kEntry));
EXPECT_TRUE(q.Push(SequenceNumber(4), kEntry));
- EXPECT_FALSE(q.MaybeSkipSequenceNumber(SequenceNumber(4)));
+ EXPECT_FALSE(q.SkipElement(SequenceNumber(4), kTestElementSize));
+ EXPECT_EQ(kEntry.size(), q.GetTotalAvailableElementSize());
+ EXPECT_EQ(kEntry.size() * 2 + kTestElementSize * 3,
+ q.GetTotalElementSizeQueuedSoFar());
+ // Cap the sequence at 6 elements and verify that accounting remains intact
+ // when we skip the last element.
EXPECT_TRUE(q.SetFinalSequenceLength(SequenceNumber(6)));
EXPECT_FALSE(q.IsSequenceFullyConsumed());
EXPECT_TRUE(q.Pop(s));
EXPECT_FALSE(q.IsSequenceFullyConsumed());
- EXPECT_TRUE(q.MaybeSkipSequenceNumber(SequenceNumber(5)));
+ EXPECT_TRUE(q.SkipElement(SequenceNumber(5), kTestElementSize));
+ EXPECT_EQ(0u, q.GetTotalAvailableElementSize());
+ EXPECT_EQ(kEntry.size() * 2 + kTestElementSize * 4,
+ q.GetTotalElementSizeQueuedSoFar());
EXPECT_TRUE(q.IsSequenceFullyConsumed());
// Fully consumed queue: skipping must fail.
- EXPECT_FALSE(q.MaybeSkipSequenceNumber(SequenceNumber(6)));
+ EXPECT_FALSE(q.SkipElement(SequenceNumber(6), kTestElementSize));
}
TEST(SequencedQueueTest, Accounting) {
diff --git a/chromium/third_party/ipcz/src/ipcz/sublink_id.h b/chromium/third_party/ipcz/src/ipcz/sublink_id.h
index 5b9158e27c0..c5a658753c4 100644
--- a/chromium/third_party/ipcz/src/ipcz/sublink_id.h
+++ b/chromium/third_party/ipcz/src/ipcz/sublink_id.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/test_messages.cc b/chromium/third_party/ipcz/src/ipcz/test_messages.cc
index 12c4f36721e..6bd43e7bd84 100644
--- a/chromium/third_party/ipcz/src/ipcz/test_messages.cc
+++ b/chromium/third_party/ipcz/src/ipcz/test_messages.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/test_messages.h b/chromium/third_party/ipcz/src/ipcz/test_messages.h
index 88e7ce84da8..fbbbd3474af 100644
--- a/chromium/third_party/ipcz/src/ipcz/test_messages.h
+++ b/chromium/third_party/ipcz/src/ipcz/test_messages.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/test_messages_generator.h b/chromium/third_party/ipcz/src/ipcz/test_messages_generator.h
index 5f33a18349f..63420da10d1 100644
--- a/chromium/third_party/ipcz/src/ipcz/test_messages_generator.h
+++ b/chromium/third_party/ipcz/src/ipcz/test_messages_generator.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.cc b/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.cc
index d47aaa5caae..aa08b95a722 100644
--- a/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.cc
+++ b/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.h b/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.h
index 44d312c99a8..60029c299f4 100644
--- a/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.h
+++ b/chromium/third_party/ipcz/src/ipcz/trap_event_dispatcher.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/ipcz/trap_set.cc b/chromium/third_party/ipcz/src/ipcz/trap_set.cc
index 2aacb02e618..c0d26cdf2ca 100644
--- a/chromium/third_party/ipcz/src/ipcz/trap_set.cc
+++ b/chromium/third_party/ipcz/src/ipcz/trap_set.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,7 +16,7 @@ namespace ipcz {
namespace {
-IpczTrapConditionFlags GetSatisfiedConditions(
+IpczTrapConditionFlags GetSatisfiedConditionsForUpdate(
const IpczTrapConditions& conditions,
TrapSet::UpdateReason reason,
const IpczPortalStatus& status) {
@@ -52,9 +52,12 @@ IpczTrapConditionFlags GetSatisfiedConditions(
return event_flags;
}
-bool NeedRemoteState(IpczTrapConditionFlags flags) {
- return (flags & (IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS |
- IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES)) != 0;
+bool NeedRemoteParcels(IpczTrapConditionFlags flags) {
+ return (flags & IPCZ_TRAP_BELOW_MAX_REMOTE_PARCELS) != 0;
+}
+
+bool NeedRemoteBytes(IpczTrapConditionFlags flags) {
+ return (flags & IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES) != 0;
}
} // namespace
@@ -65,6 +68,14 @@ TrapSet::~TrapSet() {
ABSL_ASSERT(empty());
}
+// static
+IpczTrapConditionFlags TrapSet::GetSatisfiedConditions(
+ const IpczTrapConditions& conditions,
+ const IpczPortalStatus& current_status) {
+ return GetSatisfiedConditionsForUpdate(conditions, UpdateReason::kInstallTrap,
+ current_status);
+}
+
IpczResult TrapSet::Add(const IpczTrapConditions& conditions,
IpczTrapEventHandler handler,
uintptr_t context,
@@ -72,8 +83,8 @@ IpczResult TrapSet::Add(const IpczTrapConditions& conditions,
IpczTrapConditionFlags* satisfied_condition_flags,
IpczPortalStatus* status) {
last_known_status_ = current_status;
- IpczTrapConditionFlags flags = GetSatisfiedConditions(
- conditions, UpdateReason::kInstallTrap, current_status);
+ IpczTrapConditionFlags flags =
+ GetSatisfiedConditions(conditions, current_status);
if (flags != 0) {
if (satisfied_condition_flags) {
*satisfied_condition_flags = flags;
@@ -91,40 +102,56 @@ IpczResult TrapSet::Add(const IpczTrapConditions& conditions,
}
traps_.emplace_back(conditions, handler, context);
- if (NeedRemoteState(conditions.flags)) {
- ++num_traps_monitoring_remote_state_;
+ if (NeedRemoteParcels(conditions.flags)) {
+ ++num_traps_monitoring_remote_parcels_;
+ }
+ if (NeedRemoteBytes(conditions.flags)) {
+ ++num_traps_monitoring_remote_bytes_;
}
return IPCZ_RESULT_OK;
}
-void TrapSet::UpdatePortalStatus(const IpczPortalStatus& status,
+void TrapSet::UpdatePortalStatus(const OperationContext& context,
+ const IpczPortalStatus& status,
UpdateReason reason,
TrapEventDispatcher& dispatcher) {
last_known_status_ = status;
for (auto* it = traps_.begin(); it != traps_.end();) {
const Trap& trap = *it;
- const IpczTrapConditionFlags flags =
- GetSatisfiedConditions(trap.conditions, reason, status);
+ IpczTrapConditionFlags flags =
+ GetSatisfiedConditionsForUpdate(trap.conditions, reason, status);
if (!flags) {
++it;
continue;
}
+ if (context.is_api_call()) {
+ flags |= IPCZ_TRAP_WITHIN_API_CALL;
+ }
dispatcher.DeferEvent(trap.handler, trap.context, flags, status);
it = traps_.erase(it);
- if (NeedRemoteState(flags)) {
- --num_traps_monitoring_remote_state_;
+ if (NeedRemoteParcels(flags)) {
+ --num_traps_monitoring_remote_parcels_;
+ }
+ if (NeedRemoteBytes(flags)) {
+ --num_traps_monitoring_remote_bytes_;
}
}
}
-void TrapSet::RemoveAll(TrapEventDispatcher& dispatcher) {
+void TrapSet::RemoveAll(const OperationContext& context,
+ TrapEventDispatcher& dispatcher) {
+ IpczTrapConditionFlags flags = IPCZ_TRAP_REMOVED;
+ if (context.is_api_call()) {
+ flags |= IPCZ_TRAP_WITHIN_API_CALL;
+ }
for (const Trap& trap : traps_) {
- dispatcher.DeferEvent(trap.handler, trap.context, IPCZ_TRAP_REMOVED,
+ dispatcher.DeferEvent(trap.handler, trap.context, flags,
last_known_status_);
}
traps_.clear();
- num_traps_monitoring_remote_state_ = 0;
+ num_traps_monitoring_remote_parcels_ = 0;
+ num_traps_monitoring_remote_bytes_ = 0;
}
TrapSet::Trap::Trap(IpczTrapConditions conditions,
diff --git a/chromium/third_party/ipcz/src/ipcz/trap_set.h b/chromium/third_party/ipcz/src/ipcz/trap_set.h
index 671f0cd7ca9..a772796d416 100644
--- a/chromium/third_party/ipcz/src/ipcz/trap_set.h
+++ b/chromium/third_party/ipcz/src/ipcz/trap_set.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,7 @@
#include <cstdint>
#include "ipcz/ipcz.h"
+#include "ipcz/operation_context.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
namespace ipcz {
@@ -51,10 +52,25 @@ class TrapSet {
// Indicates whether any installed traps in this set require monitoring of
// remote queue state.
+ bool need_remote_parcels() const {
+ return num_traps_monitoring_remote_parcels_ > 0;
+ }
+ bool need_remote_bytes() const {
+ return num_traps_monitoring_remote_bytes_ > 0;
+ }
bool need_remote_state() const {
- return num_traps_monitoring_remote_state_ > 0;
+ return need_remote_parcels() || need_remote_bytes();
}
+ // Returns the set of trap condition flags within `conditions` that would be
+ // raised right now if a trap were installed to watch for them, given
+ // `current_status` as the status of the portal being watched. If this returns
+ // zero (IPCZ_NO_FLAGS), then no watched conditions are satisfied and a
+ // corresponding call to Add() would succeed.
+ static IpczTrapConditionFlags GetSatisfiedConditions(
+ const IpczTrapConditions& conditions,
+ const IpczPortalStatus& current_status);
+
// Attempts to install a new trap in the set. This effectively implements
// the ipcz Trap() API. If `conditions` are already met, returns
// IPCZ_RESULT_FAILED_PRECONDITION and populates `satisfied_condition_flags`
@@ -70,13 +86,15 @@ class TrapSet {
// If the state change is interesting to any trap in the set, an appropriate
// event may be appended to `dispatcher` for imminent dispatch and the trap is
// removed from the set before returning.
- void UpdatePortalStatus(const IpczPortalStatus& status,
+ void UpdatePortalStatus(const OperationContext& context,
+ const IpczPortalStatus& status,
UpdateReason reason,
TrapEventDispatcher& dispatcher);
// Immediately removes all traps from the set. Every trap present appends an
// IPCZ_TRAP_REMOVED event to `dispatcher` before removal.
- void RemoveAll(TrapEventDispatcher& dispatcher);
+ void RemoveAll(const OperationContext& context,
+ TrapEventDispatcher& dispatcher);
private:
struct Trap {
@@ -92,7 +110,8 @@ class TrapSet {
using TrapList = absl::InlinedVector<Trap, 4>;
TrapList traps_;
- size_t num_traps_monitoring_remote_state_ = 0;
+ size_t num_traps_monitoring_remote_parcels_ = 0;
+ size_t num_traps_monitoring_remote_bytes_ = 0;
IpczPortalStatus last_known_status_ = {.size = sizeof(last_known_status_)};
};
diff --git a/chromium/third_party/ipcz/src/ipcz/validator.cc b/chromium/third_party/ipcz/src/ipcz/validator.cc
new file mode 100644
index 00000000000..bba6ad3919b
--- /dev/null
+++ b/chromium/third_party/ipcz/src/ipcz/validator.cc
@@ -0,0 +1,37 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipcz/validator.h"
+
+#include "ipcz/driver_object.h"
+#include "ipcz/driver_transport.h"
+#include "ipcz/ipcz.h"
+#include "ipcz/node.h"
+#include "ipcz/node_link.h"
+#include "util/ref_counted.h"
+
+namespace ipcz {
+
+Validator::Validator(Ref<NodeLink> remote_source)
+ : remote_source_(std::move(remote_source)) {}
+
+Validator::~Validator() = default;
+
+IpczResult Validator::Close() {
+ return IPCZ_RESULT_OK;
+}
+
+IpczResult Validator::Reject(uintptr_t context) {
+ if (!remote_source_) {
+ return IPCZ_RESULT_FAILED_PRECONDITION;
+ }
+
+ const IpczDriver& driver = remote_source_->node()->driver();
+ const Ref<DriverTransport>& transport = remote_source_->transport();
+ driver.ReportBadTransportActivity(transport->driver_object().handle(),
+ context, IPCZ_NO_FLAGS, nullptr);
+ return IPCZ_RESULT_OK;
+}
+
+} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/ipcz/validator.h b/chromium/third_party/ipcz/src/ipcz/validator.h
new file mode 100644
index 00000000000..556f25d9633
--- /dev/null
+++ b/chromium/third_party/ipcz/src/ipcz/validator.h
@@ -0,0 +1,43 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPCZ_SRC_IPCZ_VALIDATOR_H_
+#define IPCZ_SRC_IPCZ_VALIDATOR_H_
+
+#include "ipcz/validator.h"
+
+#include "ipcz/api_object.h"
+#include "util/ref_counted.h"
+
+namespace ipcz {
+
+class NodeLink;
+
+// A validator object retains context associated with a specific inbound parcel.
+// Applications can use these objects to report their own application-level
+// validation failures to ipcz, and ipcz can use the context within to propagate
+// the failure out to an appropriate driver transport.
+class Validator : public APIObjectImpl<Validator, APIObject::kValidator> {
+ public:
+ explicit Validator(Ref<NodeLink> remote_source);
+
+ // APIObject:
+ IpczResult Close() override;
+
+ // Signals application-level rejection of whatever this validator is
+ // associated with. `context` is an opaque value passed by the application
+ // and propagated to the driver when appropriate. See the Reject() API.
+ IpczResult Reject(uintptr_t context);
+
+ private:
+ ~Validator() override;
+
+ // The remote source which sent the parcel to the local node. If this is null,
+ // the parcel originated from the local node.
+ const Ref<NodeLink> remote_source_;
+};
+
+} // namespace ipcz
+
+#endif // IPCZ_SRC_IPCZ_VALIDATOR_H_
diff --git a/chromium/third_party/ipcz/src/merge_portals_test.cc b/chromium/third_party/ipcz/src/merge_portals_test.cc
index a25008aa3b1..50f849d1849 100644
--- a/chromium/third_party/ipcz/src/merge_portals_test.cc
+++ b/chromium/third_party/ipcz/src/merge_portals_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -30,7 +30,7 @@ MULTINODE_TEST_NODE(MergePortalsTestNode, MergeWithInitialPortalClient) {
Close(b);
}
-TEST_P(MergePortalsTest, MergeWithInitialPortal) {
+MULTINODE_TEST(MergePortalsTest, MergeWithInitialPortal) {
IpczHandle c = SpawnTestNode<MergeWithInitialPortalClient>();
auto [q, p] = OpenPortals();
EXPECT_EQ(IPCZ_RESULT_OK, Merge(c, p));
@@ -43,7 +43,7 @@ TEST_P(MergePortalsTest, MergeWithInitialPortal) {
Close(q);
}
-TEST_P(MergePortalsTest, MergeWithClosedLocalPeer) {
+MULTINODE_TEST(MergePortalsTest, MergeWithClosedLocalPeer) {
auto [q, p] = OpenPortals();
auto [d, b] = OpenPortals();
@@ -64,7 +64,7 @@ MULTINODE_TEST_NODE(MergePortalsTestNode, MergeWithClosedRemotePeerClient) {
Close(b);
}
-TEST_P(MergePortalsTest, MergeWithClosedRemotePeer) {
+MULTINODE_TEST(MergePortalsTest, MergeWithClosedRemotePeer) {
IpczHandle c = SpawnTestNode<MergeWithClosedRemotePeerClient>();
auto [r, s] = OpenPortals();
EXPECT_EQ(IPCZ_RESULT_OK, Put(c, "", {&r, 1}));
@@ -95,7 +95,7 @@ MULTINODE_TEST_NODE(MergePortalsTestNode, MergeComplexRoutesClient) {
CloseAll({b, portal, other_client});
}
-TEST_P(MergePortalsTest, MergeComplexRoutes) {
+MULTINODE_TEST(MergePortalsTest, MergeComplexRoutes) {
IpczHandle c1 = SpawnTestNode<MergeComplexRoutesClient>();
IpczHandle c2 = SpawnTestNode<MergeComplexRoutesClient>();
@@ -123,7 +123,5 @@ TEST_P(MergePortalsTest, MergeComplexRoutes) {
CloseAll({c1, c2});
}
-INSTANTIATE_MULTINODE_TEST_SUITE_P(MergePortalsTest);
-
} // namespace
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/queueing_test.cc b/chromium/third_party/ipcz/src/queueing_test.cc
index a3ed6b7433d..96fe47259cf 100644
--- a/chromium/third_party/ipcz/src/queueing_test.cc
+++ b/chromium/third_party/ipcz/src/queueing_test.cc
@@ -1,7 +1,10 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <limits>
+#include <string>
+
#include "ipcz/ipcz.h"
#include "test/multinode_test.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,7 +44,7 @@ MULTINODE_TEST_NODE(QueueingTestNode, RemoteQueueFeedbackClient) {
Close(b);
}
-TEST_P(QueueingTest, RemoteQueueFeedback) {
+MULTINODE_TEST(QueueingTest, RemoteQueueFeedback) {
// Exercises operations which rely on feedback from the remote peer regarding
// its inbound parcel queue state.
IpczHandle c = SpawnTestNode<RemoteQueueFeedbackClient>();
@@ -120,13 +123,13 @@ MULTINODE_TEST_NODE(QueueingTestNode, TwoPhaseQueueingClient) {
// The producer should only have been able to put 3 out of its 4 bytes.
EXPECT_EQ("ipc",
std::string_view(reinterpret_cast<const char*>(data), num_bytes));
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().EndGet(b, num_bytes, 0, IPCZ_NO_FLAGS, nullptr, nullptr));
+ EXPECT_EQ(IPCZ_RESULT_OK, ipcz().EndGet(b, num_bytes, 0, IPCZ_NO_FLAGS,
+ nullptr, nullptr, nullptr));
Close(b);
}
-TEST_P(QueueingTest, TwoPhaseQueueing) {
+MULTINODE_TEST(QueueingTest, TwoPhaseQueueing) {
IpczHandle c = SpawnTestNode<TwoPhaseQueueingClient>();
WaitForDirectRemoteLink(c);
@@ -171,12 +174,13 @@ MULTINODE_TEST_NODE(QueueingTestNode, TwoPhaseFeedbackClient) {
EXPECT_EQ("hello?",
std::string_view(reinterpret_cast<const char*>(data), num_bytes));
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().EndGet(b, num_bytes, 0, IPCZ_NO_FLAGS, nullptr, nullptr));
+ EXPECT_EQ(IPCZ_RESULT_OK, ipcz().EndGet(b, num_bytes, 0, IPCZ_NO_FLAGS,
+ nullptr, nullptr, nullptr));
Close(b);
}
-TEST_P(QueueingTest, TwoPhaseFeedback) {
+// TODO(https://crbug.com/1361670): Fix flakiness and re-enable this test.
+MULTINODE_TEST(QueueingTest, DISABLED_TwoPhaseFeedback) {
IpczHandle c = SpawnTestNode<TwoPhaseFeedbackClient>();
WaitForDirectRemoteLink(c);
EXPECT_EQ(IPCZ_RESULT_OK, Put(c, "hello?"));
@@ -186,7 +190,80 @@ TEST_P(QueueingTest, TwoPhaseFeedback) {
Close(c);
}
-INSTANTIATE_MULTINODE_TEST_SUITE_P(QueueingTest);
+constexpr size_t kStressTestPortalCapacity = 256;
+constexpr size_t kStressTestPayloadSize = 4 * 1024 * 1024;
+
+MULTINODE_TEST_NODE(QueueingTestNode, RemoteQueueFeedbackStressTestClient) {
+ IpczHandle b = ConnectToBroker();
+
+ size_t bytes_received = 0;
+ while (bytes_received < kStressTestPayloadSize) {
+ // Consistency check: ensure that the portal never has more than
+ // kStressTestPortalCapacity bytes available to retrieve. Otherwise limits
+ // were not properly enforced by the sender.
+ IpczPortalStatus status = {.size = sizeof(status)};
+ EXPECT_EQ(IPCZ_RESULT_OK,
+ ipcz().QueryPortalStatus(b, IPCZ_NO_FLAGS, nullptr, &status));
+ EXPECT_LE(status.num_local_bytes, kStressTestPortalCapacity);
+
+ const void* data;
+ size_t num_bytes;
+ const IpczResult begin_result =
+ ipcz().BeginGet(b, IPCZ_NO_FLAGS, nullptr, &data, &num_bytes, nullptr);
+ if (begin_result == IPCZ_RESULT_OK) {
+ bytes_received += num_bytes;
+ EXPECT_EQ(std::string_view(static_cast<const char*>(data), num_bytes),
+ std::string(num_bytes, '!'));
+ EXPECT_EQ(IPCZ_RESULT_OK, ipcz().EndGet(b, num_bytes, 0, IPCZ_NO_FLAGS,
+ nullptr, nullptr, nullptr));
+ continue;
+ }
+
+ ASSERT_EQ(IPCZ_RESULT_UNAVAILABLE, begin_result);
+ WaitForConditions(
+ b, {.flags = IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES, .min_local_bytes = 0});
+ }
+
+ Close(b);
+}
+
+MULTINODE_TEST(QueueingTest, RemoteQueueFeedbackStressTest) {
+ IpczHandle c = SpawnTestNode<RemoteQueueFeedbackStressTestClient>();
+
+ size_t bytes_remaining = kStressTestPayloadSize;
+ while (bytes_remaining) {
+ void* data;
+ size_t capacity = bytes_remaining;
+ const IpczPutLimits limits = {
+ .size = sizeof(limits),
+ .max_queued_parcels = std::numeric_limits<size_t>::max(),
+ .max_queued_bytes = kStressTestPortalCapacity,
+ };
+ const IpczBeginPutOptions options = {
+ .size = sizeof(options),
+ .limits = &limits,
+ };
+ const IpczResult begin_result = ipcz().BeginPut(
+ c, IPCZ_BEGIN_PUT_ALLOW_PARTIAL, &options, &capacity, &data);
+ if (begin_result == IPCZ_RESULT_OK) {
+ size_t num_bytes = std::min(bytes_remaining, capacity);
+ bytes_remaining -= num_bytes;
+ memset(data, '!', num_bytes);
+ EXPECT_EQ(IPCZ_RESULT_OK, ipcz().EndPut(c, num_bytes, nullptr, 0,
+ IPCZ_NO_FLAGS, nullptr));
+ continue;
+ }
+ ASSERT_EQ(IPCZ_RESULT_RESOURCE_EXHAUSTED, begin_result);
+
+ EXPECT_EQ(
+ IPCZ_RESULT_OK,
+ WaitForConditions(c, {.flags = IPCZ_TRAP_BELOW_MAX_REMOTE_BYTES,
+ .max_remote_bytes = kStressTestPortalCapacity}));
+ }
+
+ WaitForConditionFlags(c, IPCZ_TRAP_PEER_CLOSED);
+ Close(c);
+}
} // namespace
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.cc b/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.cc
index 3ebbe8e6763..f4714ffd539 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -274,6 +274,7 @@ const IpczDriver kAsyncReferenceDriver = {
ActivateTransport,
DeactivateTransport,
Transmit,
+ kSingleProcessReferenceDriverBase.ReportBadTransportActivity,
kSingleProcessReferenceDriverBase.AllocateSharedMemory,
kSingleProcessReferenceDriverBase.GetSharedMemoryInfo,
kSingleProcessReferenceDriverBase.DuplicateSharedMemory,
@@ -290,6 +291,7 @@ const IpczDriver kAsyncReferenceDriverWithForcedBrokering = {
ActivateTransport,
DeactivateTransport,
Transmit,
+ kSingleProcessReferenceDriverBase.ReportBadTransportActivity,
kSingleProcessReferenceDriverBase.AllocateSharedMemory,
kSingleProcessReferenceDriverBase.GetSharedMemoryInfo,
kSingleProcessReferenceDriverBase.DuplicateSharedMemory,
@@ -306,4 +308,12 @@ AsyncTransportPair CreateAsyncTransportPair() {
};
}
+std::pair<IpczDriverHandle, IpczDriverHandle>
+CreateAsyncTransportPairForBrokers() {
+ AsyncTransport::Pair transports = AsyncTransport::CreatePair(
+ AsyncTransport::NodeType::kBroker, AsyncTransport::NodeType::kBroker);
+ return {Object::ReleaseAsHandle(std::move(transports.first)),
+ Object::ReleaseAsHandle(std::move(transports.second))};
+}
+
} // namespace ipcz::reference_drivers
diff --git a/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.h b/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.h
index 2371be15467..270a107db57 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/async_reference_driver.h
@@ -1,10 +1,12 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IPCZ_SRC_DRIVERS_ASYNC_REFERENCE_DRIVER_H_
#define IPCZ_SRC_DRIVERS_ASYNC_REFERENCE_DRIVER_H_
+#include <utility>
+
#include "ipcz/ipcz.h"
namespace ipcz::reference_drivers {
@@ -28,6 +30,11 @@ struct AsyncTransportPair {
};
AsyncTransportPair CreateAsyncTransportPair();
+// Creates a new pair of async transport endpoints, one for each of two
+// different brokers to be connected.
+std::pair<IpczDriverHandle, IpczDriverHandle>
+CreateAsyncTransportPairForBrokers();
+
} // namespace ipcz::reference_drivers
#endif // IPCZ_SRC_DRIVERS_ASYNC_REFERENCE_DRIVER_H_
diff --git a/chromium/third_party/ipcz/src/reference_drivers/blob.cc b/chromium/third_party/ipcz/src/reference_drivers/blob.cc
deleted file mode 100644
index bbebebe9b9c..00000000000
--- a/chromium/third_party/ipcz/src/reference_drivers/blob.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "reference_drivers/blob.h"
-
-#include <iterator>
-
-#include "util/ref_counted.h"
-
-namespace ipcz::reference_drivers {
-
-Blob::RefCountedFlag::RefCountedFlag() = default;
-
-Blob::RefCountedFlag::~RefCountedFlag() = default;
-
-Blob::Blob(std::string_view message) : message_(message) {}
-
-Blob::~Blob() = default;
-
-IpczResult Blob::Close() {
- destruction_flag_for_testing_->set(true);
- return IPCZ_RESULT_OK;
-}
-
-// static
-Blob* Blob::FromHandle(IpczDriverHandle handle) {
- Object* object = Object::FromHandle(handle);
- if (!object || object->type() != kBlob) {
- return nullptr;
- }
-
- return static_cast<Blob*>(object);
-}
-
-// static
-Ref<Blob> Blob::TakeFromHandle(IpczDriverHandle handle) {
- return AdoptRef(FromHandle(handle));
-}
-
-} // namespace ipcz::reference_drivers
diff --git a/chromium/third_party/ipcz/src/reference_drivers/blob.h b/chromium/third_party/ipcz/src/reference_drivers/blob.h
deleted file mode 100644
index 84be3788759..00000000000
--- a/chromium/third_party/ipcz/src/reference_drivers/blob.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IPCZ_SRC_REFERENCE_DRIVERS_BLOB_H_
-#define IPCZ_SRC_REFERENCE_DRIVERS_BLOB_H_
-
-#include <string>
-#include <string_view>
-
-#include "reference_drivers/object.h"
-#include "util/ref_counted.h"
-
-namespace ipcz::reference_drivers {
-
-// A driver-managed object which packages arbitrary string data. Blobs are used
-// to exercise driver object boxing in tests.
-//
-// Note that unlike the transport and memory objects defined by the reference
-// drivers, a blob is not a type of object known to ipcz. Instead it is used to
-// demonstrate how drivers can define arbitrary new types of transferrable
-// objects to extend ipcz.
-class Blob : public ObjectImpl<Blob, Object::kBlob> {
- public:
- class RefCountedFlag : public RefCounted {
- public:
- RefCountedFlag();
-
- bool get() const { return flag_; }
- void set(bool flag) { flag_ = flag; }
-
- private:
- ~RefCountedFlag() override;
- bool flag_ = false;
- };
-
- explicit Blob(std::string_view message);
-
- // Object:
- IpczResult Close() override;
-
- std::string& message() { return message_; }
-
- const Ref<RefCountedFlag>& destruction_flag_for_testing() const {
- return destruction_flag_for_testing_;
- }
-
- static Blob* FromHandle(IpczDriverHandle handle);
- static Ref<Blob> TakeFromHandle(IpczDriverHandle handle);
-
- protected:
- ~Blob() override;
-
- private:
- std::string message_;
- const Ref<RefCountedFlag> destruction_flag_for_testing_{
- MakeRefCounted<RefCountedFlag>()};
-};
-
-} // namespace ipcz::reference_drivers
-
-#endif // IPCZ_SRC_REFERENCE_DRIVERS_BLOB_H_
diff --git a/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.cc b/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.cc
index b00f44addaa..e73f4beafbd 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.h b/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.h
index 6e2233e6910..e92afbe00e9 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/file_descriptor.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/handle_eintr.h b/chromium/third_party/ipcz/src/reference_drivers/handle_eintr.h
index 927e9bd70c1..db4c4a81df9 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/handle_eintr.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/handle_eintr.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.cc b/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.cc
index c5e839be201..fadf967c313 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.h b/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.h
index b989106da07..07f7b6a6f36 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/memfd_memory.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/memfd_memory_test.cc b/chromium/third_party/ipcz/src/reference_drivers/memfd_memory_test.cc
index 67d5d105aa7..89d3dfbbe7a 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/memfd_memory_test.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/memfd_memory_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc b/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc
index fe967b10edd..445affe9141 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,7 +11,6 @@
#include <utility>
#include "ipcz/ipcz.h"
-#include "reference_drivers/blob.h"
#include "reference_drivers/file_descriptor.h"
#include "reference_drivers/memfd_memory.h"
#include "reference_drivers/object.h"
@@ -206,11 +205,6 @@ IpczResult IPCZ_API Serialize(IpczDriverHandle handle,
required_num_handles = 1;
break;
- case Object::kBlob:
- required_num_bytes += Blob::FromObject(object)->message().size();
- required_num_handles = 0;
- break;
-
default:
return IPCZ_RESULT_INVALID_ARGUMENT;
}
@@ -246,12 +240,6 @@ IpczResult IPCZ_API Serialize(IpczDriverHandle handle,
break;
}
- case Object::kBlob: {
- auto blob = Blob::TakeFromObject(object);
- memcpy(&header + 1, blob->message().data(), blob->message().size());
- break;
- }
-
default:
return IPCZ_RESULT_INVALID_ARGUMENT;
}
@@ -290,12 +278,6 @@ IpczResult IPCZ_API Deserialize(const void* data,
}
break;
- case Object::kBlob:
- object = MakeRefCounted<Blob>(
- std::string_view(reinterpret_cast<const char*>(&header + 1),
- num_bytes - sizeof(header)));
- break;
-
default:
break;
}
@@ -352,6 +334,13 @@ IpczResult IPCZ_API Transmit(IpczDriverHandle driver_transport,
absl::MakeSpan(handles, num_handles));
}
+IpczResult IPCZ_API ReportBadTransportActivity(IpczDriverHandle transport,
+ uintptr_t context,
+ uint32_t flags,
+ const void* options) {
+ return IPCZ_RESULT_OK;
+}
+
IpczResult IPCZ_API AllocateSharedMemory(size_t num_bytes,
uint32_t flags,
const void* options,
@@ -415,6 +404,7 @@ const IpczDriver kMultiprocessReferenceDriver = {
ActivateTransport,
DeactivateTransport,
Transmit,
+ ReportBadTransportActivity,
AllocateSharedMemory,
GetSharedMemoryInfo,
DuplicateSharedMemory,
diff --git a/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.h b/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.h
index 2aa2c183740..ebe564a8307 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver_test.cc b/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver_test.cc
index aa966bae945..94f960fe2a4 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver_test.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/multiprocess_reference_driver_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/object.cc b/chromium/third_party/ipcz/src/reference_drivers/object.cc
index 5028d07e087..005924be08f 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/object.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/object.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/object.h b/chromium/third_party/ipcz/src/reference_drivers/object.h
index 56e88cd8eac..e562d2beea2 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/object.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/object.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -21,11 +21,6 @@ class Object : public RefCounted {
kMemory,
kMapping,
- // A non-standard driver object type, used to exercise more complex, custom
- // driver object de/serialization via boxing and unboxing in tests. See the
- // Blob definition in src/reference_drivers/blob.h.
- kBlob,
-
#if defined(OS_LINUX)
// A non-standard driver object type which wraps a FileDescriptor object.
kFileDescriptor,
diff --git a/chromium/third_party/ipcz/src/reference_drivers/random.cc b/chromium/third_party/ipcz/src/reference_drivers/random.cc
index 91312250c0f..83c0e6f2553 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/random.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/random.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/random.h b/chromium/third_party/ipcz/src/reference_drivers/random.h
index 28596baabb7..aee39e34a52 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/random.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/random.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.cc b/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.cc
index f9b5cb1e6b0..f6832d31624 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -55,6 +55,12 @@ class InProcessMapping : public ObjectImpl<InProcessMapping, Object::kMapping> {
const Ref<InProcessMemory> memory_;
};
+BadTransportActivityCallback& GetBadTransportActivityCallback() {
+ static BadTransportActivityCallback* callback =
+ new BadTransportActivityCallback();
+ return *callback;
+}
+
IpczResult IPCZ_API Close(IpczDriverHandle handle,
uint32_t flags,
const void* options) {
@@ -110,6 +116,17 @@ IpczResult IPCZ_API Deserialize(const void* data,
return IPCZ_RESULT_OK;
}
+IpczResult IPCZ_API ReportBadTransportActivity(IpczDriverHandle transport,
+ uintptr_t context,
+ uint32_t flags,
+ const void* options) {
+ auto& callback = GetBadTransportActivityCallback();
+ if (callback) {
+ callback(transport, context);
+ }
+ return IPCZ_RESULT_OK;
+}
+
IpczResult IPCZ_API AllocateSharedMemory(size_t num_bytes,
uint32_t flags,
const void* options,
@@ -177,6 +194,7 @@ const IpczDriver kSingleProcessReferenceDriverBase = {
nullptr,
nullptr,
nullptr,
+ ReportBadTransportActivity,
AllocateSharedMemory,
GetSharedMemoryInfo,
DuplicateSharedMemory,
@@ -184,4 +202,8 @@ const IpczDriver kSingleProcessReferenceDriverBase = {
GenerateRandomBytes,
};
+void SetBadTransportActivityCallback(BadTransportActivityCallback callback) {
+ GetBadTransportActivityCallback() = std::move(callback);
+}
+
} // namespace ipcz::reference_drivers
diff --git a/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.h b/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.h
index e0e89b5aca3..cb2b9986a64 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/single_process_reference_driver_base.h
@@ -1,10 +1,12 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IPCZ_SRC_REFERENCE_DRIVERS_SINGLE_PROCESS_REFERENCE_DRIVER_BASE_H_
#define IPCZ_SRC_REFERENCE_DRIVERS_SINGLE_PROCESS_REFERENCE_DRIVER_BASE_H_
+#include <functional>
+
#include "ipcz/ipcz.h"
namespace ipcz::reference_drivers {
@@ -13,6 +15,13 @@ namespace ipcz::reference_drivers {
// and async single-process drivers.
extern const IpczDriver kSingleProcessReferenceDriverBase;
+// Installs a hook to be invoked any time ReportBadTransportActivity() is called
+// on any single-process reference driver. If called with null, any previously
+// installed hook is removed.
+using BadTransportActivityCallback =
+ std::function<void(IpczDriverHandle, uintptr_t)>;
+void SetBadTransportActivityCallback(BadTransportActivityCallback callback);
+
} // namespace ipcz::reference_drivers
#endif // IPCZ_SRC_REFERENCE_DRIVERS_SINGLE_PROCESS_REFERENCE_DRIVER_BASE_H_
diff --git a/chromium/third_party/ipcz/src/reference_drivers/socket_transport.cc b/chromium/third_party/ipcz/src/reference_drivers/socket_transport.cc
index 695fffea80e..91eca3084a8 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/socket_transport.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/socket_transport.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/socket_transport.h b/chromium/third_party/ipcz/src/reference_drivers/socket_transport.h
index a016c5bb6a6..d48310afbd2 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/socket_transport.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/socket_transport.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/socket_transport_test.cc b/chromium/third_party/ipcz/src/reference_drivers/socket_transport_test.cc
index 7b3f7fb39cc..d55e4f7c748 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/socket_transport_test.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/socket_transport_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.cc b/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.cc
index 6384c32a180..8b086c6bfc0 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -379,6 +379,7 @@ const IpczDriver kSyncReferenceDriver = {
ActivateTransport,
DeactivateTransport,
Transmit,
+ kSingleProcessReferenceDriverBase.ReportBadTransportActivity,
kSingleProcessReferenceDriverBase.AllocateSharedMemory,
kSingleProcessReferenceDriverBase.GetSharedMemoryInfo,
kSingleProcessReferenceDriverBase.DuplicateSharedMemory,
diff --git a/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.h b/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.h
index 4dd4c269897..faaa02f26d9 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver_test.cc b/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver_test.cc
index 2ec1f9a2f71..ee5b1284b84 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver_test.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/sync_reference_driver_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.cc b/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.cc
index 675b874d574..f7f63b1951d 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.cc
+++ b/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.h b/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.h
index e91154bd3ca..651f29127fc 100644
--- a/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.h
+++ b/chromium/third_party/ipcz/src/reference_drivers/wrapped_file_descriptor.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/remote_portal_test.cc b/chromium/third_party/ipcz/src/remote_portal_test.cc
index 798fdfe97a0..b8982c5698c 100644
--- a/chromium/third_party/ipcz/src/remote_portal_test.cc
+++ b/chromium/third_party/ipcz/src/remote_portal_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,8 +6,8 @@
#include <string_view>
#include <utility>
+#include "build/build_config.h"
#include "ipcz/ipcz.h"
-#include "reference_drivers/blob.h"
#include "test/multinode_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/strings/str_cat.h"
@@ -31,7 +31,7 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, BasicConnectionClient) {
Close(b);
}
-TEST_P(RemotePortalTest, BasicConnection) {
+MULTINODE_TEST(RemotePortalTest, BasicConnection) {
IpczHandle c = SpawnTestNode<BasicConnectionClient>();
std::string message;
@@ -55,7 +55,7 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, PortalTransferClient) {
CloseAll({p, b});
}
-TEST_P(RemotePortalTest, PortalTransfer) {
+MULTINODE_TEST(RemotePortalTest, PortalTransfer) {
IpczHandle c = SpawnTestNode<PortalTransferClient>();
auto [q, p] = OpenPortals();
@@ -110,7 +110,7 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, MultipleHopsClient2) {
CloseAll({p, b});
}
-TEST_P(RemotePortalTest, MultipleHops) {
+MULTINODE_TEST(RemotePortalTest, MultipleHops) {
IpczHandle c1 = SpawnTestNode<MultipleHopsClient1>();
IpczHandle c2 = SpawnTestNode<MultipleHopsClient2>();
@@ -138,7 +138,7 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, TransferBackAndForthClient) {
Close(b);
}
-TEST_P(RemotePortalTest, TransferBackAndForth) {
+MULTINODE_TEST(RemotePortalTest, TransferBackAndForth) {
IpczHandle c = SpawnTestNode<TransferBackAndForthClient>();
constexpr std::string_view kMessage = "hihihihi";
@@ -176,22 +176,12 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, HugeNumberOfPortalsClient) {
EXPECT_EQ(IPCZ_RESULT_OK,
WaitToGet(other_client, nullptr, {&portals[i], 1}));
- IpczDriverHandle blob = reference_drivers::Blob::ReleaseAsHandle(
- MakeRefCounted<reference_drivers::Blob>(absl::StrCat(absl::Dec(i))));
- IpczHandle box;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob, IPCZ_NO_FLAGS, nullptr, &box));
+ IpczHandle box = BoxBlob(absl::StrCat(absl::Dec(i)));
EXPECT_EQ(IPCZ_RESULT_OK, Put(portals[i], "", {&box, 1}));
- }
- for (size_t i = 0; i < kHugeNumberOfPortalsCount; ++i) {
- IpczHandle box;
+ box = IPCZ_INVALID_HANDLE;
EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(portals[i], nullptr, {&box, 1}));
-
- IpczDriverHandle blob;
- EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob));
- EXPECT_EQ(absl::StrCat(absl::Dec(i)),
- reference_drivers::Blob::TakeFromHandle(blob)->message());
+ EXPECT_EQ(absl::StrCat(absl::Dec(i)), UnboxBlob(box));
}
EXPECT_EQ(IPCZ_RESULT_OK, Put(b, "", {&other_client, 1}));
@@ -200,7 +190,7 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, HugeNumberOfPortalsClient) {
Close(b);
}
-TEST_P(RemotePortalTest, HugeNumberOfPortals) {
+MULTINODE_TEST(RemotePortalTest, HugeNumberOfPortals) {
// Opens a very large number of portals, and sends them all to client nodes.
// The client nodes exchange these portals with each other and transmit
// parcels over them, with and without driver objects. This exercises
@@ -238,7 +228,7 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, RoutingStressTestClient) {
Close(b);
}
-TEST_P(RemotePortalTest, RoutingStressTest) {
+MULTINODE_TEST(RemotePortalTest, RoutingStressTest) {
// This test spawns a bunch of nodes and bounces two portals back and forth
// among them over a large number of iterations, then waits for all the
// intermediate routers to be removed. Every iteration also sends a message
@@ -254,11 +244,7 @@ TEST_P(RemotePortalTest, RoutingStressTest) {
auto [a, b] = OpenPortals();
for (size_t j = 0; j < kRouteExpansionStressTestNumIterations; ++j) {
- IpczDriverHandle blob = reference_drivers::Blob::ReleaseAsHandle(
- MakeRefCounted<reference_drivers::Blob>(absl::StrCat(absl::Dec(j))));
- IpczHandle box;
- EXPECT_EQ(IPCZ_RESULT_OK,
- ipcz().Box(node(), blob, IPCZ_NO_FLAGS, nullptr, &box));
+ IpczHandle box = BoxBlob(absl::StrCat(absl::Dec(j)));
EXPECT_EQ(IPCZ_RESULT_OK,
Put(a, absl::StrCat("a", absl::Dec(j)), {&box, 1}));
EXPECT_EQ(IPCZ_RESULT_OK, Put(b, absl::StrCat("b", absl::Dec(j))));
@@ -279,11 +265,7 @@ TEST_P(RemotePortalTest, RoutingStressTest) {
EXPECT_EQ(absl::StrCat("b", absl::Dec(i)), message);
EXPECT_EQ(IPCZ_RESULT_OK, WaitToGet(b, &message, {&box, 1}));
EXPECT_EQ(absl::StrCat("a", absl::Dec(i)), message);
-
- IpczDriverHandle blob;
- EXPECT_EQ(IPCZ_RESULT_OK, ipcz().Unbox(box, IPCZ_NO_FLAGS, nullptr, &blob));
- EXPECT_EQ(absl::StrCat(absl::Dec(i)),
- reference_drivers::Blob::TakeFromHandle(blob)->message());
+ EXPECT_EQ(absl::StrCat(absl::Dec(i)), UnboxBlob(box));
}
for (auto& pair : client_pairs) {
@@ -340,7 +322,7 @@ MULTINODE_TEST_NODE(RemotePortalTestNode, DisconnectThroughProxyClient3) {
#else
#define MAYBE_DisconnectThroughProxy DisconnectThroughProxy
#endif
-TEST_P(RemotePortalTest, MAYBE_DisconnectThroughProxy) {
+MULTINODE_TEST(RemotePortalTest, MAYBE_DisconnectThroughProxy) {
// Exercises node disconnection. Namely if portals on nodes 1 and 3 are
// connected via proxy on node 2, and node 3 disappears, node 1's portal
// should observe peer closure.
@@ -372,7 +354,5 @@ TEST_P(RemotePortalTest, MAYBE_DisconnectThroughProxy) {
CloseAll({c1, c2, c3});
}
-INSTANTIATE_MULTINODE_TEST_SUITE_P(RemotePortalTest);
-
} // namespace
} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/standalone/BUILD.gn b/chromium/third_party/ipcz/src/standalone/BUILD.gn
index f94f5152a8f..19c1fc2dab0 100644
--- a/chromium/third_party/ipcz/src/standalone/BUILD.gn
+++ b/chromium/third_party/ipcz/src/standalone/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2022 The Chromium Authors. All rights reserved.
+# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/standalone/base/logging.cc b/chromium/third_party/ipcz/src/standalone/base/logging.cc
index b304758fbb4..8db8a859565 100644
--- a/chromium/third_party/ipcz/src/standalone/base/logging.cc
+++ b/chromium/third_party/ipcz/src/standalone/base/logging.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/standalone/base/logging.h b/chromium/third_party/ipcz/src/standalone/base/logging.h
index e12cc3ba29c..0cdff606b5c 100644
--- a/chromium/third_party/ipcz/src/standalone/base/logging.h
+++ b/chromium/third_party/ipcz/src/standalone/base/logging.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/standalone/base/stack_trace.cc b/chromium/third_party/ipcz/src/standalone/base/stack_trace.cc
index 159e4a339eb..65dbdd55442 100644
--- a/chromium/third_party/ipcz/src/standalone/base/stack_trace.cc
+++ b/chromium/third_party/ipcz/src/standalone/base/stack_trace.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/standalone/base/stack_trace.h b/chromium/third_party/ipcz/src/standalone/base/stack_trace.h
index b14df86a77c..f23bbb94093 100644
--- a/chromium/third_party/ipcz/src/standalone/base/stack_trace.h
+++ b/chromium/third_party/ipcz/src/standalone/base/stack_trace.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/trap_test.cc b/chromium/third_party/ipcz/src/trap_test.cc
index 5c2f537ab6b..d23c0a90ca3 100644
--- a/chromium/third_party/ipcz/src/trap_test.cc
+++ b/chromium/third_party/ipcz/src/trap_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,12 +40,14 @@ TEST_F(TrapTest, RemoveOnClose) {
.flags = IPCZ_TRAP_NEW_LOCAL_PARCEL,
};
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_REMOVED, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_REMOVED | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
parcel_trap_removed = true;
}));
conditions.flags = IPCZ_TRAP_PEER_CLOSED;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_REMOVED, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_REMOVED | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
closure_trap_removed = true;
}));
@@ -67,7 +69,8 @@ TEST_F(TrapTest, PeerClosed) {
};
bool received_event = false;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
received_event = true;
}));
@@ -96,7 +99,9 @@ TEST_F(TrapTest, MinLocalParcels) {
};
bool received_event = false;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS, e.condition_flags);
+ EXPECT_EQ(
+ IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
received_event = true;
}));
@@ -118,7 +123,9 @@ TEST_F(TrapTest, MinLocalParcels) {
received_event = false;
conditions.min_local_parcels = 2;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS, e.condition_flags);
+ EXPECT_EQ(
+ IPCZ_TRAP_ABOVE_MIN_LOCAL_PARCELS | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
received_event = true;
}));
@@ -150,7 +157,9 @@ TEST_F(TrapTest, MinLocalBytes) {
};
bool received_event = false;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES, e.condition_flags);
+ EXPECT_EQ(
+ IPCZ_TRAP_ABOVE_MIN_LOCAL_BYTES | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
received_event = true;
}));
@@ -184,7 +193,8 @@ TEST_F(TrapTest, NewLocalParcel) {
};
bool received_event = false;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
received_event = true;
}));
@@ -194,7 +204,8 @@ TEST_F(TrapTest, NewLocalParcel) {
received_event = false;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
received_event = true;
}));
@@ -214,7 +225,8 @@ TEST_F(TrapTest, DeadPortal) {
};
bool received_event = false;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_DEAD, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_DEAD | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
received_event = true;
}));
@@ -255,19 +267,22 @@ TEST_F(TrapTest, MultipleTraps) {
.flags = IPCZ_TRAP_NEW_LOCAL_PARCEL,
};
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_NEW_LOCAL_PARCEL | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
observed_parcel = true;
}));
conditions.flags = IPCZ_TRAP_PEER_CLOSED;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_PEER_CLOSED | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
observed_closure = true;
}));
conditions.flags = IPCZ_TRAP_DEAD;
EXPECT_EQ(IPCZ_RESULT_OK, Trap(b, conditions, [&](const IpczTrapEvent& e) {
- EXPECT_EQ(IPCZ_TRAP_DEAD, e.condition_flags);
+ EXPECT_EQ(IPCZ_TRAP_DEAD | IPCZ_TRAP_WITHIN_API_CALL,
+ e.condition_flags);
observed_death = true;
}));
diff --git a/chromium/third_party/ipcz/src/util/log.h b/chromium/third_party/ipcz/src/util/log.h
index 3aba4e27f4e..52476a48286 100644
--- a/chromium/third_party/ipcz/src/util/log.h
+++ b/chromium/third_party/ipcz/src/util/log.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/util/multi_mutex_lock.h b/chromium/third_party/ipcz/src/util/multi_mutex_lock.h
index 2633dad16ee..6d303c6c54a 100644
--- a/chromium/third_party/ipcz/src/util/multi_mutex_lock.h
+++ b/chromium/third_party/ipcz/src/util/multi_mutex_lock.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/util/ref_counted.cc b/chromium/third_party/ipcz/src/util/ref_counted.cc
index 9c64c18bb30..40f508ee45b 100644
--- a/chromium/third_party/ipcz/src/util/ref_counted.cc
+++ b/chromium/third_party/ipcz/src/util/ref_counted.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/util/ref_counted.h b/chromium/third_party/ipcz/src/util/ref_counted.h
index d991b5049df..98921e960c7 100644
--- a/chromium/third_party/ipcz/src/util/ref_counted.h
+++ b/chromium/third_party/ipcz/src/util/ref_counted.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/util/ref_counted_test.cc b/chromium/third_party/ipcz/src/util/ref_counted_test.cc
index ffa3f93a86f..c589a2e586d 100644
--- a/chromium/third_party/ipcz/src/util/ref_counted_test.cc
+++ b/chromium/third_party/ipcz/src/util/ref_counted_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/util/safe_math.h b/chromium/third_party/ipcz/src/util/safe_math.h
index 5affb986e71..3c4c7b39768 100644
--- a/chromium/third_party/ipcz/src/util/safe_math.h
+++ b/chromium/third_party/ipcz/src/util/safe_math.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#define IPCZ_SRC_UTIL_SAFE_MATH_
#include <limits>
+#include <type_traits>
#include "third_party/abseil-cpp/absl/base/macros.h"
#include "third_party/abseil-cpp/absl/base/optimization.h"
@@ -22,6 +23,18 @@ constexpr Dst checked_cast(Src value) {
return static_cast<Dst>(value);
}
+template <typename Dst, typename Src>
+constexpr Dst saturated_cast(Src value) {
+ static_assert(std::is_unsigned_v<Src> && std::is_unsigned_v<Dst>,
+ "saturated_cast only supports unsigned types");
+ constexpr Dst kMaxDst = std::numeric_limits<Dst>::max();
+ constexpr Src kMaxSrc = std::numeric_limits<Src>::max();
+ if (ABSL_PREDICT_TRUE(kMaxDst >= kMaxSrc || value <= kMaxDst)) {
+ return static_cast<Dst>(value);
+ }
+ return kMaxDst;
+}
+
template <typename T>
constexpr T CheckAdd(T a, T b) {
T result;
diff --git a/chromium/third_party/ipcz/src/util/safe_math_test.cc b/chromium/third_party/ipcz/src/util/safe_math_test.cc
new file mode 100644
index 00000000000..0ccd2cd6dda
--- /dev/null
+++ b/chromium/third_party/ipcz/src/util/safe_math_test.cc
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "util/safe_math.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ipcz {
+namespace {
+
+template <typename T>
+uint64_t AsUint64(T value) {
+ return static_cast<uint64_t>(value);
+}
+
+TEST(SafeMathTest, SaturatedCast) {
+ const uint32_t kMaxUint32 = 0xffffffff;
+ const uint64_t kSmallUint64 = 0x12345678;
+ const uint64_t kLargeUint64 = 0x123456789abcull;
+
+ // Casting to a smaller type within its range yields the same value.
+ EXPECT_EQ(kSmallUint64, AsUint64(saturated_cast<uint32_t>(kSmallUint64)));
+
+ // Casting to a smaller type outside of its range yields the max value for
+ // the destination type.
+ EXPECT_EQ(kMaxUint32, saturated_cast<uint32_t>(kLargeUint64));
+
+ // Casting to a larger type always yields the same value.
+ EXPECT_EQ(AsUint64(kMaxUint32), saturated_cast<uint64_t>(kMaxUint32));
+}
+
+} // namespace
+} // namespace ipcz
diff --git a/chromium/third_party/ipcz/src/util/stack_trace.h b/chromium/third_party/ipcz/src/util/stack_trace.h
index bcf462bd80e..55b6fd36ff1 100644
--- a/chromium/third_party/ipcz/src/util/stack_trace.h
+++ b/chromium/third_party/ipcz/src/util/stack_trace.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/util/stack_trace_test.cc b/chromium/third_party/ipcz/src/util/stack_trace_test.cc
index bce69ac7b4a..ea0d23aec34 100644
--- a/chromium/third_party/ipcz/src/util/stack_trace_test.cc
+++ b/chromium/third_party/ipcz/src/util/stack_trace_test.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/chromium/third_party/ipcz/src/util/strong_alias.h b/chromium/third_party/ipcz/src/util/strong_alias.h
index d6faf97005b..eeea5b89b12 100644
--- a/chromium/third_party/ipcz/src/util/strong_alias.h
+++ b/chromium/third_party/ipcz/src/util/strong_alias.h
@@ -1,4 +1,4 @@
-// Copyright 2022 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.