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 {}