Modifications to QuicPathValidator.

Add effective peer address to PathValidationContext and pass it to SendPathChallenge().

CancelPathValidation() to call validation failure callback.

Add a QUIC_BUG to prevent StartValidatingPath() to be called while there is on-going validation.

PiperOrigin-RevId: 348542080
Change-Id: I5ce4f2a7ea4b621ce6a2c25c1852a86b454c9b58
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index 1599d10..a8067cd 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -5380,10 +5380,12 @@
   return sent_packet_manager_.GetRetransmissionTime();
 }
 
-bool QuicConnection::SendPathChallenge(const QuicPathFrameBuffer& data_buffer,
-                                       const QuicSocketAddress& self_address,
-                                       const QuicSocketAddress& peer_address,
-                                       QuicPacketWriter* writer) {
+bool QuicConnection::SendPathChallenge(
+    const QuicPathFrameBuffer& data_buffer,
+    const QuicSocketAddress& self_address,
+    const QuicSocketAddress& peer_address,
+    const QuicSocketAddress& /*effective_peer_address*/,
+    QuicPacketWriter* writer) {
   if (writer == writer_) {
     {
       // It's on current path, add the PATH_CHALLENGE the same way as other
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h
index dd453cb..02f70de 100644
--- a/quic/core/quic_connection.h
+++ b/quic/core/quic_connection.h
@@ -1129,6 +1129,7 @@
   bool SendPathChallenge(const QuicPathFrameBuffer& data_buffer,
                          const QuicSocketAddress& self_address,
                          const QuicSocketAddress& peer_address,
+                         const QuicSocketAddress& effective_peer_address,
                          QuicPacketWriter* writer) override;
   // If |writer| is the default writer and |peer_address| is the same as
   // peer_address(), return the PTO of this connection. Otherwise, return 3 *
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 5d26ab0..c1ce8b4 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -6395,8 +6395,9 @@
     QuicPathFrameBuffer payload{
         {0xde, 0xad, 0xbe, 0xef, 0xba, 0xdc, 0x0f, 0xfe}};
     QuicConnection::ScopedPacketFlusher flusher(&connection_);
-    connection_.SendPathChallenge(payload, connection_.self_address(),
-                                  connection_.peer_address(), writer_.get());
+    connection_.SendPathChallenge(
+        payload, connection_.self_address(), connection_.peer_address(),
+        connection_.effective_peer_address(), writer_.get());
   } else {
     connection_.SendConnectivityProbingPacket(writer_.get(),
                                               connection_.peer_address());
diff --git a/quic/core/quic_path_validator.cc b/quic/core/quic_path_validator.cc
index fe9e046..0722216 100644
--- a/quic/core/quic_path_validator.cc
+++ b/quic/core/quic_path_validator.cc
@@ -59,16 +59,22 @@
       probing_data_.end()) {
     result_delegate_->OnPathValidationSuccess(std::move(path_context_));
     ResetPathValidation();
+  } else {
+    QUIC_DVLOG(1) << "PATH_RESPONSE with payload " << probing_data.data()
+                  << " doesn't match the probing data.";
   }
 }
 
 void QuicPathValidator::StartPathValidation(
     std::unique_ptr<QuicPathValidationContext> context,
     std::unique_ptr<ResultDelegate> result_delegate) {
-  CancelPathValidation();
   DCHECK_NE(nullptr, context);
   QUIC_DLOG(INFO) << "Start validating path " << *context
                   << " via writer: " << context->WriterToUse();
+  if (path_context_ != nullptr) {
+    QUIC_BUG << "There is an on-going validation on path " << *path_context_;
+    ResetPathValidation();
+  }
 
   path_context_ = std::move(context);
   result_delegate_ = std::move(result_delegate);
@@ -87,6 +93,7 @@
     return;
   }
   QUIC_DVLOG(1) << "Cancel validation on path" << *path_context_;
+  result_delegate_->OnPathValidationFailure(std::move(path_context_));
   ResetPathValidation();
 }
 
@@ -107,7 +114,6 @@
 void QuicPathValidator::OnRetryTimeout() {
   ++retry_count_;
   if (retry_count_ > kMaxRetryTimes) {
-    result_delegate_->OnPathValidationFailure(std::move(path_context_));
     CancelPathValidation();
     return;
   }
@@ -118,7 +124,8 @@
 void QuicPathValidator::SendPathChallengeAndSetAlarm() {
   bool should_continue = send_delegate_->SendPathChallenge(
       GeneratePathChallengePayload(), path_context_->self_address(),
-      path_context_->peer_address(), path_context_->WriterToUse());
+      path_context_->peer_address(), path_context_->effective_peer_address(),
+      path_context_->WriterToUse());
 
   if (!should_continue) {
     // The delegate doesn't want to continue the path validation.
diff --git a/quic/core/quic_path_validator.h b/quic/core/quic_path_validator.h
index b9c9c5d..1463720 100644
--- a/quic/core/quic_path_validator.h
+++ b/quic/core/quic_path_validator.h
@@ -31,7 +31,16 @@
  public:
   QuicPathValidationContext(const QuicSocketAddress& self_address,
                             const QuicSocketAddress& peer_address)
-      : self_address_(self_address), peer_address_(peer_address) {}
+      : self_address_(self_address),
+        peer_address_(peer_address),
+        effective_peer_address_(peer_address) {}
+
+  QuicPathValidationContext(const QuicSocketAddress& self_address,
+                            const QuicSocketAddress& peer_address,
+                            const QuicSocketAddress& effective_peer_address)
+      : self_address_(self_address),
+        peer_address_(peer_address),
+        effective_peer_address_(effective_peer_address) {}
 
   virtual ~QuicPathValidationContext() = default;
 
@@ -39,6 +48,9 @@
 
   const QuicSocketAddress& self_address() const { return self_address_; }
   const QuicSocketAddress& peer_address() const { return peer_address_; }
+  const QuicSocketAddress& effective_peer_address() const {
+    return effective_peer_address_;
+  }
 
  private:
   QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(
@@ -46,7 +58,11 @@
       const QuicPathValidationContext& context);
 
   QuicSocketAddress self_address_;
+  // The address to send PATH_CHALLENGE.
   QuicSocketAddress peer_address_;
+  // The actual peer address which is different from |peer_address_| if the peer
+  // is behind a proxy.
+  QuicSocketAddress effective_peer_address_;
 };
 
 // Used to validate a path by sending up to 3 PATH_CHALLENGE frames before
@@ -64,10 +80,12 @@
     // Send a PATH_CHALLENGE with |data_buffer| as the frame payload using given
     // path information. Return false if the delegate doesn't want to continue
     // the validation.
-    virtual bool SendPathChallenge(const QuicPathFrameBuffer& data_buffer,
-                                   const QuicSocketAddress& self_address,
-                                   const QuicSocketAddress& peer_address,
-                                   QuicPacketWriter* writer) = 0;
+    virtual bool SendPathChallenge(
+        const QuicPathFrameBuffer& data_buffer,
+        const QuicSocketAddress& self_address,
+        const QuicSocketAddress& peer_address,
+        const QuicSocketAddress& effective_peer_address,
+        QuicPacketWriter* writer) = 0;
     // Return the time to retry sending PATH_CHALLENGE again based on given peer
     // address and writer.
     virtual QuicTime GetRetryTimeout(const QuicSocketAddress& peer_address,
diff --git a/quic/core/quic_path_validator_test.cc b/quic/core/quic_path_validator_test.cc
index 5fd7f9f..fab0c7c 100644
--- a/quic/core/quic_path_validator_test.cc
+++ b/quic/core/quic_path_validator_test.cc
@@ -35,6 +35,7 @@
               (const QuicPathFrameBuffer&,
                const QuicSocketAddress&,
                const QuicSocketAddress&,
+               const QuicSocketAddress&,
                QuicPacketWriter*),
               (override));
 
@@ -50,8 +51,10 @@
       : path_validator_(&alarm_factory_, &arena_, &send_delegate_, &random_),
         context_(new MockQuicPathValidationContext(self_address_,
                                                    peer_address_,
+                                                   effective_peer_address_,
                                                    &writer_)),
-        result_delegate_(new MockQuicPathValidationResultDelegate()) {
+        result_delegate_(
+            new testing::StrictMock<MockQuicPathValidationResultDelegate>()) {
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
     ON_CALL(send_delegate_, GetRetryTimeout(_, _))
         .WillByDefault(
@@ -68,6 +71,7 @@
   QuicPathValidator path_validator_;
   QuicSocketAddress self_address_{QuicIpAddress::Any4(), 443};
   QuicSocketAddress peer_address_{QuicIpAddress::Loopback4(), 443};
+  QuicSocketAddress effective_peer_address_{QuicIpAddress::Loopback4(), 12345};
   MockPacketWriter writer_;
   MockQuicPathValidationContext* context_;
   MockQuicPathValidationResultDelegate* result_delegate_;
@@ -76,10 +80,11 @@
 TEST_F(QuicPathValidatorTest, PathValidationSuccessOnFirstRound) {
   QuicPathFrameBuffer challenge_data;
   EXPECT_CALL(send_delegate_,
-              SendPathChallenge(_, self_address_, peer_address_, &writer_))
+              SendPathChallenge(_, self_address_, peer_address_,
+                                effective_peer_address_, &writer_))
       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
                            const QuicSocketAddress&, const QuicSocketAddress&,
-                           QuicPacketWriter*) {
+                           const QuicSocketAddress&, QuicPacketWriter*) {
         memcpy(challenge_data.data(), payload.data(), payload.size());
         return true;
       }));
@@ -99,10 +104,11 @@
 TEST_F(QuicPathValidatorTest, RespondWithDifferentSelfAddress) {
   QuicPathFrameBuffer challenge_data;
   EXPECT_CALL(send_delegate_,
-              SendPathChallenge(_, self_address_, peer_address_, &writer_))
+              SendPathChallenge(_, self_address_, peer_address_,
+                                effective_peer_address_, &writer_))
       .WillOnce(Invoke([&](const QuicPathFrameBuffer payload,
                            const QuicSocketAddress&, const QuicSocketAddress&,
-                           QuicPacketWriter*) {
+                           const QuicSocketAddress&, QuicPacketWriter*) {
         memcpy(challenge_data.data(), payload.data(), payload.size());
         return true;
       }));
@@ -126,17 +132,18 @@
 TEST_F(QuicPathValidatorTest, RespondAfter1stRetry) {
   QuicPathFrameBuffer challenge_data;
   EXPECT_CALL(send_delegate_,
-              SendPathChallenge(_, self_address_, peer_address_, &writer_))
+              SendPathChallenge(_, self_address_, peer_address_,
+                                effective_peer_address_, &writer_))
       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
                            const QuicSocketAddress&, const QuicSocketAddress&,
-                           QuicPacketWriter*) {
+                           const QuicSocketAddress&, QuicPacketWriter*) {
         // Store up the 1st PATH_CHALLANGE payload.
         memcpy(challenge_data.data(), payload.data(), payload.size());
         return true;
       }))
       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
                            const QuicSocketAddress&, const QuicSocketAddress&,
-                           QuicPacketWriter*) {
+                           const QuicSocketAddress&, QuicPacketWriter*) {
         EXPECT_NE(payload, challenge_data);
         return true;
       }));
@@ -160,16 +167,17 @@
 TEST_F(QuicPathValidatorTest, RespondToRetryChallenge) {
   QuicPathFrameBuffer challenge_data;
   EXPECT_CALL(send_delegate_,
-              SendPathChallenge(_, self_address_, peer_address_, &writer_))
+              SendPathChallenge(_, self_address_, peer_address_,
+                                effective_peer_address_, &writer_))
       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
                            const QuicSocketAddress&, const QuicSocketAddress&,
-                           QuicPacketWriter*) {
+                           const QuicSocketAddress&, QuicPacketWriter*) {
         memcpy(challenge_data.data(), payload.data(), payload.size());
         return true;
       }))
       .WillOnce(Invoke([&](const QuicPathFrameBuffer& payload,
                            const QuicSocketAddress&, const QuicSocketAddress&,
-                           QuicPacketWriter*) {
+                           const QuicSocketAddress&, QuicPacketWriter*) {
         EXPECT_NE(challenge_data, payload);
         memcpy(challenge_data.data(), payload.data(), payload.size());
         return true;
@@ -193,7 +201,8 @@
 
 TEST_F(QuicPathValidatorTest, ValidationTimeOut) {
   EXPECT_CALL(send_delegate_,
-              SendPathChallenge(_, self_address_, peer_address_, &writer_))
+              SendPathChallenge(_, self_address_, peer_address_,
+                                effective_peer_address_, &writer_))
       .Times(3u)
       .WillRepeatedly(Return(true));
   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_))
@@ -221,9 +230,11 @@
 
 TEST_F(QuicPathValidatorTest, SendPathChallengeError) {
   EXPECT_CALL(send_delegate_,
-              SendPathChallenge(_, self_address_, peer_address_, &writer_))
+              SendPathChallenge(_, self_address_, peer_address_,
+                                effective_peer_address_, &writer_))
       .WillOnce(Invoke([&](const QuicPathFrameBuffer&, const QuicSocketAddress&,
-                           const QuicSocketAddress&, QuicPacketWriter*) {
+                           const QuicSocketAddress&, const QuicSocketAddress&,
+                           QuicPacketWriter*) {
         // Abandon this validation in the call stack shouldn't cause crash and
         // should cancel the alarm.
         path_validator_.CancelPathValidation();
@@ -231,6 +242,7 @@
       }));
   EXPECT_CALL(send_delegate_, GetRetryTimeout(peer_address_, &writer_))
       .Times(0u);
+  EXPECT_CALL(*result_delegate_, OnPathValidationFailure(_));
   path_validator_.StartPathValidation(
       std::unique_ptr<QuicPathValidationContext>(context_),
       std::unique_ptr<MockQuicPathValidationResultDelegate>(result_delegate_));
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h
index 428d695..e78839a 100644
--- a/quic/test_tools/quic_test_utils.h
+++ b/quic/test_tools/quic_test_utils.h
@@ -734,6 +734,7 @@
               (const QuicPathFrameBuffer&,
                const QuicSocketAddress&,
                const QuicSocketAddress&,
+               const QuicSocketAddress&,
                QuicPacketWriter*),
               (override));
 
@@ -1658,8 +1659,11 @@
  public:
   MockQuicPathValidationContext(const QuicSocketAddress& self_address,
                                 const QuicSocketAddress& peer_address,
+                                const QuicSocketAddress& effective_peer_address,
                                 QuicPacketWriter* writer)
-      : QuicPathValidationContext(self_address, peer_address),
+      : QuicPathValidationContext(self_address,
+                                  peer_address,
+                                  effective_peer_address),
         writer_(writer) {}
   QuicPacketWriter* WriterToUse() override { return writer_; }