xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_path_validator.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/core/quic_path_validator.h"
6 
7 #include "quiche/quic/core/quic_constants.h"
8 #include "quiche/quic/core/quic_types.h"
9 #include "quiche/quic/platform/api/quic_socket_address.h"
10 
11 namespace quic {
12 
13 class RetryAlarmDelegate : public QuicAlarm::DelegateWithContext {
14  public:
RetryAlarmDelegate(QuicPathValidator * path_validator,QuicConnectionContext * context)15   explicit RetryAlarmDelegate(QuicPathValidator* path_validator,
16                               QuicConnectionContext* context)
17       : QuicAlarm::DelegateWithContext(context),
18         path_validator_(path_validator) {}
19   RetryAlarmDelegate(const RetryAlarmDelegate&) = delete;
20   RetryAlarmDelegate& operator=(const RetryAlarmDelegate&) = delete;
21 
OnAlarm()22   void OnAlarm() override { path_validator_->OnRetryTimeout(); }
23 
24  private:
25   QuicPathValidator* path_validator_;
26 };
27 
operator <<(std::ostream & os,const QuicPathValidationContext & context)28 std::ostream& operator<<(std::ostream& os,
29                          const QuicPathValidationContext& context) {
30   return os << " from " << context.self_address_ << " to "
31             << context.peer_address_;
32 }
33 
QuicPathValidator(QuicAlarmFactory * alarm_factory,QuicConnectionArena * arena,SendDelegate * send_delegate,QuicRandom * random,const QuicClock * clock,QuicConnectionContext * context)34 QuicPathValidator::QuicPathValidator(QuicAlarmFactory* alarm_factory,
35                                      QuicConnectionArena* arena,
36                                      SendDelegate* send_delegate,
37                                      QuicRandom* random, const QuicClock* clock,
38                                      QuicConnectionContext* context)
39     : send_delegate_(send_delegate),
40       random_(random),
41       clock_(clock),
42       retry_timer_(alarm_factory->CreateAlarm(
43           arena->New<RetryAlarmDelegate>(this, context), arena)),
44       retry_count_(0u) {}
45 
OnPathResponse(const QuicPathFrameBuffer & probing_data,QuicSocketAddress self_address)46 void QuicPathValidator::OnPathResponse(const QuicPathFrameBuffer& probing_data,
47                                        QuicSocketAddress self_address) {
48   if (!HasPendingPathValidation()) {
49     return;
50   }
51 
52   QUIC_DVLOG(1) << "Match PATH_RESPONSE received on " << self_address;
53   QUIC_BUG_IF(quic_bug_12402_1, !path_context_->self_address().IsInitialized())
54       << "Self address should have been known by now";
55   if (self_address != path_context_->self_address()) {
56     QUIC_DVLOG(1) << "Expect the response to be received on "
57                   << path_context_->self_address();
58     return;
59   }
60   // This iterates at most 3 times.
61   for (auto it = probing_data_.begin(); it != probing_data_.end(); ++it) {
62     if (it->frame_buffer == probing_data) {
63       result_delegate_->OnPathValidationSuccess(std::move(path_context_),
64                                                 it->send_time);
65       ResetPathValidation();
66       return;
67     }
68   }
69   QUIC_DVLOG(1) << "PATH_RESPONSE with payload " << probing_data.data()
70                 << " doesn't match the probing data.";
71 }
72 
StartPathValidation(std::unique_ptr<QuicPathValidationContext> context,std::unique_ptr<ResultDelegate> result_delegate,PathValidationReason reason)73 void QuicPathValidator::StartPathValidation(
74     std::unique_ptr<QuicPathValidationContext> context,
75     std::unique_ptr<ResultDelegate> result_delegate,
76     PathValidationReason reason) {
77   QUICHE_DCHECK(context);
78   QUIC_DLOG(INFO) << "Start validating path " << *context
79                   << " via writer: " << context->WriterToUse();
80   if (path_context_ != nullptr) {
81     QUIC_BUG(quic_bug_10876_1)
82         << "There is an on-going validation on path " << *path_context_;
83     ResetPathValidation();
84   }
85 
86   reason_ = reason;
87   path_context_ = std::move(context);
88   result_delegate_ = std::move(result_delegate);
89   SendPathChallengeAndSetAlarm();
90 }
91 
ResetPathValidation()92 void QuicPathValidator::ResetPathValidation() {
93   path_context_ = nullptr;
94   result_delegate_ = nullptr;
95   retry_timer_->Cancel();
96   retry_count_ = 0;
97   reason_ = PathValidationReason::kReasonUnknown;
98 }
99 
CancelPathValidation()100 void QuicPathValidator::CancelPathValidation() {
101   if (path_context_ == nullptr) {
102     return;
103   }
104   QUIC_DVLOG(1) << "Cancel validation on path" << *path_context_;
105   result_delegate_->OnPathValidationFailure(std::move(path_context_));
106   ResetPathValidation();
107 }
108 
HasPendingPathValidation() const109 bool QuicPathValidator::HasPendingPathValidation() const {
110   return path_context_ != nullptr;
111 }
112 
GetContext() const113 QuicPathValidationContext* QuicPathValidator::GetContext() const {
114   return path_context_.get();
115 }
116 
ReleaseContext()117 std::unique_ptr<QuicPathValidationContext> QuicPathValidator::ReleaseContext() {
118   auto ret = std::move(path_context_);
119   ResetPathValidation();
120   return ret;
121 }
122 
GeneratePathChallengePayload()123 const QuicPathFrameBuffer& QuicPathValidator::GeneratePathChallengePayload() {
124   probing_data_.emplace_back(clock_->Now());
125   random_->RandBytes(probing_data_.back().frame_buffer.data(),
126                      sizeof(QuicPathFrameBuffer));
127   return probing_data_.back().frame_buffer;
128 }
129 
OnRetryTimeout()130 void QuicPathValidator::OnRetryTimeout() {
131   ++retry_count_;
132   if (retry_count_ > kMaxRetryTimes) {
133     CancelPathValidation();
134     return;
135   }
136   QUIC_DVLOG(1) << "Send another PATH_CHALLENGE on path " << *path_context_;
137   SendPathChallengeAndSetAlarm();
138 }
139 
SendPathChallengeAndSetAlarm()140 void QuicPathValidator::SendPathChallengeAndSetAlarm() {
141   bool should_continue = send_delegate_->SendPathChallenge(
142       GeneratePathChallengePayload(), path_context_->self_address(),
143       path_context_->peer_address(), path_context_->effective_peer_address(),
144       path_context_->WriterToUse());
145 
146   if (!should_continue) {
147     // The delegate doesn't want to continue the path validation.
148     CancelPathValidation();
149     return;
150   }
151   retry_timer_->Set(send_delegate_->GetRetryTimeout(
152       path_context_->peer_address(), path_context_->WriterToUse()));
153 }
154 
IsValidatingPeerAddress(const QuicSocketAddress & effective_peer_address)155 bool QuicPathValidator::IsValidatingPeerAddress(
156     const QuicSocketAddress& effective_peer_address) {
157   return path_context_ != nullptr &&
158          path_context_->effective_peer_address() == effective_peer_address;
159 }
160 
MaybeWritePacketToAddress(const char * buffer,size_t buf_len,const QuicSocketAddress & peer_address)161 void QuicPathValidator::MaybeWritePacketToAddress(
162     const char* buffer, size_t buf_len, const QuicSocketAddress& peer_address) {
163   if (!HasPendingPathValidation() ||
164       path_context_->peer_address() != peer_address) {
165     return;
166   }
167   QUIC_DVLOG(1) << "Path validator is sending packet of size " << buf_len
168                 << " from " << path_context_->self_address() << " to "
169                 << path_context_->peer_address();
170   path_context_->WriterToUse()->WritePacket(
171       buffer, buf_len, path_context_->self_address().host(),
172       path_context_->peer_address(), nullptr, QuicPacketWriterParams());
173 }
174 
175 }  // namespace quic
176