Send PATH_RESPONSE using the alternative socket if the PATH_CHALLENGE is received on that socket.

behind existing flags --gfe2_reloadable_flag_quic_send_path_response and --gfe2_reloadable_flag_quic_start_peer_migration_earlier.

PiperOrigin-RevId: 351603900
Change-Id: I00b43457817c8bba559fec46217495e7d609e638
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc
index 2b994eb..568c891 100644
--- a/quic/core/http/quic_spdy_session_test.cc
+++ b/quic/core/http/quic_spdy_session_test.cc
@@ -1297,6 +1297,10 @@
 // Test that server session will send a connectivity probe in response to a
 // connectivity probe on the same path.
 TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) {
+  if (VersionHasIetfQuicFrames(transport_version()) &&
+      connection_->send_path_response()) {
+    return;
+  }
   connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
   QuicSocketAddress old_peer_address =
       QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort);
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 7b5d984..b53e90d 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -5535,7 +5535,37 @@
   QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_,
                                                       peer_address_to_send);
   QUIC_DVLOG(1) << ENDPOINT << "Send PATH_RESPONSE to " << peer_address_to_send;
-  return packet_creator_.AddPathResponseFrame(data_buffer);
+  if (self_address_ == last_packet_destination_address_) {
+    // The PATH_CHALLENGE is received on the default socket. Respond on the same
+    // socket.
+    return packet_creator_.AddPathResponseFrame(data_buffer);
+  }
+
+  DCHECK_EQ(Perspective::IS_CLIENT, perspective_);
+  // This PATH_CHALLENGE is received on an alternative socket which should be
+  // used to send PATH_RESPONSE.
+  if (!path_validator_.HasPendingPathValidation() ||
+      path_validator_.GetContext()->self_address() !=
+          last_packet_destination_address_) {
+    // Ignore this PATH_CHALLENGE if it's received from an uninteresting socket.
+    return true;
+  }
+  QuicPacketWriter* writer = path_validator_.GetContext()->WriterToUse();
+
+  std::unique_ptr<SerializedPacket> probing_packet =
+      packet_creator_.SerializePathResponseConnectivityProbingPacket(
+          {data_buffer}, /*is_padded=*/true);
+  DCHECK_EQ(IsRetransmittable(*probing_packet), NO_RETRANSMITTABLE_DATA);
+  QUIC_DVLOG(1) << ENDPOINT
+                << "Send PATH_RESPONSE from alternative socket with address "
+                << last_packet_destination_address_;
+  // Ignore the return value to treat write error on the alternative writer as
+  // part of network error. If the writer becomes blocked, wait for the peer to
+  // send another PATH_CHALLENGE.
+  WritePacketUsingWriter(std::move(probing_packet), writer,
+                         last_packet_destination_address_, peer_address_to_send,
+                         /*measure_rtt=*/false);
+  return true;
 }
 
 void QuicConnection::UpdatePeerAddress(QuicSocketAddress peer_address) {
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 2f5c09f..14716ce 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -8487,7 +8487,7 @@
                       sizeof(challenge_data)));
 }
 
-TEST_P(QuicConnectionTest, ClientResponseToPathChallenge) {
+TEST_P(QuicConnectionTest, ClientResponseToPathChallengeOnDefaulSocket) {
   if (!VersionHasIetfQuicFrames(connection_.version().transport_version) ||
       !connection_.send_path_response()) {
     return;
@@ -8528,6 +8528,57 @@
                       sizeof(challenge_data)));
 }
 
+TEST_P(QuicConnectionTest, ClientResponseToPathChallengeOnAlternativeSocket) {
+  if (!VersionHasIetfQuicFrames(connection_.version().transport_version) ||
+      !connection_.send_path_response()) {
+    return;
+  }
+  PathProbeTestInit(Perspective::IS_CLIENT);
+  QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false);
+
+  QuicSocketAddress kNewSelfAddress(QuicIpAddress::Loopback6(), /*port=*/23456);
+  TestPacketWriter new_writer(version(), &clock_, Perspective::IS_CLIENT);
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .Times(AtLeast(1u))
+      .WillOnce(Invoke([&]() {
+        EXPECT_EQ(1u, new_writer.packets_write_attempts());
+        EXPECT_EQ(1u, new_writer.path_challenge_frames().size());
+        EXPECT_EQ(1u, new_writer.padding_frames().size());
+        EXPECT_EQ(kNewSelfAddress.host(),
+                  new_writer.last_write_source_address());
+      }));
+  bool success = false;
+  connection_.ValidatePath(
+      std::make_unique<TestQuicPathValidationContext>(
+          kNewSelfAddress, connection_.peer_address(), &new_writer),
+      std::make_unique<TestValidationResultDelegate>(
+          kNewSelfAddress, connection_.peer_address(), &success));
+
+  // Receiving a PATH_CHALLENGE on the alternative path. Response to this
+  // PATH_CHALLENGE should be sent via the alternative writer.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .Times(AtLeast(1u))
+      .WillOnce(Invoke([&]() {
+        EXPECT_EQ(2u, new_writer.packets_write_attempts());
+        EXPECT_EQ(1u, new_writer.path_response_frames().size());
+        EXPECT_EQ(1u, new_writer.padding_frames().size());
+        EXPECT_EQ(kNewSelfAddress.host(),
+                  new_writer.last_write_source_address());
+      }));
+  std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket();
+  std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
+      QuicEncryptedPacket(probing_packet->encrypted_buffer,
+                          probing_packet->encrypted_length),
+      clock_.Now()));
+  ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received);
+
+  QuicSocketAddress kNewerSelfAddress(QuicIpAddress::Loopback6(),
+                                      /*port=*/34567);
+  // Receiving a PATH_CHALLENGE on an unknown socket should be ignored.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0u);
+  ProcessReceivedPacket(kNewerSelfAddress, kPeerAddress, *received);
+}
+
 TEST_P(QuicConnectionTest,
        RestartPathDegradingDetectionAfterMigrationWithProbe) {
   // TODO(b/150095484): add test coverage for IETF to verify that client takes