Add support for CreateContextForMultiPortPath running async.
This change modifies CreateContextForMultiPortPath to now take an std::function as an argument, and instead of returning an std::unique_ptr<QuicPathValidationContext> the unique_ptr is now passed into the std::function.
There is no behavioral change in how CreateContextForMultiPortPath or MaybeCreateMultiPortPath run.
This change is necessary for Chrome's implementation of CreateContextForMultiPortPath as it will need to be asynchronous. There is a WIP CL out for this change on the chrome side here: https://chromium-review.googlesource.com/c/chromium/src/+/4500184. This CL will need to be uploaded when these current changes are eventually merged into Chrome.
PiperOrigin-RevId: 529106195
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 42a4cf9..9fd036f 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -4095,18 +4095,21 @@
kMaxNumMultiPortPaths) {
return;
}
- auto path_context = visitor_->CreateContextForMultiPortPath();
- if (!path_context) {
- return;
- }
- auto multi_port_validation_result_delegate =
- std::make_unique<MultiPortPathValidationResultDelegate>(this);
- multi_port_probing_alarm_->Cancel();
- multi_port_path_context_ = nullptr;
- multi_port_stats_->num_multi_port_paths_created++;
- ValidatePath(std::move(path_context),
- std::move(multi_port_validation_result_delegate),
- PathValidationReason::kMultiPort);
+
+ visitor_->CreateContextForMultiPortPath(
+ [this](std::unique_ptr<QuicPathValidationContext> path_context) {
+ if (!path_context) {
+ return;
+ }
+ auto multi_port_validation_result_delegate =
+ std::make_unique<MultiPortPathValidationResultDelegate>(this);
+ multi_port_probing_alarm_->Cancel();
+ multi_port_path_context_ = nullptr;
+ multi_port_stats_->num_multi_port_paths_created++;
+ ValidatePath(std::move(path_context),
+ std::move(multi_port_validation_result_delegate),
+ PathValidationReason::kMultiPort);
+ });
}
void QuicConnection::SendOrQueuePacket(SerializedPacket packet) {
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index de10b88..09c1eed 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -237,9 +237,14 @@
// When bandwidth update alarms.
virtual void OnBandwidthUpdateTimeout() = 0;
- // Returns context needed for the connection to probe on the alternative path.
- virtual std::unique_ptr<QuicPathValidationContext>
- CreateContextForMultiPortPath() = 0;
+ // Runs |create_context| with context needed for the connection to probe on
+ // the alternative path. The callback must be called exactly once. May run
+ // |create_context| synchronously or asynchronously. If |create_context| is
+ // run asynchronously, it must be called on the same thread as QuicConnection
+ // is not thread safe.
+ virtual void CreateContextForMultiPortPath(
+ std::function<void(std::unique_ptr<QuicPathValidationContext>)>
+ create_context) = 0;
// Migrate to the multi-port path which is identified by |context|.
virtual void MigrateToMultiPortPath(
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 8fa8d2f..64a0358 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -13382,10 +13382,11 @@
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
frame.retire_prior_to = 0u;
frame.sequence_number = 1u;
- EXPECT_CALL(visitor_, CreateContextForMultiPortPath())
- .WillRepeatedly(Return(
- testing::ByMove(std::make_unique<TestQuicPathValidationContext>(
- kNewSelfAddress, connection_.peer_address(), &new_writer))));
+ EXPECT_CALL(visitor_, CreateContextForMultiPortPath)
+ .WillRepeatedly(testing::WithArgs<0>([&](auto&& fn) {
+ fn(std::move(std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), &new_writer)));
+ }));
connection_.OnNewConnectionIdFrame(frame);
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath(
@@ -13517,10 +13518,11 @@
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
frame.retire_prior_to = 0u;
frame.sequence_number = 1u;
- EXPECT_CALL(visitor_, CreateContextForMultiPortPath())
- .WillRepeatedly(Return(
- testing::ByMove(std::make_unique<TestQuicPathValidationContext>(
- kNewSelfAddress, connection_.peer_address(), &new_writer))));
+ EXPECT_CALL(visitor_, CreateContextForMultiPortPath)
+ .WillRepeatedly(testing::WithArgs<0>([&](auto&& fn) {
+ fn(std::move(std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), &new_writer)));
+ }));
EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame));
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath(
@@ -13555,10 +13557,11 @@
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
frame.retire_prior_to = 0u;
frame.sequence_number = i + 2;
- EXPECT_CALL(visitor_, CreateContextForMultiPortPath())
- .WillRepeatedly(Return(
- testing::ByMove(std::make_unique<TestQuicPathValidationContext>(
- kNewSelfAddress, connection_.peer_address(), &new_writer))));
+ EXPECT_CALL(visitor_, CreateContextForMultiPortPath)
+ .WillRepeatedly(testing::WithArgs<0>([&](auto&& fn) {
+ fn(std::move(std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), &new_writer)));
+ }));
EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame));
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath(
@@ -13626,10 +13629,11 @@
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
frame.retire_prior_to = 0u;
frame.sequence_number = 1u;
- EXPECT_CALL(visitor_, CreateContextForMultiPortPath())
- .WillRepeatedly(Return(
- testing::ByMove(std::make_unique<TestQuicPathValidationContext>(
- kNewSelfAddress, connection_.peer_address(), &new_writer))));
+ EXPECT_CALL(visitor_, CreateContextForMultiPortPath)
+ .WillRepeatedly(testing::WithArgs<0>([&](auto&& fn) {
+ fn(std::move(std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), &new_writer)));
+ }));
EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame));
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath(
@@ -13695,10 +13699,11 @@
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
frame.retire_prior_to = 0u;
frame.sequence_number = 1u;
- EXPECT_CALL(visitor_, CreateContextForMultiPortPath())
- .WillRepeatedly(Return(
- testing::ByMove(std::make_unique<TestQuicPathValidationContext>(
- kNewSelfAddress, connection_.peer_address(), &new_writer))));
+ EXPECT_CALL(visitor_, CreateContextForMultiPortPath)
+ .WillRepeatedly(testing::WithArgs<0>([&](auto&& fn) {
+ fn(std::move(std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), &new_writer)));
+ }));
EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame));
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath(
@@ -13772,10 +13777,11 @@
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
frame.retire_prior_to = 0u;
frame.sequence_number = 1u;
- EXPECT_CALL(visitor_, CreateContextForMultiPortPath())
- .WillRepeatedly(Return(
- testing::ByMove(std::make_unique<TestQuicPathValidationContext>(
- kNewSelfAddress, connection_.peer_address(), &new_writer))));
+ EXPECT_CALL(visitor_, CreateContextForMultiPortPath)
+ .WillRepeatedly(testing::WithArgs<0>([&](auto&& fn) {
+ fn(std::move(std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress, connection_.peer_address(), &new_writer)));
+ }));
EXPECT_TRUE(connection_.OnNewConnectionIdFrame(frame));
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_TRUE(QuicConnectionPeer::IsAlternativePath(
@@ -16842,10 +16848,11 @@
QuicUtils::GenerateStatelessResetToken(frame.connection_id);
frame.retire_prior_to = 0u;
frame.sequence_number = 2u;
- EXPECT_CALL(visitor_, CreateContextForMultiPortPath())
- .WillOnce(Return(
- testing::ByMove(std::make_unique<TestQuicPathValidationContext>(
- kNewSelfAddress2, connection_.peer_address(), &new_writer2))));
+ EXPECT_CALL(visitor_, CreateContextForMultiPortPath)
+ .WillOnce(testing::WithArgs<0>([&](auto&& fn) {
+ fn(std::move(std::make_unique<TestQuicPathValidationContext>(
+ kNewSelfAddress2, connection_.peer_address(), &new_writer2)));
+ }));
connection_.OnNewConnectionIdFrame(frame);
EXPECT_TRUE(connection_.HasPendingPathValidation());
EXPECT_EQ(1u, new_writer.path_challenge_frames().size());
diff --git a/quiche/quic/core/quic_session.h b/quiche/quic/core/quic_session.h
index e1c1932..1034a3c 100644
--- a/quiche/quic/core/quic_session.h
+++ b/quiche/quic/core/quic_session.h
@@ -181,9 +181,10 @@
bool ValidateToken(absl::string_view token) override;
bool MaybeSendAddressToken() override;
void OnBandwidthUpdateTimeout() override {}
- std::unique_ptr<QuicPathValidationContext> CreateContextForMultiPortPath()
- override {
- return nullptr;
+ void CreateContextForMultiPortPath(
+ std::function<void(std::unique_ptr<QuicPathValidationContext>)>
+ create_context) override {
+ create_context(nullptr);
}
void MigrateToMultiPortPath(
std::unique_ptr<QuicPathValidationContext> /*context*/) override {}
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h
index a60de26..c21107c 100644
--- a/quiche/quic/test_tools/quic_test_utils.h
+++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -504,8 +504,9 @@
MOCK_METHOD(void, BeforeConnectionCloseSent, (), (override));
MOCK_METHOD(bool, ValidateToken, (absl::string_view), (override));
MOCK_METHOD(bool, MaybeSendAddressToken, (), (override));
- MOCK_METHOD(std::unique_ptr<QuicPathValidationContext>,
- CreateContextForMultiPortPath, (), (override));
+ MOCK_METHOD(void, CreateContextForMultiPortPath,
+ (std::function<void(std::unique_ptr<QuicPathValidationContext>)>),
+ (override));
MOCK_METHOD(void, MigrateToMultiPortPath,
(std::unique_ptr<QuicPathValidationContext>), (override));
MOCK_METHOD(void, OnServerPreferredAddressAvailable,
diff --git a/quiche/quic/test_tools/simulator/quic_endpoint.h b/quiche/quic/test_tools/simulator/quic_endpoint.h
index 6be7bbb..29b72c5 100644
--- a/quiche/quic/test_tools/simulator/quic_endpoint.h
+++ b/quiche/quic/test_tools/simulator/quic_endpoint.h
@@ -105,9 +105,10 @@
bool ValidateToken(absl::string_view /*token*/) override { return true; }
bool MaybeSendAddressToken() override { return false; }
void OnBandwidthUpdateTimeout() override {}
- std::unique_ptr<QuicPathValidationContext> CreateContextForMultiPortPath()
- override {
- return nullptr;
+ void CreateContextForMultiPortPath(
+ std::function<void(std::unique_ptr<QuicPathValidationContext>)>
+ create_context) override {
+ create_context(nullptr);
}
void MigrateToMultiPortPath(
std::unique_ptr<QuicPathValidationContext> /*context*/) override {}
diff --git a/quiche/quic/tools/quic_simple_client_session.cc b/quiche/quic/tools/quic_simple_client_session.cc
index 23601ad..eaaa921 100644
--- a/quiche/quic/tools/quic_simple_client_session.cc
+++ b/quiche/quic/tools/quic_simple_client_session.cc
@@ -50,24 +50,28 @@
: HttpDatagramSupport::kNone;
}
-std::unique_ptr<QuicPathValidationContext>
-QuicSimpleClientSession::CreateContextForMultiPortPath() {
+void QuicSimpleClientSession::CreateContextForMultiPortPath(
+ std::function<void(std::unique_ptr<QuicPathValidationContext>)>
+ create_context) {
if (!network_helper_ || connection()->multi_port_stats() == nullptr) {
- return nullptr;
+ create_context(nullptr);
+ return;
}
auto self_address = connection()->self_address();
auto server_address = connection()->peer_address();
if (!network_helper_->CreateUDPSocketAndBind(
server_address, self_address.host(), self_address.port() + 1)) {
- return nullptr;
+ create_context(nullptr);
+ return;
}
QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();
if (writer == nullptr) {
- return nullptr;
+ create_context(nullptr);
+ return;
}
- return std::make_unique<PathMigrationContext>(
+ create_context(std::make_unique<PathMigrationContext>(
std::unique_ptr<QuicPacketWriter>(writer),
- network_helper_->GetLatestClientAddress(), peer_address());
+ network_helper_->GetLatestClientAddress(), peer_address()));
}
void QuicSimpleClientSession::MigrateToMultiPortPath(
diff --git a/quiche/quic/tools/quic_simple_client_session.h b/quiche/quic/tools/quic_simple_client_session.h
index 1770c9f..b172afc 100644
--- a/quiche/quic/tools/quic_simple_client_session.h
+++ b/quiche/quic/tools/quic_simple_client_session.h
@@ -35,8 +35,9 @@
std::unique_ptr<QuicSpdyClientStream> CreateClientStream() override;
bool ShouldNegotiateWebTransport() override;
HttpDatagramSupport LocalHttpDatagramSupport() override;
- std::unique_ptr<QuicPathValidationContext> CreateContextForMultiPortPath()
- override;
+ void CreateContextForMultiPortPath(
+ std::function<void(std::unique_ptr<QuicPathValidationContext>)>
+ create_context) override;
void MigrateToMultiPortPath(
std::unique_ptr<QuicPathValidationContext> context) override;
bool drop_response_body() const { return drop_response_body_; }