blob: 37faca3f4b094e1184a87b9f911fe207ca18d430 [file] [log] [blame]
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <ostream>
#include "absl/container/inlined_vector.h"
#include "quiche/quic/core/crypto/quic_random.h"
#include "quiche/quic/core/quic_alarm.h"
#include "quiche/quic/core/quic_alarm_factory.h"
#include "quiche/quic/core/quic_arena_scoped_ptr.h"
#include "quiche/quic/core/quic_clock.h"
#include "quiche/quic/core/quic_connection_context.h"
#include "quiche/quic/core/quic_one_block_arena.h"
#include "quiche/quic/core/quic_packet_writer.h"
#include "quiche/quic/core/quic_time.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_export.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
namespace quic {
namespace test {
class QuicPathValidatorPeer;
class QuicConnection;
enum class PathValidationReason {
// Interface to provide the information of the path to be validated.
class QUICHE_EXPORT QuicPathValidationContext {
QuicPathValidationContext(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address)
: self_address_(self_address),
effective_peer_address_(peer_address) {}
QuicPathValidationContext(const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
const QuicSocketAddress& effective_peer_address)
: self_address_(self_address),
effective_peer_address_(effective_peer_address) {}
virtual ~QuicPathValidationContext() = default;
virtual QuicPacketWriter* WriterToUse() = 0;
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_;
QUICHE_EXPORT friend std::ostream& operator<<(
std::ostream& os, 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
// declaring a path validation failure.
class QUICHE_EXPORT QuicPathValidator {
static const uint16_t kMaxRetryTimes = 2;
// Used to write PATH_CHALLENGE on the path to be validated and to get retry
// timeout.
class QUICHE_EXPORT SendDelegate {
virtual ~SendDelegate() = default;
// 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,
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,
QuicPacketWriter* writer) const = 0;
// Handles the validation result.
// TODO(danzh) consider to simplify this interface and its life time to
// outlive a validation.
class QUICHE_EXPORT ResultDelegate {
virtual ~ResultDelegate() = default;
// Called when a PATH_RESPONSE is received with a matching PATH_CHALLANGE.
// |start_time| is the time when the matching PATH_CHALLANGE was sent.
virtual void OnPathValidationSuccess(
std::unique_ptr<QuicPathValidationContext> context,
QuicTime start_time) = 0;
virtual void OnPathValidationFailure(
std::unique_ptr<QuicPathValidationContext> context) = 0;
QuicPathValidator(QuicAlarmFactory* alarm_factory, QuicConnectionArena* arena,
SendDelegate* delegate, QuicRandom* random,
const QuicClock* clock, QuicConnectionContext* context);
// Send PATH_CHALLENGE and start the retry timer.
void StartPathValidation(std::unique_ptr<QuicPathValidationContext> context,
std::unique_ptr<ResultDelegate> result_delegate,
PathValidationReason reason);
// Called when a PATH_RESPONSE frame has been received. Matches the received
// PATH_RESPONSE payload with the payloads previously sent in PATH_CHALLANGE
// frames and the self address on which it was sent.
void OnPathResponse(const QuicPathFrameBuffer& probing_data,
QuicSocketAddress self_address);
// Cancel the retry timer and reset the path and result delegate.
void CancelPathValidation();
bool HasPendingPathValidation() const;
QuicPathValidationContext* GetContext() const;
// Pass the ownership of path_validation context to the caller and reset the
// validator.
std::unique_ptr<QuicPathValidationContext> ReleaseContext();
PathValidationReason GetPathValidationReason() const { return reason_; }
// Send another PATH_CHALLENGE on the same path. After retrying
// |kMaxRetryTimes| times, fail the current path validation.
void OnRetryTimeout();
bool IsValidatingPeerAddress(const QuicSocketAddress& effective_peer_address);
// Called to send packet to |peer_address| if the path validation to this
// address is pending.
void MaybeWritePacketToAddress(const char* buffer, size_t buf_len,
const QuicSocketAddress& peer_address);
friend class test::QuicPathValidatorPeer;
// Return the payload to be used in the next PATH_CHALLENGE frame.
const QuicPathFrameBuffer& GeneratePathChallengePayload();
void SendPathChallengeAndSetAlarm();
void ResetPathValidation();
struct QUICHE_EXPORT ProbingData {
explicit ProbingData(QuicTime send_time) : send_time(send_time) {}
QuicPathFrameBuffer frame_buffer;
QuicTime send_time;
// Has at most 3 entries due to validation timeout.
absl::InlinedVector<ProbingData, 3> probing_data_;
SendDelegate* send_delegate_;
QuicRandom* random_;
const QuicClock* clock_;
std::unique_ptr<QuicPathValidationContext> path_context_;
std::unique_ptr<ResultDelegate> result_delegate_;
QuicArenaScopedPtr<QuicAlarm> retry_timer_;
size_t retry_count_;
PathValidationReason reason_ = PathValidationReason::kReasonUnknown;
} // namespace quic