diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-11-18 16:35:47 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-11-18 15:45:54 +0000 |
commit | 32f5a1c56531e4210bc4cf8d8c7825d66e081888 (patch) | |
tree | eeeec6822f4d738d8454525233fd0e2e3a659e6d /chromium/net/third_party | |
parent | 99677208ff3b216fdfec551fbe548da5520cd6fb (diff) | |
download | qtwebengine-chromium-32f5a1c56531e4210bc4cf8d8c7825d66e081888.tar.gz |
BASELINE: Update Chromium to 87.0.4280.67
Change-Id: Ib157360be8c2ffb2c73125751a89f60e049c1d54
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/third_party')
173 files changed, 5434 insertions, 4363 deletions
diff --git a/chromium/net/third_party/quiche/BUILD.gn b/chromium/net/third_party/quiche/BUILD.gn index 836245d848b..ffab81e2122 100644 --- a/chromium/net/third_party/quiche/BUILD.gn +++ b/chromium/net/third_party/quiche/BUILD.gn @@ -5,6 +5,16 @@ import("//testing/libfuzzer/fuzzer_test.gni") import("//third_party/protobuf/proto_library.gni") +# Since //net and //net/third_party/quiche have a circular dependency on each +# other, exporting dependencies from the :quiche target directly does not work. +# Thus, all public dependencies for QUICHE should go into the target below, +# which is in turn propagated to all of //net source sets. +source_set("quiche_public_deps") { + visibility = [ "//net:net_public_deps" ] + + public_deps = [ "//third_party/abseil-cpp:absl" ] +} + source_set("quiche") { sources = [ "src/quic/core/quic_error_codes.cc", @@ -17,7 +27,6 @@ source_set("quiche") { "src/common/platform/api/quiche_endian.h", "src/common/platform/api/quiche_export.h", "src/common/platform/api/quiche_logging.h", - "src/common/platform/api/quiche_map_util.h", "src/common/platform/api/quiche_optional.h", "src/common/platform/api/quiche_ptr_util.h", "src/common/platform/api/quiche_str_cat.h", @@ -1367,7 +1376,6 @@ source_set("quiche_tests") { "src/quic/core/quic_versions_test.cc", "src/quic/core/quic_write_blocked_list_test.cc", "src/quic/core/tls_chlo_extractor_test.cc", - "src/quic/core/tls_handshaker_test.cc", "src/quic/core/uber_quic_stream_id_manager_test.cc", "src/quic/core/uber_received_packet_manager_test.cc", "src/quic/platform/api/quic_containers_test.cc", diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h index f8a9ee68665..69bdc5bf029 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian.h @@ -5,8 +5,11 @@ #ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_ENDIAN_H_ #define QUICHE_COMMON_PLATFORM_API_QUICHE_ENDIAN_H_ +#include <algorithm> +#include <cstdint> +#include <type_traits> + #include "net/third_party/quiche/src/common/platform/api/quiche_export.h" -#include "net/quiche/common/platform/impl/quiche_endian_impl.h" namespace quiche { @@ -20,33 +23,38 @@ enum Endianness { // platform). class QUICHE_EXPORT_PRIVATE QuicheEndian { public: - // Convert |x| from host order (can be either little or big endian depending - // on the platform) to network order (big endian). - static uint16_t HostToNet16(uint16_t x) { - return QuicheEndianImpl::HostToNet16(x); - } - static uint32_t HostToNet32(uint32_t x) { - return QuicheEndianImpl::HostToNet32(x); - } - static uint64_t HostToNet64(uint64_t x) { - return QuicheEndianImpl::HostToNet64(x); - } - - // Convert |x| from network order (big endian) to host order (can be either - // little or big endian depending on the platform). - static uint16_t NetToHost16(uint16_t x) { - return QuicheEndianImpl::NetToHost16(x); - } - static uint32_t NetToHost32(uint32_t x) { - return QuicheEndianImpl::NetToHost32(x); - } - static uint64_t NetToHost64(uint64_t x) { - return QuicheEndianImpl::NetToHost64(x); - } + // Convert |x| from host order (little endian) to network order (big endian). +#if defined(__clang__) || \ + (defined(__GNUC__) && \ + ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5)) + static uint16_t HostToNet16(uint16_t x) { return __builtin_bswap16(x); } + static uint32_t HostToNet32(uint32_t x) { return __builtin_bswap32(x); } + static uint64_t HostToNet64(uint64_t x) { return __builtin_bswap64(x); } +#else + static uint16_t HostToNet16(uint16_t x) { return PortableByteSwap(x); } + static uint32_t HostToNet32(uint32_t x) { return PortableByteSwap(x); } + static uint64_t HostToNet64(uint64_t x) { return PortableByteSwap(x); } +#endif + + // Convert |x| from network order (big endian) to host order (little endian). + static uint16_t NetToHost16(uint16_t x) { return HostToNet16(x); } + static uint32_t NetToHost32(uint32_t x) { return HostToNet32(x); } + static uint64_t NetToHost64(uint64_t x) { return HostToNet64(x); } // Returns true if current host order is little endian. - static bool HostIsLittleEndian() { - return QuicheEndianImpl::HostIsLittleEndian(); + static bool HostIsLittleEndian() { return true; } + + // Left public for tests. + template <typename T> + static T PortableByteSwap(T input) { + static_assert(std::is_unsigned<T>::value, "T has to be uintNN_t"); + union { + T number; + char bytes[sizeof(T)]; + } value; + value.number = input; + std::reverse(std::begin(value.bytes), std::end(value.bytes)); + return value.number; } }; diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc index 98e16febd2f..2f21938b087 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_endian_test.cc @@ -18,40 +18,33 @@ const uint64_t k64BitSwappedTestData = 0x11223344ddccbbaa; class QuicheEndianTest : public QuicheTest {}; +// Test portable version. Since we normally compile with either GCC or Clang, +// it will very rarely used otherwise. +TEST_F(QuicheEndianTest, Portable) { + EXPECT_EQ(k16BitSwappedTestData, + QuicheEndian::PortableByteSwap(k16BitTestData)); + EXPECT_EQ(k32BitSwappedTestData, + QuicheEndian::PortableByteSwap(k32BitTestData)); + EXPECT_EQ(k64BitSwappedTestData, + QuicheEndian::PortableByteSwap(k64BitTestData)); +} + TEST_F(QuicheEndianTest, HostToNet) { - if (quiche::QuicheEndian::HostIsLittleEndian()) { - EXPECT_EQ(k16BitSwappedTestData, - quiche::QuicheEndian::HostToNet16(k16BitTestData)); - EXPECT_EQ(k32BitSwappedTestData, - quiche::QuicheEndian::HostToNet32(k32BitTestData)); - EXPECT_EQ(k64BitSwappedTestData, - quiche::QuicheEndian::HostToNet64(k64BitTestData)); - } else { - EXPECT_EQ(k16BitTestData, - quiche::QuicheEndian::HostToNet16(k16BitTestData)); - EXPECT_EQ(k32BitTestData, - quiche::QuicheEndian::HostToNet32(k32BitTestData)); - EXPECT_EQ(k64BitTestData, - quiche::QuicheEndian::HostToNet64(k64BitTestData)); - } + EXPECT_EQ(k16BitSwappedTestData, + quiche::QuicheEndian::HostToNet16(k16BitTestData)); + EXPECT_EQ(k32BitSwappedTestData, + quiche::QuicheEndian::HostToNet32(k32BitTestData)); + EXPECT_EQ(k64BitSwappedTestData, + quiche::QuicheEndian::HostToNet64(k64BitTestData)); } TEST_F(QuicheEndianTest, NetToHost) { - if (quiche::QuicheEndian::HostIsLittleEndian()) { - EXPECT_EQ(k16BitTestData, - quiche::QuicheEndian::NetToHost16(k16BitSwappedTestData)); - EXPECT_EQ(k32BitTestData, - quiche::QuicheEndian::NetToHost32(k32BitSwappedTestData)); - EXPECT_EQ(k64BitTestData, - quiche::QuicheEndian::NetToHost64(k64BitSwappedTestData)); - } else { - EXPECT_EQ(k16BitSwappedTestData, - quiche::QuicheEndian::NetToHost16(k16BitSwappedTestData)); - EXPECT_EQ(k32BitSwappedTestData, - quiche::QuicheEndian::NetToHost32(k32BitSwappedTestData)); - EXPECT_EQ(k64BitSwappedTestData, - quiche::QuicheEndian::NetToHost64(k64BitSwappedTestData)); - } + EXPECT_EQ(k16BitTestData, + quiche::QuicheEndian::NetToHost16(k16BitSwappedTestData)); + EXPECT_EQ(k32BitTestData, + quiche::QuicheEndian::NetToHost32(k32BitSwappedTestData)); + EXPECT_EQ(k64BitTestData, + quiche::QuicheEndian::NetToHost64(k64BitSwappedTestData)); } } // namespace diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_map_util.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_map_util.h deleted file mode 100644 index b539466caad..00000000000 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_map_util.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2019 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. - -#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_MAP_UTIL_H_ -#define QUICHE_COMMON_PLATFORM_API_QUICHE_MAP_UTIL_H_ - -#include "net/quiche/common/platform/impl/quiche_map_util_impl.h" - -namespace quiche { - -template <class Collection, class Key> -bool QuicheContainsKey(const Collection& collection, const Key& key) { - return QuicheContainsKeyImpl(collection, key); -} - -} // namespace quiche - -#endif // QUICHE_COMMON_PLATFORM_API_QUICHE_MAP_UTIL_H_ diff --git a/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h b/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h index 7a1aa0ed3cc..a59a595813c 100644 --- a/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h +++ b/chromium/net/third_party/quiche/src/common/platform/api/quiche_ptr_util.h @@ -7,13 +7,16 @@ #include <memory> +#include "absl/memory/memory.h" #include "net/quiche/common/platform/impl/quiche_ptr_util_impl.h" namespace quiche { template <typename T> std::unique_ptr<T> QuicheWrapUnique(T* ptr) { - return QuicheWrapUniqueImpl<T>(ptr); + // TODO(b/166325009): replace this in code with absl::WrapUnique and delete + // this function. + return absl::WrapUnique<T>(ptr); } } // namespace quiche diff --git a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h index 6eb6ed9a5dc..36933bc6505 100644 --- a/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h +++ b/chromium/net/third_party/quiche/src/common/simple_linked_hash_map.h @@ -212,7 +212,7 @@ class SimpleLinkedHashMap { typename ListType::iterator last = list_.end(); --last; - CHECK(map_.insert(std::make_pair(pair.first, last)).second) + CHECK(map_.insert(std::make_pair(last->first, last)).second) << "Map and list are inconsistent"; return std::make_pair(last, true); } diff --git a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc index 7e559459e7b..9f9eefd9ab8 100644 --- a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc +++ b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.cc @@ -17,7 +17,8 @@ FakeSimpleEpollServer::FakeSimpleEpollServer() : until_in_usec_(-1) {} FakeSimpleEpollServer::~FakeSimpleEpollServer() = default; -int FakeSimpleEpollServer::epoll_wait_impl(int epfd, struct epoll_event* events, +int FakeSimpleEpollServer::epoll_wait_impl(int /*epfd*/, + struct epoll_event* events, int max_events, int timeout_in_ms) { int num_events = 0; while (!event_queue_.empty() && num_events < max_events && diff --git a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h index cd5bd3a8808..ae435881eea 100644 --- a/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h +++ b/chromium/net/third_party/quiche/src/epoll_server/fake_simple_epoll_server.h @@ -95,14 +95,14 @@ class EPOLL_EXPORT_PRIVATE FakeSimpleEpollServer protected: // functions // These functions do nothing here, as we're not actually // using the epoll_* syscalls. - void DelFD(int fd) const override {} - void AddFD(int fd, int event_mask) const override {} - void ModFD(int fd, int event_mask) const override {} + void DelFD(int /*fd*/) const override {} + void AddFD(int /*fd*/, int /*event_mask*/) const override {} + void ModFD(int /*fd*/, int /*event_mask*/) const override {} // Replaces the epoll_server's epoll_wait_impl. int epoll_wait_impl(int epfd, struct epoll_event* events, int max_events, int timeout_in_ms) override; - void SetNonblocking(int fd) override {} + void SetNonblocking(int /*fd*/) override {} private: // members EventQueue event_queue_; diff --git a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc index 01175421107..1da05ae0a5c 100644 --- a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc +++ b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server.cc @@ -87,7 +87,7 @@ class ReadPipeCallback : public EpollCallbackInterface { data_read = read(fd, &data, sizeof(data)); } } - void OnShutdown(SimpleEpollServer* eps, int fd) override {} + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} void OnRegistration(SimpleEpollServer*, int, int) override {} void OnModification(int, int) override {} // COV_NF_LINE void OnUnregistration(int, bool) override {} // COV_NF_LINE @@ -790,7 +790,7 @@ void EpollAlarm::OnRegistration(const SimpleEpollServer::AlarmRegToken& token, void EpollAlarm::OnUnregistration() { registered_ = false; } -void EpollAlarm::OnShutdown(SimpleEpollServer* eps) { +void EpollAlarm::OnShutdown(SimpleEpollServer* /*eps*/) { registered_ = false; eps_ = NULL; } diff --git a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc index dbc3292f96d..9ec23666048 100644 --- a/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc +++ b/chromium/net/third_party/quiche/src/epoll_server/simple_epoll_server_test.cc @@ -151,7 +151,8 @@ class RecordingCB : public EpollCallbackInterface { delete recorder_; } - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { + void OnRegistration(SimpleEpollServer* /*eps*/, int fd, + int event_mask) override { recorder_->Record(this, REGISTRATION, fd, event_mask); } @@ -565,7 +566,7 @@ class TestAlarm : public EpollAlarmCallbackInterface { } } - void OnShutdown(SimpleEpollServer* eps) override { + void OnShutdown(SimpleEpollServer* /*eps*/) override { onshutdown_called_ = true; has_token_ = false; } @@ -657,7 +658,7 @@ class TestChildAlarm : public TestAlarm { parent_->OnShutdown(this, eps); } void OnRegistration(const SimpleEpollServer::AlarmRegToken& token, - SimpleEpollServer* eps) override { + SimpleEpollServer* /*eps*/) override { parent_->OnRegistration(this, token); } @@ -766,7 +767,7 @@ class TestAlarmUnregister : public TestAlarm { delete iterator_token_; } - void OnShutdown(SimpleEpollServer* eps) override { + void OnShutdown(SimpleEpollServer* /*eps*/) override { onshutdown_called_ = true; } @@ -778,7 +779,7 @@ class TestAlarmUnregister : public TestAlarm { } void OnRegistration(const SimpleEpollServer::AlarmRegToken& token, - SimpleEpollServer* eps) override { + SimpleEpollServer* /*eps*/) override { // Multiple iterator tokens are not maintained by this code, // so we should have reset the iterator_token in OnAlarm or // OnUnregistration. @@ -1562,7 +1563,7 @@ class UnregisterCB : public EpollCallbackInterface { ~UnregisterCB() override { } - void OnShutdown(SimpleEpollServer* eps, int fd) override { + void OnShutdown(SimpleEpollServer* /*eps*/, int fd) override { eps_->UnregisterFD(fd_); eps_->UnregisterFD(fd); onshutdown_called_ = true; @@ -1572,11 +1573,11 @@ class UnregisterCB : public EpollCallbackInterface { void set_epollserver(SimpleEpollServer* eps) { eps_ = eps; } bool onshutdown_called() { return onshutdown_called_; } - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { - } - void OnModification(int fd, int event_mask) override {} - void OnEvent(int fd, EpollEvent* event) override {} - void OnUnregistration(int fd, bool replaced) override {} + void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, + int /*event_mask*/) override {} + void OnModification(int /*fd*/, int /*event_mask*/) override {} + void OnEvent(int /*fd*/, EpollEvent* /*event*/) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} std::string Name() const override { return "UnregisterCB"; } @@ -1680,10 +1681,10 @@ class EpollReader: public EpollCallbackInterface { ~EpollReader() override {} - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { - } + void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, + int /*event_mask*/) override {} - void OnModification(int fd, int event_mask) override {} + void OnModification(int /*fd*/, int /*event_mask*/) override {} void OnEvent(int fd, EpollEvent* event) override { if (event->in_events & EPOLLIN) { @@ -1697,9 +1698,9 @@ class EpollReader: public EpollCallbackInterface { } } - void OnUnregistration(int fd, bool replaced) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} - void OnShutdown(SimpleEpollServer* eps, int fd) override { + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override { // None of the current tests involve having active callbacks when the // server shuts down. EPOLL_LOG(FATAL); @@ -1934,12 +1935,12 @@ class EdgeTriggerCB : public EpollCallbackInterface { } } - void OnUnregistration(int fd, bool replaced) override { + void OnUnregistration(int /*fd*/, bool /*replaced*/) override { EXPECT_TRUE(eps_ != nullptr); eps_ = nullptr; } - void OnShutdown(SimpleEpollServer* eps, int fd) override { + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override { // None of the current tests involve having active callbacks when the // server shuts down. EPOLL_LOG(FATAL); @@ -2068,17 +2069,17 @@ class UnRegisterWhileProcessingCB: public EpollCallbackInterface { ~UnRegisterWhileProcessingCB() override { } - void OnShutdown(SimpleEpollServer* eps, int fd) override {} + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { - } - void OnModification(int fd, int event_mask) override {} - void OnEvent(int fd, EpollEvent* event) override { + void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, + int /*event_mask*/) override {} + void OnModification(int /*fd*/, int /*event_mask*/) override {} + void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { // This should cause no problems. eps_->UnregisterFD(fd_); } - void OnUnregistration(int fd, bool replaced) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} std::string Name() const override { return "UnRegisterWhileProcessingCB"; } protected: @@ -2094,17 +2095,17 @@ class RegisterWhileProcessingCB: public EpollCallbackInterface { ~RegisterWhileProcessingCB() override { } - void OnShutdown(SimpleEpollServer* eps, int fd) override {} + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { - } - void OnModification(int fd, int event_mask) override {} - void OnEvent(int fd, EpollEvent* event) override { + void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, + int /*event_mask*/) override {} + void OnModification(int /*fd*/, int /*event_mask*/) override {} + void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { // This should cause no problems. eps_->RegisterFDForReadWrite(fd_, cb_); } - void OnUnregistration(int fd, bool replaced) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} std::string Name() const override { return "RegisterWhileProcessingCB"; } protected: @@ -2180,21 +2181,21 @@ TEST(SimpleEpollServerTest, class ReRegWhileReadyListOnEvent: public EpollCallbackInterface { public: - explicit ReRegWhileReadyListOnEvent(int fd) : eps_(nullptr) {} + explicit ReRegWhileReadyListOnEvent(int /*fd*/) : eps_(nullptr) {} - void OnShutdown(SimpleEpollServer* eps, int fd) override {} + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { - } - void OnModification(int fd, int event_mask) override {} - void OnEvent(int fd, EpollEvent* event) override { + void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, + int /*event_mask*/) override {} + void OnModification(int /*fd*/, int /*event_mask*/) override {} + void OnEvent(int fd, EpollEvent* /*event_mask*/) override { // This should cause no problems. eps_->UnregisterFD(fd); eps_->RegisterFDForReadWrite(fd, this); eps_->UnregisterFD(fd); } - void OnUnregistration(int fd, bool replaced) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} std::string Name() const override { return "ReRegWhileReadyListOnEvent"; } protected: @@ -2226,14 +2227,15 @@ class UnRegEverythingReadyListOnEvent: public EpollCallbackInterface { void set_fd_range(int fd_range) { fd_range_ = fd_range; } void set_num_called(int* num_called) { num_called_ = num_called; } - void OnShutdown(SimpleEpollServer* eps, int fd) override {} + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { + void OnRegistration(SimpleEpollServer* eps, int fd, + int /*event_mask*/) override { eps->SetFDReady(fd, EPOLLIN); } - void OnModification(int fd, int event_mask) override {} - void OnEvent(int fd, EpollEvent* event) override { + void OnModification(int /*fd*/, int /*event_mask*/) override {} + void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { // This should cause no problems. CHECK(num_called_ != nullptr); ++(*num_called_); @@ -2247,7 +2249,7 @@ class UnRegEverythingReadyListOnEvent: public EpollCallbackInterface { eps_->UnregisterFD(i); } } - void OnUnregistration(int fd, bool replaced) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} std::string Name() const override { return "UnRegEverythingReadyListOnEvent"; } @@ -2306,10 +2308,10 @@ class ApproximateNowInUsecTestCB: public EpollCallbackInterface { public: ApproximateNowInUsecTestCB() : feps_(nullptr), called_(false) {} - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { - } - void OnModification(int fd, int event_mask) override {} - void OnEvent(int fd, EpollEvent* event) override { + void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, + int /*event_mask*/) override {} + void OnModification(int /*fd*/, int /*event_mask*/) override {} + void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { EXPECT_EQ(feps_->ApproximateNowInUsec(), feps_->NowInUsec()); feps_->AdvanceBy(1111); EXPECT_EQ(1 * 1111 + feps_->ApproximateNowInUsec(), feps_->NowInUsec()); @@ -2317,8 +2319,8 @@ class ApproximateNowInUsecTestCB: public EpollCallbackInterface { EXPECT_EQ(2 * 1111 + feps_->ApproximateNowInUsec(), feps_->NowInUsec()); called_ = true; } - void OnUnregistration(int fd, bool replaced) override {} - void OnShutdown(SimpleEpollServer* eps, int fd) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} std::string Name() const override { return "ApproximateNowInUsecTestCB"; } void set_fakeepollserver(FakeSimpleEpollServer* feps) { feps_ = feps; } @@ -2374,18 +2376,18 @@ class RecordDelayOnEvent: public EpollCallbackInterface { ~RecordDelayOnEvent() override { } - void OnShutdown(SimpleEpollServer* eps, int fd) override {} + void OnShutdown(SimpleEpollServer* /*eps*/, int /*fd*/) override {} std::string Name() const override { return "RecordDelayOnEvent"; } void set_epoll_server(SimpleEpollServer* eps) { eps_ = eps; } - void OnRegistration(SimpleEpollServer* eps, int fd, int event_mask) override { - } - void OnModification(int fd, int event_mask) override {} - void OnEvent(int fd, EpollEvent* event) override { + void OnRegistration(SimpleEpollServer* /*eps*/, int /*fd*/, + int /*event_mask*/) override {} + void OnModification(int /*fd*/, int /*event_mask*/) override {} + void OnEvent(int /*fd*/, EpollEvent* /*event*/) override { last_delay = eps_->LastDelayInUsec(); } - void OnUnregistration(int fd, bool replaced) override {} + void OnUnregistration(int /*fd*/, bool /*replaced*/) override {} int64_t last_delay; diff --git a/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_benchmark.cc b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_benchmark.cc new file mode 100644 index 00000000000..1f365c6b0da --- /dev/null +++ b/chromium/net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder_benchmark.cc @@ -0,0 +1,60 @@ +// Copyright 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. + +// +// $ blaze run -c opt --dynamic_mode=off \ +// -- //net/third_party/quiche/src/http2/hpack/huffman:hpack_huffman_encoder_benchmark \ +// --benchmarks=all --benchmark_memory_usage --benchmark_repetitions=1 +// +// Benchmark Time(ns) CPU(ns) Allocs Iterations +// ----------------------------------------------------------------------------- +// BM_EncodeSmallStrings 239 239 0 2456085 0.000B peak-mem +// BM_EncodeLargeString/1k 4560 4561 5 153325 1.125kB peak-mem +// BM_EncodeLargeString/4k 18787 18788 7 38430 4.500kB peak-mem +// BM_EncodeLargeString/32k 147680 147657 10 4664 36.000kB peak-mem +// BM_EncodeLargeString/256k 1161688 1161511 13 601 288.000kB peak-mem +// BM_EncodeLargeString/2M 10042722 10036764 16 75 2.250MB peak-mem +// BM_EncodeLargeString/16M 76127338 76138839 19 9 18.000MB peak-mem +// BM_EncodeLargeString/128M 640008098 640154859 22 1 144.000MB peak-mem +// + +#include <string> + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +// This header has multiple DCHECK_* macros with signed-unsigned comparison. +#include "testing/base/public/benchmark.h" +#pragma clang diagnostic pop + +#include "net/third_party/quiche/src/http2/hpack/huffman/hpack_huffman_encoder.h" + +namespace http2 { +namespace { + +void BM_EncodeSmallStrings(benchmark::State& state) { + const std::vector<const std::string> inputs{ + ":method", ":path", "cookie", "set-cookie", "vary", "accept-encoding"}; + for (auto s : state) { + for (const auto& input : inputs) { + std::string result; + ExactHuffmanSize(input); + HuffmanEncode(input, &result); + } + } +} + +void BM_EncodeLargeString(benchmark::State& state) { + const std::string input(state.range(0), 'a'); + for (auto s : state) { + std::string result; + ExactHuffmanSize(input); + HuffmanEncode(input, &result); + } +} + +BENCHMARK(BM_EncodeSmallStrings); +BENCHMARK(BM_EncodeLargeString)->Range(1024, 128 * 1024 * 1024); + +} // namespace +} // namespace http2 diff --git a/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc b/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc index a8371808773..20dd0ec1cdc 100644 --- a/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc +++ b/chromium/net/third_party/quiche/src/http2/http2_structures_test.cc @@ -47,7 +47,9 @@ E IncrementEnum(E e) { template <class T> AssertionResult VerifyRandomCalls() { T t1; - Http2Random seq1; + // Initialize with a stable key, to avoid test flakiness. + Http2Random seq1( + "6d9a61ddf2bc1fc0b8245505a1f28e324559d8b5c9c3268f38b42b1af3287c47"); Randomize(&t1, &seq1); T t2; diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc index ade94a73feb..29cbccc97e5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_batch_writer_base.cc @@ -8,6 +8,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h" namespace quic { @@ -39,9 +40,23 @@ WriteResult QuicBatchWriterBase::InternalWritePacket( return WriteResult(WRITE_STATUS_MSG_TOO_BIG, EMSGSIZE); } - ReleaseTime release_time = SupportsReleaseTime() - ? GetReleaseTime(options) - : ReleaseTime{0, QuicTime::Delta::Zero()}; + ReleaseTime release_time{0, QuicTime::Delta::Zero()}; + if (SupportsReleaseTime()) { + release_time = GetReleaseTime(options); + if (release_time.release_time_offset >= QuicTime::Delta::Zero()) { + QUIC_SERVER_HISTOGRAM_TIMES( + "batch_writer_positive_release_time_offset", + release_time.release_time_offset.ToMicroseconds(), 1, 100000, 50, + "Duration from ideal release time to actual " + "release time, in microseconds."); + } else { + QUIC_SERVER_HISTOGRAM_TIMES( + "batch_writer_negative_release_time_offset", + -release_time.release_time_offset.ToMicroseconds(), 1, 100000, 50, + "Duration from actual release time to ideal " + "release time, in microseconds."); + } + } const CanBatchResult can_batch_result = CanBatch(buffer, buf_len, self_address, peer_address, options, diff --git a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc index bda5fe26080..d83b83b3389 100644 --- a/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/batch_writer/quic_gso_batch_writer.cc @@ -120,18 +120,6 @@ QuicGsoBatchWriter::ReleaseTime QuicGsoBatchWriter::GetReleaseTime( const uint64_t actual_release_time = buffered_writes().back().release_time; const int64_t offset_ns = actual_release_time - ideal_release_time; - if (offset_ns >= 0) { - QUIC_SERVER_HISTOGRAM_TIMES("gso_writer_positive_release_time_offset", - offset_ns / 1000, 1, 100000, 50, - "Duration from ideal release time to actual " - "release time, in microseconds."); - } else { - QUIC_SERVER_HISTOGRAM_TIMES("gso_writer_negative_release_time_offset", - -offset_ns / 1000, 1, 100000, 50, - "Duration from actual release time to ideal " - "release time, in microseconds."); - } - ReleaseTime result{actual_release_time, QuicTime::Delta::FromMicroseconds(offset_ns / 1000)}; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc index 153f63e1938..605318589e3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.cc @@ -211,13 +211,7 @@ void Bbr2NetworkModel::OnCongestionEventFinish( bandwidth_sampler_.RemoveObsoletePackets(least_unacked_packet); } -void Bbr2NetworkModel::UpdateNetworkParameters(QuicBandwidth bandwidth, - QuicTime::Delta rtt) { - if (!improve_adjust_network_parameters_ && !bandwidth.IsInfinite() && - bandwidth > MaxBandwidth()) { - max_bandwidth_filter_.Update(bandwidth); - } - +void Bbr2NetworkModel::UpdateNetworkParameters(QuicTime::Delta rtt) { if (!rtt.IsZero()) { min_rtt_filter_.Update(rtt, MinRttTimestamp()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h index de30377d45e..8732118049e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h @@ -326,10 +326,8 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { const Bbr2CongestionEvent& congestion_event); // Update the model without a congestion event. - // Max bandwidth is updated if |bandwidth| is larger than existing max - // bandwidth. Min rtt is updated if |rtt| is non-zero and smaller than - // existing min rtt. - void UpdateNetworkParameters(QuicBandwidth bandwidth, QuicTime::Delta rtt); + // Min rtt is updated if |rtt| is non-zero and smaller than existing min rtt. + void UpdateNetworkParameters(QuicTime::Delta rtt); // Update inflight/bandwidth short-term lower bounds. void AdaptLowerBounds(const Bbr2CongestionEvent& congestion_event); @@ -450,10 +448,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { float pacing_gain() const { return pacing_gain_; } void set_pacing_gain(float pacing_gain) { pacing_gain_ = pacing_gain; } - bool improve_adjust_network_parameters() const { - return improve_adjust_network_parameters_; - } - private: const Bbr2Params& Params() const { return *params_; } const Bbr2Params* const params_; @@ -485,9 +479,6 @@ class QUIC_EXPORT_PRIVATE Bbr2NetworkModel { float cwnd_gain_; float pacing_gain_; - - const bool improve_adjust_network_parameters_ = - GetQuicReloadableFlag(quic_bbr2_improve_adjust_network_parameters); }; enum class Bbr2Mode : uint8_t { diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc index 59e63032fcb..172911817aa 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.cc @@ -9,6 +9,7 @@ #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" #include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" @@ -165,18 +166,26 @@ void Bbr2ProbeBwMode::UpdateProbeDown( QUIC_DVLOG(3) << sender_ << " Checking if have enough inflight headroom. prior_in_flight:" - << prior_in_flight + << prior_in_flight << " congestion_event.bytes_in_flight:" + << congestion_event.bytes_in_flight << ", inflight_with_headroom:" << inflight_with_headroom; - if (prior_in_flight > inflight_with_headroom) { + QuicByteCount bytes_in_flight = prior_in_flight; + if (GetQuicReloadableFlag(quic_bbr2_use_post_inflight_to_detect_queuing)) { + // TODO(ianswett): Remove prior_in_flight from UpdateProbeDown. + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_use_post_inflight_to_detect_queuing, + 2, 2); + bytes_in_flight = congestion_event.bytes_in_flight; + } + if (bytes_in_flight > inflight_with_headroom) { // Stay in PROBE_DOWN. return; } // Transition to PROBE_CRUISE iff we've drained to target. QuicByteCount bdp = model_->BDP(model_->MaxBandwidth()); - QUIC_DVLOG(3) << sender_ << " Checking if drained to target. prior_in_flight:" - << prior_in_flight << ", bdp:" << bdp; - if (prior_in_flight < bdp) { + QUIC_DVLOG(3) << sender_ << " Checking if drained to target. bytes_in_flight:" + << bytes_in_flight << ", bdp:" << bdp; + if (bytes_in_flight < bdp) { EnterProbeCruise(congestion_event.event_time); } } @@ -436,10 +445,18 @@ void Bbr2ProbeBwMode::UpdateProbeUp( QuicByteCount queuing_threshold = (Params().probe_bw_probe_inflight_gain * bdp) + queuing_threshold_extra_bytes; - is_queuing = prior_in_flight >= queuing_threshold; + if (GetQuicReloadableFlag(quic_bbr2_use_post_inflight_to_detect_queuing)) { + QUIC_RELOADABLE_FLAG_COUNT_N( + quic_bbr2_use_post_inflight_to_detect_queuing, 1, 2); + is_queuing = congestion_event.bytes_in_flight >= queuing_threshold; + } else { + is_queuing = prior_in_flight >= queuing_threshold; + } QUIC_DVLOG(3) << sender_ << " Checking if building up a queue. prior_in_flight:" - << prior_in_flight << ", threshold:" << queuing_threshold + << prior_in_flight + << ", post_in_flight:" << congestion_event.bytes_in_flight + << ", threshold:" << queuing_threshold << ", is_queuing:" << is_queuing << ", max_bw:" << model_->MaxBandwidth() << ", min_rtt:" << model_->MinRtt(); diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc index 3c7ba2fc8ad..fe32835fb8f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.cc @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { @@ -73,8 +74,10 @@ Bbr2Sender::Bbr2Sender(QuicTime now, /*cwnd_gain=*/1.0, /*pacing_gain=*/kInitialPacingGain, old_sender ? &old_sender->sampler_ : nullptr), - initial_cwnd_( - cwnd_limits().ApplyLimits(initial_cwnd_in_packets * kDefaultTCPMSS)), + initial_cwnd_(cwnd_limits().ApplyLimits( + (GetQuicReloadableFlag(quic_copy_bbr_cwnd_to_bbr2) && old_sender) + ? old_sender->GetCongestionWindow() + : (initial_cwnd_in_packets * kDefaultTCPMSS))), cwnd_(initial_cwnd_), pacing_rate_(kInitialPacingGain * QuicBandwidth::FromBytesAndTimeDelta( cwnd_, @@ -84,6 +87,10 @@ Bbr2Sender::Bbr2Sender(QuicTime now, probe_bw_(this, &model_), probe_rtt_(this, &model_), last_sample_is_app_limited_(false) { + if (GetQuicReloadableFlag(quic_copy_bbr_cwnd_to_bbr2) && old_sender) { + QUIC_RELOADABLE_FLAG_COUNT(quic_copy_bbr_cwnd_to_bbr2); + } + QUIC_DVLOG(2) << this << " Initializing Bbr2Sender. mode:" << mode_ << ", PacingRate:" << pacing_rate_ << ", Cwnd:" << cwnd_ << ", CwndLimits:" << cwnd_limits() << " @ " << now; @@ -115,9 +122,7 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config, QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_fewer_startup_round_trips, 2, 2); params_.startup_full_bw_rounds = 2; } - if (GetQuicReloadableFlag(quic_bbr2_ignore_inflight_lo) && - config.HasClientRequestedIndependentOption(kB2LO, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_lo); + if (config.HasClientRequestedIndependentOption(kB2LO, perspective)) { params_.ignore_inflight_lo = true; } if (GetQuicReloadableFlag(quic_bbr2_limit_inflight_hi) && @@ -125,6 +130,11 @@ void Bbr2Sender::SetFromConfig(const QuicConfig& config, QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_limit_inflight_hi); params_.limit_inflight_hi_by_cwnd = true; } + if (GetQuicReloadableFlag(quic_bbr2_use_tcp_inflight_hi_headroom) && + config.HasClientRequestedIndependentOption(kB2HR, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_use_tcp_inflight_hi_headroom); + params_.inflight_hi_headroom = 0.15; + } ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective)); } @@ -162,33 +172,21 @@ const Limits<QuicByteCount>& Bbr2Sender::cwnd_limits() const { } void Bbr2Sender::AdjustNetworkParameters(const NetworkParams& params) { - model_.UpdateNetworkParameters(params.bandwidth, params.rtt); + model_.UpdateNetworkParameters(params.rtt); if (mode_ == Bbr2Mode::STARTUP) { const QuicByteCount prior_cwnd = cwnd_; - if (model_.improve_adjust_network_parameters()) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_improve_adjust_network_parameters); - QuicBandwidth effective_bandwidth = - std::max(params.bandwidth, model_.BandwidthEstimate()); - cwnd_ = cwnd_limits().ApplyLimits(model_.BDP(effective_bandwidth)); - } else { - // Normally UpdateCongestionWindow updates |cwnd_| towards the target by a - // small step per congestion event, by changing |cwnd_| to the bdp at here - // we are reducing the number of updates needed to arrive at the target. - cwnd_ = model_.BDP(model_.BandwidthEstimate()); - UpdateCongestionWindow(0); - } + QuicBandwidth effective_bandwidth = + std::max(params.bandwidth, model_.BandwidthEstimate()); + cwnd_ = cwnd_limits().ApplyLimits(model_.BDP(effective_bandwidth)); if (!params.allow_cwnd_to_decrease) { cwnd_ = std::max(cwnd_, prior_cwnd); } - if (model_.improve_adjust_network_parameters()) { - pacing_rate_ = std::max( - pacing_rate_, - QuicBandwidth::FromBytesAndTimeDelta(cwnd_, model_.MinRtt())); - } + pacing_rate_ = std::max(pacing_rate_, QuicBandwidth::FromBytesAndTimeDelta( + cwnd_, model_.MinRtt())); } } diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc index 1ff703d0953..1f5db20c892 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_simulator_test.cc @@ -449,9 +449,6 @@ TEST_F(Bbr2DefaultTopologyTest, SimpleTransfer2RTTAggregationBytes) { TEST_F(Bbr2DefaultTopologyTest, SimpleTransferAckDecimation) { SetConnectionOption(kBSAO); - // Enable Ack Decimation on the receiver. - QuicConnectionPeer::SetAckMode(receiver_endpoint_.connection(), - AckMode::ACK_DECIMATION); DefaultTopologyParams params; CreateNetwork(params); @@ -664,10 +661,10 @@ TEST_F(Bbr2DefaultTopologyTest, InFlightAwareGainCycling) { } // Now that in-flight is almost zero and the pacing gain is still above 1, - // send approximately 1.25 BDPs worth of data. This should cause the - // PROBE_BW mode to enter low gain cycle(PROBE_DOWN), and exit it earlier than - // one min_rtt due to running out of data to send. - sender_endpoint_.AddBytesToTransfer(1.3 * params.BDP()); + // send approximately 1.4 BDPs worth of data. This should cause the PROBE_BW + // mode to enter low gain cycle(PROBE_DOWN), and exit it earlier than one + // min_rtt due to running out of data to send. + sender_endpoint_.AddBytesToTransfer(1.4 * params.BDP()); simulator_result = simulator_.RunUntilOrTimeout( [this]() { return sender_->ExportDebugState().probe_bw.phase == @@ -915,7 +912,7 @@ TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) { BbrSender old_sender(sender_connection()->clock()->Now(), sender_connection()->sent_packet_manager().GetRttStats(), GetUnackedMap(sender_connection()), - kDefaultInitialCwndPackets, + kDefaultInitialCwndPackets + 1, GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, QuicConnectionPeer::GetStats(sender_connection())); @@ -930,7 +927,11 @@ TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) { } // Switch from |old_sender| to |sender_|. + const QuicByteCount old_sender_cwnd = old_sender.GetCongestionWindow(); sender_ = SetupBbr2Sender(&sender_endpoint_, &old_sender); + if (GetQuicReloadableFlag(quic_copy_bbr_cwnd_to_bbr2)) { + EXPECT_EQ(old_sender_cwnd, sender_->GetCongestionWindow()); + } // Send packets 5-7. now = now + QuicTime::Delta::FromMilliseconds(10); @@ -1007,13 +1008,9 @@ TEST_F(Bbr2DefaultTopologyTest, AdjustNetworkParameters) { EXPECT_EQ(params.BDP(), sender_->ExportDebugState().congestion_window); - if (GetQuicReloadableFlag(quic_bbr2_improve_adjust_network_parameters)) { - EXPECT_EQ(params.BottleneckBandwidth(), - sender_->PacingRate(/*bytes_in_flight=*/0)); - EXPECT_NE(params.BottleneckBandwidth(), sender_->BandwidthEstimate()); - } else { - EXPECT_EQ(params.BottleneckBandwidth(), sender_->BandwidthEstimate()); - } + EXPECT_EQ(params.BottleneckBandwidth(), + sender_->PacingRate(/*bytes_in_flight=*/0)); + EXPECT_NE(params.BottleneckBandwidth(), sender_->BandwidthEstimate()); EXPECT_APPROX_EQ(params.RTT(), sender_->ExportDebugState().min_rtt, 0.01f); diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc index 7389067fed7..2948272d737 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.cc @@ -112,7 +112,6 @@ BbrSender::BbrSender(QuicTime now, probe_rtt_round_passed_(false), last_sample_is_app_limited_(false), has_non_app_limited_sample_(false), - flexible_app_limited_(false), recovery_state_(NOT_IN_RECOVERY), recovery_window_(max_congestion_window_), slower_startup_(false), @@ -219,12 +218,7 @@ bool BbrSender::ShouldSendProbingPacket() const { // TODO(b/77975811): If the pipe is highly under-utilized, consider not // sending a probing transmission, because the extra bandwidth is not needed. - // If flexible_app_limited is enabled, check if the pipe is sufficiently full. - if (flexible_app_limited_) { - return !IsPipeSufficientlyFull(); - } else { - return true; - } + return true; } bool BbrSender::IsPipeSufficientlyFull() const { @@ -268,11 +262,6 @@ void BbrSender::SetFromConfig(const QuicConfig& config, if (config.HasClientRequestedIndependentOption(kBBR5, perspective)) { sampler_.SetMaxAckHeightTrackerWindowLength(4 * kBandwidthWindowSize); } - if (GetQuicReloadableFlag(quic_bbr_flexible_app_limited) && - config.HasClientRequestedIndependentOption(kBBR9, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_flexible_app_limited); - flexible_app_limited_ = true; - } if (config.HasClientRequestedIndependentOption(kBBQ1, perspective)) { set_high_gain(kDerivedHighGain); set_high_cwnd_gain(kDerivedHighGain); @@ -291,9 +280,7 @@ void BbrSender::SetFromConfig(const QuicConfig& config, max_congestion_window_with_network_parameters_adjusted_ = 100 * kDefaultTCPMSS; } - if (GetQuicReloadableFlag(quic_enable_overshooting_detection) && - config.HasClientRequestedIndependentOption(kDTOS, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_enable_overshooting_detection); + if (config.HasClientRequestedIndependentOption(kDTOS, perspective)) { detect_overshooting_ = true; // DTOS would allow pacing rate drop to IW 10 / min_rtt if overshooting is // detected. @@ -887,9 +874,6 @@ void BbrSender::OnApplicationLimited(QuicByteCount bytes_in_flight) { if (bytes_in_flight >= GetCongestionWindow()) { return; } - if (flexible_app_limited_ && IsPipeSufficientlyFull()) { - return; - } sampler_.OnAppLimited(); QUIC_DVLOG(2) << "Becoming application limited. Last sent packet: " diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h index d89e3fecdfd..ae6cce9a393 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h @@ -354,9 +354,6 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface { bool last_sample_is_app_limited_; // Indicates whether any non app-limited samples have been recorded. bool has_non_app_limited_sample_; - // Indicates app-limited calls should be ignored as long as there's - // enough data inflight to see more bandwidth when necessary. - bool flexible_app_limited_; // Current state of recovery. RecoveryState recovery_state_; diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc index 0e94b6b73da..b476b557a47 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr_sender_test.cc @@ -292,8 +292,6 @@ TEST_F(BbrSenderTest, SetInitialCongestionWindow) { // Test a simple long data transfer in the default setup. TEST_F(BbrSenderTest, SimpleTransfer) { - // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); // At startup make sure we are at the default. @@ -341,8 +339,6 @@ TEST_F(BbrSenderTest, SimpleTransferSmallBuffer) { } TEST_F(BbrSenderTest, RemoveBytesLostInRecovery) { - // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); DriveOutOfStartup(); @@ -421,9 +417,6 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, QuicConnectionPeer::GetStats(bbr_sender_.connection())); QuicConnectionPeer::SetSendAlgorithm(bbr_sender_.connection(), sender_); - // Enable Ack Decimation on the receiver. - QuicConnectionPeer::SetAckMode(receiver_.connection(), - AckMode::ACK_DECIMATION); CreateDefaultSetup(); // Transfer 12MB. @@ -445,8 +438,6 @@ TEST_F(BbrSenderTest, SimpleTransferAckDecimation) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { SetConnectionOption(kBSAO); - // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); SetConnectionOption(kBBR4); // 2 RTTs of aggregation, with a max of 10kb. @@ -471,8 +462,6 @@ TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes20RTTWindow) { // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes40RTTWindow) { SetConnectionOption(kBSAO); - // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); SetConnectionOption(kBBR5); // 2 RTTs of aggregation, with a max of 10kb. @@ -590,8 +579,6 @@ TEST_F(BbrSenderTest, ApplicationLimitedBurstsWithoutPrior) { // Verify that the DRAIN phase works correctly. TEST_F(BbrSenderTest, Drain) { - // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); // Get the queue at the bottleneck, which is the outgoing queue at the port to @@ -654,10 +641,6 @@ TEST_F(BbrSenderTest, Drain) { // TODO(wub): Re-enable this test once default drain_gain changed to 0.75. // Verify that the DRAIN phase works correctly. TEST_F(BbrSenderTest, DISABLED_ShallowDrain) { - // TODO(haoyuewang) Remove this when TCP_ACKING is deprecated. - // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); - CreateDefaultSetup(); const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(10); // Get the queue at the bottleneck, which is the outgoing queue at the port to @@ -746,8 +729,6 @@ TEST_F(BbrSenderTest, ProbeRtt) { // bandwidth will not exit high gain phase, and similarly ensure that the // connection will exit low gain early if the number of bytes in flight is low. TEST_F(BbrSenderTest, InFlightAwareGainCycling) { - // Disable Ack Decimation on the receiver, because it can increase srtt. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); DriveOutOfStartup(); @@ -987,9 +968,6 @@ TEST_F(BbrSenderTest, DerivedCWNDGainStartup) { } TEST_F(BbrSenderTest, AckAggregationInStartup) { - // Disable Ack Decimation on the receiver to avoid loss and make results - // consistent. - QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); CreateDefaultSetup(); SetConnectionOption(kBBQ3); @@ -1299,9 +1277,6 @@ TEST_F(BbrSenderTest, LossOnlyCongestionEvent) { } TEST_F(BbrSenderTest, EnableOvershootingDetection) { - if (!GetQuicReloadableFlag(quic_enable_overshooting_detection)) { - return; - } SetConnectionOption(kDTOS); CreateSmallBufferSetup(); // Set a overly large initial cwnd. diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc index 9124e49d2ae..42b97bf89f8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm_test.cc @@ -43,7 +43,7 @@ class GeneralLossAlgorithmTest : public QuicTest { encrypted_length, false, false); packet.retransmittable_frames.push_back(QuicFrame(frame)); unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(), - true); + true, true); } void SendDataPacket(uint64_t packet_number) { @@ -55,7 +55,7 @@ class GeneralLossAlgorithmTest : public QuicTest { PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, true, false); unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(), - false); + false, true); } void VerifyLosses(uint64_t largest_newly_acked, diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc index 458152f024a..7a9d37ee107 100644 --- a/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm_test.cc @@ -53,7 +53,7 @@ class UberLossAlgorithmTest : public QuicTest { packet.encryption_level = encryption_level; packet.retransmittable_frames.push_back(QuicFrame(frame)); unacked_packets_->AddSentPacket(&packet, NOT_RETRANSMISSION, clock_.Now(), - true); + true, true); } void AckPackets(const std::vector<uint64_t>& packets_acked) { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h index 4ebdd2e05ef..bf3a97ca891 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h @@ -96,8 +96,7 @@ const QuicTag kBBR3 = TAG('B', 'B', 'R', '3'); // Fully drain the queue once // per cycle const QuicTag kBBR4 = TAG('B', 'B', 'R', '4'); // 20 RTT ack aggregation const QuicTag kBBR5 = TAG('B', 'B', 'R', '5'); // 40 RTT ack aggregation -const QuicTag kBBR9 = TAG('B', 'B', 'R', '9'); // Ignore app-limited calls in - // BBR if enough inflight. +const QuicTag kBBR9 = TAG('B', 'B', 'R', '9'); // DEPRECATED const QuicTag kBBRS = TAG('B', 'B', 'R', 'S'); // DEPRECATED const QuicTag kBBQ1 = TAG('B', 'B', 'Q', '1'); // BBR with lower 2.77 STARTUP // pacing and CWND gain. @@ -127,6 +126,7 @@ const QuicTag kB2CL = TAG('B', '2', 'C', 'L'); // For BBRv2, allow PROBE_BW const QuicTag kB2LO = TAG('B', '2', 'L', 'O'); // Ignore inflight_lo in BBR2 const QuicTag kB2HI = TAG('B', '2', 'H', 'I'); // Limit inflight_hi reduction // based on CWND. +const QuicTag kB2HR = TAG('B', '2', 'H', 'R'); // 15% inflight_hi headroom. const QuicTag kBSAO = TAG('B', 'S', 'A', 'O'); // Avoid Overestimation in // Bandwidth Sampler with ack // aggregation @@ -160,6 +160,7 @@ const QuicTag kAKDU = TAG('A', 'K', 'D', 'U'); // Unlimited number of packets // received before acking const QuicTag kACKQ = TAG('A', 'C', 'K', 'Q'); // Send an immediate ack after // 1 RTT of not receiving. +const QuicTag kAFFE = TAG('A', 'F', 'F', 'E'); // AckFrequencyFrame Enabled. const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction. const QuicTag kNPRR = TAG('N', 'P', 'R', 'R'); // Pace at unity instead of PRR const QuicTag k2RTO = TAG('2', 'R', 'T', 'O'); // Close connection on 2 RTOs @@ -299,6 +300,9 @@ const QuicTag kFIDT = TAG('F', 'I', 'D', 'T'); // Extend idle timer by PTO // instead of the whole idle // timeout. +const QuicTag k3AFF = TAG('3', 'A', 'F', 'F'); // 3 anti amplification factor. +const QuicTag k10AF = TAG('1', '0', 'A', 'F'); // 10 anti amplification factor. + // Enable path MTU discovery experiment. const QuicTag kMTUH = TAG('M', 'T', 'U', 'H'); // High-target MTU discovery. const QuicTag kMTUL = TAG('M', 'T', 'U', 'L'); // Low-target MTU discovery. diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc index fe1a5ee86b8..365fb120d19 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.cc @@ -691,6 +691,30 @@ const char* CryptoUtils::HandshakeFailureReasonToString( } // static +const char* CryptoUtils::EarlyDataReasonToString( + ssl_early_data_reason_t reason) { + switch (reason) { + RETURN_STRING_LITERAL(ssl_early_data_unknown); + RETURN_STRING_LITERAL(ssl_early_data_disabled); + RETURN_STRING_LITERAL(ssl_early_data_accepted); + RETURN_STRING_LITERAL(ssl_early_data_protocol_version); + RETURN_STRING_LITERAL(ssl_early_data_peer_declined); + RETURN_STRING_LITERAL(ssl_early_data_no_session_offered); + RETURN_STRING_LITERAL(ssl_early_data_session_not_resumed); + RETURN_STRING_LITERAL(ssl_early_data_unsupported_for_session); + RETURN_STRING_LITERAL(ssl_early_data_hello_retry_request); + RETURN_STRING_LITERAL(ssl_early_data_alpn_mismatch); + RETURN_STRING_LITERAL(ssl_early_data_channel_id); + RETURN_STRING_LITERAL(ssl_early_data_token_binding); + RETURN_STRING_LITERAL(ssl_early_data_ticket_age_skew); + RETURN_STRING_LITERAL(ssl_early_data_quic_parameter_mismatch); + } + QUIC_BUG_IF(reason < 0 || reason > ssl_early_data_reason_max_value) + << "Unknown ssl_early_data_reason_t " << reason; + return "unknown ssl_early_data_reason_t"; +} + +// static std::string CryptoUtils::HashHandshakeMessage( const CryptoHandshakeMessage& message, Perspective /*perspective*/) { diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h index 6c167f8f694..964f81fdf69 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/crypto_utils.h @@ -12,6 +12,7 @@ #include <string> #include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" @@ -211,6 +212,9 @@ class QUIC_EXPORT_PRIVATE CryptoUtils { static const char* HandshakeFailureReasonToString( HandshakeFailureReason reason); + // Returns the name of an ssl_early_data_reason_t as a char* + static const char* EarlyDataReasonToString(ssl_early_data_reason_t reason); + // Returns a hash of the serialized |message|. static std::string HashHandshakeMessage(const CryptoHandshakeMessage& message, Perspective perspective); diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc index 73f16721821..3a980296a96 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.cc @@ -8,9 +8,26 @@ namespace quic { +CryptoBuffers::~CryptoBuffers() { + for (size_t i = 0; i < value.size(); i++) { + CRYPTO_BUFFER_free(value[i]); + } +} + ProofSource::Chain::Chain(const std::vector<std::string>& certs) : certs(certs) {} ProofSource::Chain::~Chain() {} +CryptoBuffers ProofSource::Chain::ToCryptoBuffers() const { + CryptoBuffers crypto_buffers; + crypto_buffers.value.reserve(certs.size()); + for (size_t i = 0; i < certs.size(); i++) { + crypto_buffers.value.push_back( + CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(certs[i].data()), + certs[i].length(), nullptr)); + } + return crypto_buffers; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h index c4224f46607..637dd0c33c5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/proof_source.h @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_proof.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" @@ -18,6 +19,17 @@ namespace quic { +// CryptoBuffers is a RAII class to own a std::vector<CRYPTO_BUFFER*> and the +// buffers the elements point to. +struct QUIC_EXPORT_PRIVATE CryptoBuffers { + CryptoBuffers() = default; + CryptoBuffers(const CryptoBuffers&) = delete; + CryptoBuffers(CryptoBuffers&&) = default; + ~CryptoBuffers(); + + std::vector<CRYPTO_BUFFER*> value; +}; + // ProofSource is an interface by which a QUIC server can obtain certificate // chains and signatures that prove its identity. class QUIC_EXPORT_PRIVATE ProofSource { @@ -29,6 +41,8 @@ class QUIC_EXPORT_PRIVATE ProofSource { Chain(const Chain&) = delete; Chain& operator=(const Chain&) = delete; + CryptoBuffers ToCryptoBuffers() const; + const std::vector<std::string> certs; protected: diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc index 5835e944dca..ec535cfa7c6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.cc @@ -47,6 +47,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_reference_counted.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_testvalue.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" #include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h" @@ -797,6 +798,11 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterGetProof( return; } + // Allow testing a specific adversarial case in which a client sends a public + // value of incorrect size. + AdjustTestValue("quic::QuicCryptoServerConfig::public_value_adjust", + &public_value); + const AsynchronousKeyExchange* key_exchange = configs.requested->key_exchanges[key_exchange_index].get(); std::string* initial_premaster_secret = @@ -824,9 +830,11 @@ void QuicCryptoServerConfig::ProcessClientHelloAfterCalculateSharedKeys( << QuicVersionToString(context->transport_version()); if (found_error) { - // If we are already using the fallback config, just bail out of the - // handshake. - if (context->signed_config()->config == configs.fallback || + // If we are already using the fallback config, or there is no fallback + // config to use, just bail out of the handshake. + if ((GetQuicReloadableFlag(quic_check_fallback_null) && + configs.fallback == nullptr) || + context->signed_config()->config == configs.fallback || !GetQuicReloadableFlag( send_quic_fallback_server_config_on_leto_error)) { context->Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, diff --git a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc index 0e59997d438..c821a388748 100644 --- a/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/crypto/tls_server_connection.cc @@ -24,16 +24,13 @@ bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx( SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr); // We don't actually need the TicketCrypter here, but we need to know // whether it's set. - if (GetQuicRestartFlag(quic_enable_tls_resumption_v4) && - proof_source->GetTicketCrypter()) { + if (proof_source->GetTicketCrypter()) { SSL_CTX_set_ticket_aead_method(ssl_ctx.get(), &TlsServerConnection::kSessionTicketMethod); - QUIC_CODE_COUNT_N(quic_tls_resumption_ticket_method, 1, 2); if (GetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2)) { SSL_CTX_set_early_data_enabled(ssl_ctx.get(), 1); } } else { - QUIC_CODE_COUNT_N(quic_tls_resumption_ticket_method, 2, 2); SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET); } return ssl_ctx; diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc index b8c7efafa98..1486327cb18 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.cc @@ -8,6 +8,16 @@ namespace quic { +QuicAckFrequencyFrame::QuicAckFrequencyFrame( + QuicControlFrameId control_frame_id, + uint64_t sequence_number, + uint64_t packet_tolerance, + QuicTime::Delta max_ack_delay) + : control_frame_id(control_frame_id), + sequence_number(sequence_number), + packet_tolerance(packet_tolerance), + max_ack_delay(max_ack_delay) {} + std::ostream& operator<<(std::ostream& os, const QuicAckFrequencyFrame& frame) { os << "{ control_frame_id: " << frame.control_frame_id << ", sequence_number: " << frame.sequence_number diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h index 52b70daff2e..3f9397c2f8c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h @@ -21,8 +21,14 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrequencyFrame { std::ostream& os, const QuicAckFrequencyFrame& ack_frequency_frame); - // A unique identifier of this control frame. 0 when this frame is received, - // and non-zero when sent. + QuicAckFrequencyFrame() = default; + QuicAckFrequencyFrame(QuicControlFrameId control_frame_id, + uint64_t sequence_number, + uint64_t packet_tolerance, + QuicTime::Delta max_ack_delay); + + // A unique identifier of this control frame. 0 when this frame is + // received, and non-zero when sent. QuicControlFrameId control_frame_id = kInvalidControlFrameId; // If true, do not ack immediately upon observeation of packet reordering. @@ -34,10 +40,11 @@ struct QUIC_EXPORT_PRIVATE QuicAckFrequencyFrame { // The maximum number of ack-eliciting packets after which the receiver sends // an acknowledgement. Invald if == 0. - uint64_t packet_tolerance = 0; + uint64_t packet_tolerance = 2; // The maximum time that ack packets can be delayed. - QuicTime::Delta max_ack_delay = QuicTime::Delta::Zero(); + QuicTime::Delta max_ack_delay = + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc index 99b0963a2dc..7fe322dffaf 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.cc @@ -87,6 +87,16 @@ void DeleteFrames(QuicFrames* frames) { } void DeleteFrame(QuicFrame* frame) { +#if QUIC_FRAME_DEBUG + // If the frame is not inlined, check that it can be safely deleted. + if (frame->type != PADDING_FRAME && frame->type != MTU_DISCOVERY_FRAME && + frame->type != PING_FRAME && frame->type != MAX_STREAMS_FRAME && + frame->type != STOP_WAITING_FRAME && + frame->type != STREAMS_BLOCKED_FRAME && frame->type != STREAM_FRAME && + frame->type != HANDSHAKE_DONE_FRAME) { + CHECK(!frame->delete_forbidden) << *frame; + } +#endif // QUIC_FRAME_DEBUG switch (frame->type) { // Frames smaller than a pointer are inlined, so don't need to be deleted. case PADDING_FRAME: diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h index b5785b8bc7f..6e096e3d91c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frame.h @@ -36,6 +36,14 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#ifndef QUIC_FRAME_DEBUG +#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER) +#define QUIC_FRAME_DEBUG 1 +#else // !defined(NDEBUG) || defined(ADDRESS_SANITIZER) +#define QUIC_FRAME_DEBUG 0 +#endif // !defined(NDEBUG) || defined(ADDRESS_SANITIZER) +#endif // QUIC_FRAME_DEBUG + namespace quic { struct QUIC_EXPORT_PRIVATE QuicFrame { @@ -87,6 +95,10 @@ struct QUIC_EXPORT_PRIVATE QuicFrame { struct { QuicFrameType type; +#if QUIC_FRAME_DEBUG + bool delete_forbidden = false; +#endif // QUIC_FRAME_DEBUG + // TODO(wub): These frames can also be inlined without increasing the size // of QuicFrame: QuicRstStreamFrame, QuicWindowUpdateFrame, // QuicBlockedFrame, QuicPathResponseFrame, QuicPathChallengeFrame and diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc index 3f04c8c0704..3177b0cc191 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_frames_test.cc @@ -95,11 +95,14 @@ TEST_F(QuicFramesTest, StopSendingFrameToString) { SetControlFrameId(1, &frame); EXPECT_EQ(1u, GetControlFrameId(frame)); stop_sending.stream_id = 321; - stop_sending.application_error_code = QUIC_STREAM_CANCELLED; + stop_sending.error_code = QUIC_STREAM_CANCELLED; + stop_sending.ietf_error_code = + static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED); std::ostringstream stream; stream << stop_sending; EXPECT_EQ( - "{ control_frame_id: 1, stream_id: 321, application_error_code: 6 }\n", + "{ control_frame_id: 1, stream_id: 321, error_code: 6, ietf_error_code: " + "268 }\n", stream.str()); EXPECT_TRUE(IsControlFrame(frame.type)); } diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc index c4d732ed44d..20281e522b1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.cc @@ -6,18 +6,26 @@ namespace quic { -QuicStopSendingFrame::QuicStopSendingFrame( - QuicControlFrameId control_frame_id, - QuicStreamId stream_id, - QuicApplicationErrorCode application_error_code) +QuicStopSendingFrame::QuicStopSendingFrame(QuicControlFrameId control_frame_id, + QuicStreamId stream_id, + QuicRstStreamErrorCode error_code) : control_frame_id(control_frame_id), stream_id(stream_id), - application_error_code(application_error_code) {} + error_code(error_code), + ietf_error_code( + GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code) + ? RstStreamErrorCodeToIetfResetStreamErrorCode(error_code) + : static_cast<uint64_t>(error_code)) { + if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_stop_sending_uses_ietf_error_code, 1, 2); + } +} std::ostream& operator<<(std::ostream& os, const QuicStopSendingFrame& frame) { os << "{ control_frame_id: " << frame.control_frame_id << ", stream_id: " << frame.stream_id - << ", application_error_code: " << frame.application_error_code << " }\n"; + << ", error_code: " << frame.error_code + << ", ietf_error_code: " << frame.ietf_error_code << " }\n"; return os; } diff --git a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h index 8222067d276..57114d77c56 100644 --- a/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h +++ b/chromium/net/third_party/quiche/src/quic/core/frames/quic_stop_sending_frame.h @@ -17,7 +17,7 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame { QuicStopSendingFrame() = default; QuicStopSendingFrame(QuicControlFrameId control_frame_id, QuicStreamId stream_id, - QuicApplicationErrorCode application_error_code); + QuicRstStreamErrorCode error_code); friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( std::ostream& os, @@ -27,7 +27,14 @@ struct QUIC_EXPORT_PRIVATE QuicStopSendingFrame { // and non-zero when sent. QuicControlFrameId control_frame_id = kInvalidControlFrameId; QuicStreamId stream_id = 0; - QuicApplicationErrorCode application_error_code = 0; + + // For an outgoing frame, the error code generated by the application that + // determines |ietf_error_code| to be sent on the wire; for an incoming frame, + // the error code inferred from |ietf_error_code| received on the wire. + QuicRstStreamErrorCode error_code = QUIC_STREAM_NO_ERROR; + + // On-the-wire application error code of the frame. + uint64_t ietf_error_code = 0; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h index d72471fb687..5103509d06e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h +++ b/chromium/net/third_party/quiche/src/quic/core/handshaker_delegate_interface.h @@ -58,7 +58,7 @@ class QUIC_EXPORT_PRIVATE HandshakerDelegateInterface { // Called when 0-RTT data is rejected by the server. This is only called in // TLS handshakes and only called on clients. - virtual void OnZeroRttRejected() = 0; + virtual void OnZeroRttRejected(int reason) = 0; // Fills in |params| with values from the delegate's QuicConfig. // Returns whether the operation succeeded. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc index cfb76718004..7a0bd9a7823 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/end_to_end_test.cc @@ -199,9 +199,8 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { AddToCache("/foo", 200, kFooResponseBody); AddToCache("/bar", 200, kBarResponseBody); // Enable fixes for bugs found in tests and prod. - SetQuicReloadableFlag(quic_fix_packet_number_length, true); - SetQuicRestartFlag(quic_enable_tls_resumption_v4, true); SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true); + SetQuicReloadableFlag(quic_fix_out_of_order_sending2, true); } ~EndToEndTest() override { QuicRecyclePort(server_address_.port()); } @@ -531,8 +530,7 @@ class EndToEndTest : public QuicTestWithParam<TestParams> { if (server_connection != nullptr) { QuicConnectionStats server_stats = server_connection->GetStats(); if (!had_packet_loss) { - EXPECT_EQ(0u, server_stats.packets_lost - - server_stats.packet_spuriously_detected_lost); + EXPECT_EQ(0u, server_stats.packets_lost); } EXPECT_EQ(0u, server_stats.packets_discarded); EXPECT_EQ(server_session->user_agent_id().value_or("MissingUserAgent"), @@ -1497,7 +1495,6 @@ TEST_P(EndToEndTest, LargePostZeroRTTFailure) { EXPECT_FALSE(client_session->ReceivedInchoateReject()); EXPECT_FALSE(client_->client()->EarlyDataAccepted()); EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); - VerifyCleanConnection(false); } @@ -1608,7 +1605,7 @@ TEST_P(EndToEndTest, LargePostSynchronousRequest) { } // This is a regression test for b/162595387 -TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) { +TEST_P(EndToEndTest, PostZeroRTTRequestDuringHandshake) { if (!version_.UsesTls()) { // This test is TLS specific. ASSERT_TRUE(Initialize()); @@ -1620,15 +1617,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) { connection_debug_visitor_ = &visitor; ASSERT_TRUE(Initialize()); - std::string body(20480, 'a'); - SpdyHeaderBlock headers; - headers[":method"] = "POST"; - headers[":path"] = "/foo"; - headers[":scheme"] = "https"; - headers[":authority"] = server_hostname_; - - EXPECT_EQ(kFooResponseBody, - client_->SendCustomSynchronousRequest(headers, body)); + SendSynchronousFooRequestAndCheckResponse(); QuicSpdyClientSession* client_session = GetClientSession(); ASSERT_TRUE(client_session); EXPECT_FALSE(client_session->EarlyDataAccepted()); @@ -1640,8 +1629,7 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) { // The 0-RTT handshake should succeed. ON_CALL(visitor, OnCryptoFrame(_)) - .WillByDefault(Invoke([this, &headers, - &body](const QuicCryptoFrame& frame) { + .WillByDefault(Invoke([this](const QuicCryptoFrame& frame) { if (frame.level != ENCRYPTION_HANDSHAKE) { return; } @@ -1654,9 +1642,14 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) { EXPECT_TRUE( GetClientConnection()->framer().HasEncrypterOfEncryptionLevel( ENCRYPTION_HANDSHAKE)); - EXPECT_GT(client_->SendMessage(headers, body, /*fin*/ true, - /*flush*/ false), - 0); + SpdyHeaderBlock headers; + headers[":method"] = "POST"; + headers[":path"] = "/foo"; + headers[":scheme"] = "https"; + headers[":authority"] = server_hostname_; + EXPECT_GT( + client_->SendMessage(headers, "", /*fin*/ true, /*flush*/ false), + 0); })); client_->Connect(); ASSERT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); @@ -1671,6 +1664,65 @@ TEST_P(EndToEndTest, LargePostZeroRTTRequestDuringHandshake) { EXPECT_TRUE(client_->client()->EarlyDataAccepted()); } +// Regression test for b/166836136. +TEST_P(EndToEndTest, RetransmissionAfterZeroRTTRejectBeforeOneRtt) { + if (!version_.UsesTls()) { + // This test is TLS specific. + ASSERT_TRUE(Initialize()); + return; + } + // Send a request and then disconnect. This prepares the client to attempt + // a 0-RTT handshake for the next request. + NiceMock<MockQuicConnectionDebugVisitor> visitor; + connection_debug_visitor_ = &visitor; + ASSERT_TRUE(Initialize()); + + SendSynchronousFooRequestAndCheckResponse(); + QuicSpdyClientSession* client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + EXPECT_FALSE(client_session->ReceivedInchoateReject()); + EXPECT_FALSE(client_->client()->EarlyDataAccepted()); + EXPECT_FALSE(client_->client()->ReceivedInchoateReject()); + + client_->Disconnect(); + + client_->Connect(); + EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + ASSERT_TRUE(client_->client()->connected()); + EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_TRUE(client_session->EarlyDataAccepted()); + EXPECT_TRUE(client_->client()->EarlyDataAccepted()); + + client_->Disconnect(); + + // Restart the server so that the 0-RTT handshake will take 1 RTT. + StopServer(); + server_writer_ = new PacketDroppingTestWriter(); + StartServer(); + + ON_CALL(visitor, OnZeroRttRejected(_)).WillByDefault(Invoke([this]() { + EXPECT_FALSE(GetClientSession()->IsEncryptionEstablished()); + // Trigger an OnCanWrite() to make sure no unencrypted data will be written. + GetClientSession()->OnCanWrite(); + })); + + // The 0-RTT handshake should fail. + client_->Connect(); + ASSERT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); + client_->WaitForWriteToFlush(); + client_->WaitForResponse(); + ASSERT_TRUE(client_->client()->connected()); + + client_session = GetClientSession(); + ASSERT_TRUE(client_session); + EXPECT_FALSE(client_session->EarlyDataAccepted()); + EXPECT_FALSE(client_->client()->EarlyDataAccepted()); +} + TEST_P(EndToEndTest, RejectWithPacketLoss) { // In this test, we intentionally drop the first packet from the // server, which corresponds with the initial REJ response from @@ -2108,10 +2160,17 @@ TEST_P(EndToEndTest, MaxInitialRTT) { client_sent_packet_manager->GetRttStats()->smoothed_rtt().IsInfinite()); const RttStats* server_rtt_stats = server_sent_packet_manager->GetRttStats(); - EXPECT_EQ(static_cast<int64_t>(kMaxInitialRoundTripTimeUs), - server_rtt_stats->initial_rtt().ToMicroseconds()); - EXPECT_GE(static_cast<int64_t>(kMaxInitialRoundTripTimeUs), - server_rtt_stats->smoothed_rtt().ToMicroseconds()); + if (GetQuicReloadableFlag(quic_cap_large_client_initial_rtt)) { + EXPECT_EQ(static_cast<int64_t>(1 * kNumMicrosPerSecond), + server_rtt_stats->initial_rtt().ToMicroseconds()); + EXPECT_GE(static_cast<int64_t>(1 * kNumMicrosPerSecond), + server_rtt_stats->smoothed_rtt().ToMicroseconds()); + } else { + EXPECT_EQ(static_cast<int64_t>(kMaxInitialRoundTripTimeUs), + server_rtt_stats->initial_rtt().ToMicroseconds()); + EXPECT_GE(static_cast<int64_t>(kMaxInitialRoundTripTimeUs), + server_rtt_stats->smoothed_rtt().ToMicroseconds()); + } } else { ADD_FAILURE() << "Missing sent packet manager"; } @@ -2606,7 +2665,7 @@ TEST_P(EndToEndTest, FlowControlsSynced) { if (!version_.UsesHttp3()) { SpdyFramer spdy_framer(SpdyFramer::ENABLE_COMPRESSION); SpdySettingsIR settings_frame; - settings_frame.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, + settings_frame.AddSetting(spdy::SETTINGS_MAX_HEADER_LIST_SIZE, kDefaultMaxUncompressedHeaderSize); SpdySerializedFrame frame(spdy_framer.SerializeFrame(settings_frame)); @@ -3103,7 +3162,6 @@ TEST_P(EndToEndTest, CanceledStreamDoesNotBecomeZombie) { QuicSession* session = GetClientSession(); ASSERT_TRUE(session); // Verify canceled stream does not become zombie. - EXPECT_TRUE(QuicSessionPeer::zombie_streams(session).empty()); EXPECT_EQ(1u, QuicSessionPeer::closed_streams(session).size()); } @@ -4353,86 +4411,6 @@ TEST_P(EndToEndPacketReorderingTest, Buffer0RttRequest) { EXPECT_TRUE(client_->client()->EarlyDataAccepted()); } -// This observer is used to check whether stream write side is closed when -// receiving STOP_SENDING (which ends up as noop). -class StopSendingObserver : public QuicConnectionDebugVisitor { - public: - explicit StopSendingObserver(QuicTestClient* client) - : num_stop_sending_frames_(0), - client_(client), - stream_write_side_closed_before_receiving_stop_sending_(false) {} - - void OnStopSendingFrame(const QuicStopSendingFrame& /*frame*/) override { - ++num_stop_sending_frames_; - stream_write_side_closed_before_receiving_stop_sending_ = - static_cast<QuicSimpleClientStream*>(client_->latest_created_stream()) - ->write_side_closed(); - } - - size_t num_stop_sending_frames() const { return num_stop_sending_frames_; } - - bool stream_write_side_closed_before_receiving_stop_sending() const { - return stream_write_side_closed_before_receiving_stop_sending_; - } - - private: - size_t num_stop_sending_frames_; - QuicTestClient* client_; - bool stream_write_side_closed_before_receiving_stop_sending_; -}; - -// Test that STOP_SENDING makes it to the peer. Create a stream and send a -// STOP_SENDING. The receiver should get a call to QuicStream::OnStopSending. -TEST_P(EndToEndTest, SimpleStopSendingTest) { - const uint16_t kStopSendingTestCode = 123; - ASSERT_TRUE(Initialize()); - if (!version_.HasIetfQuicFrames()) { - return; - } - QuicSession* client_session = GetClientSession(); - ASSERT_TRUE(client_session); - StopSendingObserver observer(client_.get()); - QuicConnection* client_connection = client_session->connection(); - ASSERT_TRUE(client_connection); - client_connection->set_debug_visitor(&observer); - - std::string response_body(1305, 'a'); - SpdyHeaderBlock response_headers; - response_headers[":status"] = quiche::QuicheTextUtils::Uint64ToString(200); - response_headers["content-length"] = - quiche::QuicheTextUtils::Uint64ToString(response_body.length()); - memory_cache_backend_.AddStopSendingResponse( - server_hostname_, "/test_url", std::move(response_headers), response_body, - kStopSendingTestCode); - - EXPECT_TRUE(client_->client()->WaitForOneRttKeysAvailable()); - client_->WaitForDelayedAcks(); - - QuicStreamId stream_id = - client_session->next_outgoing_bidirectional_stream_id(); - client_->SendRequest("/test_url"); - // Wait for the connection to become idle. - client_->WaitForDelayedAcks(); - - EXPECT_THAT(client_->connection_error(), IsQuicNoError()); - QuicSimpleClientStream* client_stream = - static_cast<QuicSimpleClientStream*>(client_->latest_created_stream()); - if (client_stream != nullptr) { - // Ensure the stream has been write closed upon receiving STOP_SENDING. - EXPECT_EQ(stream_id, client_stream->id()); - EXPECT_TRUE(client_stream->write_side_closed()); - client_->WaitUntil( - -1, [&observer]() { return observer.num_stop_sending_frames() > 0; }); - if (!observer.stream_write_side_closed_before_receiving_stop_sending()) { - EXPECT_EQ(kStopSendingTestCode, - static_cast<uint16_t>(client_stream->stream_error())); - } - } else { - ADD_FAILURE() << "Missing client stream"; - } - client_connection->set_debug_visitor(nullptr); -} - TEST_P(EndToEndTest, SimpleStopSendingRstStreamTest) { ASSERT_TRUE(Initialize()); @@ -4726,7 +4704,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulation) { ASSERT_TRUE(Initialize()); return; } - SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); ASSERT_TRUE(Initialize()); SendSynchronousFooRequestAndCheckResponse(); @@ -4750,7 +4727,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithMultiPacketChlo) { ASSERT_TRUE(Initialize()); return; } - SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); constexpr auto kCustomParameter = static_cast<TransportParameters::TransportParameterId>(0xff34); @@ -4774,7 +4750,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithVersionNegotiation) { } client_supported_versions_.insert(client_supported_versions_.begin(), QuicVersionReservedForNegotiation()); - SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); ASSERT_TRUE(Initialize()); SendSynchronousFooRequestAndCheckResponse(); @@ -4793,7 +4768,6 @@ TEST_P(EndToEndTest, LegacyVersionEncapsulationWithLoss) { return; } SetPacketLossPercentage(30); - SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); client_config_.SetClientConnectionOptions(QuicTagVector{kQLVE}); // Disable blackhole detection as this test is testing loss recovery. client_extra_copts_.push_back(kNBHD); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h index 8a3436cc9bc..5164a4b67c8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/http_constants.h @@ -30,7 +30,7 @@ enum Http3AndQpackSettingsIdentifiers : uint64_t { // Same value as spdy::SETTINGS_HEADER_TABLE_SIZE. SETTINGS_QPACK_MAX_TABLE_CAPACITY = 0x01, // Same value as spdy::SETTINGS_MAX_HEADER_LIST_SIZE. - SETTINGS_MAX_HEADER_LIST_SIZE = 0x06, + SETTINGS_MAX_FIELD_SECTION_SIZE = 0x06, SETTINGS_QPACK_BLOCKED_STREAMS = 0x07, }; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc index e1b00c8783b..1a1ec691251 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_promised_info_test.cc @@ -52,8 +52,6 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { void set_authorized(bool authorized) { authorized_ = authorized; } - MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override)); - private: QuicCryptoClientConfig crypto_config_; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc index 0fc903a7283..3e825a05ce8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index_test.cc @@ -40,8 +40,6 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { delete; ~MockQuicSpdyClientSession() override {} - MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override)); - private: QuicCryptoClientConfig crypto_config_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc index c7b4c39dafd..9e1b08a486b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_headers_stream_test.cc @@ -663,7 +663,7 @@ TEST_P(QuicHeadersStreamTest, RespectHttp2SettingsFrameSupportedFields) { // Respect supported settings frames SETTINGS_HEADER_TABLE_SIZE, // SETTINGS_MAX_HEADER_LIST_SIZE. data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, kTestHeaderTableSize); - data.AddSetting(SETTINGS_MAX_HEADER_LIST_SIZE, 2000); + data.AddSetting(spdy::SETTINGS_MAX_HEADER_LIST_SIZE, 2000); SpdySerializedFrame frame(framer_->SerializeFrame(data)); stream_frame_.data_buffer = frame.data(); stream_frame_.data_length = frame.size(); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc index 82d1fe1ca16..1367a953272 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream.cc @@ -20,7 +20,10 @@ namespace quic { QuicReceiveControlStream::QuicReceiveControlStream( PendingStream* pending, QuicSpdySession* spdy_session) - : QuicStream(pending, READ_UNIDIRECTIONAL, /*is_static=*/true), + : QuicStream(pending, + spdy_session, + READ_UNIDIRECTIONAL, + /*is_static=*/true), settings_frame_received_(false), decoder_(this), spdy_session_(spdy_session) { @@ -107,13 +110,6 @@ bool QuicReceiveControlStream::OnGoAwayFrame(const GoAwayFrame& frame) { return false; } - if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_http3_goaway_new_behavior); - } else if (spdy_session()->perspective() == Perspective::IS_SERVER) { - OnWrongFrame("Go Away"); - return false; - } - spdy_session()->OnHttp3GoAway(frame.id); return true; } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc index 32cd298d4e9..5ee5f50e785 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_receive_control_stream_test.cc @@ -156,8 +156,8 @@ TEST_P(QuicReceiveControlStreamTest, ResetControlStream) { TEST_P(QuicReceiveControlStreamTest, ReceiveSettings) { SettingsFrame settings; - settings.values[3] = 2; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[10] = 2; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] = 12; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 37; std::string data = EncodeSettings(settings); @@ -223,8 +223,8 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsTwice) { TEST_P(QuicReceiveControlStreamTest, ReceiveSettingsFragments) { SettingsFrame settings; - settings.values[3] = 2; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[10] = 2; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; std::string data = EncodeSettings(settings); std::string data1 = data.substr(0, 1); std::string data2 = data.substr(1, data.length() - 1); @@ -292,22 +292,12 @@ TEST_P(QuicReceiveControlStreamTest, ReceiveGoAwayFrame) { std::string data = std::string(buffer.get(), header_length); QuicStreamFrame frame(receive_control_stream_->id(), false, offset, data); - EXPECT_FALSE(session_.http3_goaway_received()); + EXPECT_FALSE(session_.goaway_received()); EXPECT_CALL(debug_visitor, OnGoAwayFrameReceived(goaway)); - if (!GetQuicReloadableFlag(quic_http3_goaway_new_behavior) && - perspective() == Perspective::IS_SERVER) { - EXPECT_CALL( - *connection_, - CloseConnection(QUIC_HTTP_FRAME_UNEXPECTED_ON_CONTROL_STREAM, _, _)); - } - receive_control_stream_->OnStreamFrame(frame); - if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior) || - perspective() == Perspective::IS_CLIENT) { - EXPECT_TRUE(session_.http3_goaway_received()); - } + EXPECT_TRUE(session_.goaway_received()); } TEST_P(QuicReceiveControlStreamTest, PushPromiseOnControlStreamShouldClose) { diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc index 7be8ee4d46f..c7f1b381799 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc @@ -30,7 +30,7 @@ void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) { QUIC_BUG << "OnStreamReset() called for write unidirectional stream."; } -bool QuicSendControlStream::OnStopSending(uint16_t /* code */) { +bool QuicSendControlStream::OnStopSending(QuicRstStreamErrorCode /* code */) { stream_delegate()->OnStreamError( QUIC_HTTP_CLOSED_CRITICAL_STREAM, "STOP_SENDING received for send control stream"); @@ -128,7 +128,8 @@ void QuicSendControlStream::SendGoAway(QuicStreamId id) { GoAwayFrame frame; // If the peer has not created any stream yet, use stream ID 0 to indicate no // request is accepted. - if (id == QuicUtils::GetInvalidStreamId(session()->transport_version())) { + if (!GetQuicReloadableFlag(quic_fix_http3_goaway_stream_id) && + id == QuicUtils::GetInvalidStreamId(session()->transport_version())) { id = 0; } frame.id = id; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h index 6240310c80a..25ea5b7a192 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h @@ -31,7 +31,7 @@ class QUIC_EXPORT_PRIVATE QuicSendControlStream : public QuicStream { // Overriding QuicStream::OnStopSending() to make sure control stream is never // closed before connection. void OnStreamReset(const QuicRstStreamFrame& frame) override; - bool OnStopSending(uint16_t code) override; + bool OnStopSending(QuicRstStreamErrorCode code) override; // Send SETTINGS frame if it hasn't been sent yet. Settings frame must be the // first frame sent on this stream. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc index c37bacc2b59..61303de9fce 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_server_session_base_test.cc @@ -9,6 +9,7 @@ #include <string> #include <utility> +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h" @@ -182,20 +183,19 @@ class QuicServerSessionBaseTest : public QuicTestWithParam<ParsedQuicVersion> { // would cause a close in the opposite direction. This allows tests to do the // extra work to get a two-way (full) close where desired. Also sets up // expects needed to ensure that the STOP_SENDING worked as expected. - void InjectStopSendingFrame(QuicStreamId stream_id, - QuicRstStreamErrorCode rst_stream_code) { + void InjectStopSendingFrame(QuicStreamId stream_id) { if (!VersionHasIetfQuicFrames(transport_version())) { // Only needed for version 99/IETF QUIC. Noop otherwise. return; } - QuicStopSendingFrame stop_sending( - kInvalidControlFrameId, stream_id, - static_cast<QuicApplicationErrorCode>(rst_stream_code)); + QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_id, + QUIC_ERROR_PROCESSING_STREAM); EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1); // Expect the RESET_STREAM that is generated in response to receiving a // STOP_SENDING. EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code)); + EXPECT_CALL(*connection_, + OnStreamReset(stream_id, QUIC_ERROR_PROCESSING_STREAM)); session_->OnStopSendingFrame(stop_sending); } @@ -258,8 +258,7 @@ TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { // For version-99 will create and receive a stop-sending, completing // the full-close expected by this test. - InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0), - QUIC_ERROR_PROCESSING_STREAM); + InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0)); EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send the same two bytes of payload in a new packet. @@ -288,8 +287,7 @@ TEST_P(QuicServerSessionBaseTest, NeverOpenStreamDueToReset) { // For version-99 will create and receive a stop-sending, completing // the full-close expected by this test. - InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0), - QUIC_ERROR_PROCESSING_STREAM); + InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0)); EXPECT_EQ(0u, QuicSessionPeer::GetNumOpenDynamicStreams(session_.get())); // Send two bytes of payload. @@ -329,8 +327,7 @@ TEST_P(QuicServerSessionBaseTest, AcceptClosedStream) { // For version-99 will create and receive a stop-sending, completing // the full-close expected by this test. - InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0), - QUIC_ERROR_PROCESSING_STREAM); + InjectStopSendingFrame(GetNthClientInitiatedBidirectionalId(0)); // If we were tracking, we'd probably want to reject this because it's data // past the reset point of stream 3. As it's a closed stream we just drop the @@ -351,7 +348,9 @@ TEST_P(QuicServerSessionBaseTest, MaxOpenStreams) { // streams. For versions other than version 99, the server accepts slightly // more than the negotiated stream limit to deal with rare cases where a // client FIN/RST is lost. - + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(session_->perspective())); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); if (!VersionHasIetfQuicFrames(transport_version())) { @@ -404,7 +403,9 @@ TEST_P(QuicServerSessionBaseTest, MaxAvailableBidirectionalStreams) { // Test that the server closes the connection if a client makes too many data // streams available. The server accepts slightly more than the negotiated // stream limit to deal with rare cases where a client FIN/RST is lost. - + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(session_->perspective())); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); const size_t kAvailableStreamLimit = @@ -511,6 +512,9 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { QuicTagVector copt; copt.push_back(kBWRE); QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(session_->perspective())); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); EXPECT_TRUE( @@ -605,7 +609,7 @@ TEST_P(QuicServerSessionBaseTest, BandwidthEstimates) { QuicPacketNumber(1) + kMinPacketsBetweenServerConfigUpdates, PACKET_4BYTE_PACKET_NUMBER, nullptr, 1000, false, false); sent_packet_manager->OnPacketSent(&packet, now, NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); // Verify that the proto has exactly the values we expect. CachedNetworkParameters expected_network_params; @@ -702,6 +706,9 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) { QuicTagVector copt; copt.push_back(kBWMX); QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(session_->perspective())); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); EXPECT_TRUE( @@ -711,6 +718,9 @@ TEST_P(QuicServerSessionBaseTest, BandwidthMaxEnablesResumption) { TEST_P(QuicServerSessionBaseTest, NoBandwidthResumptionByDefault) { EXPECT_FALSE( QuicServerSessionBasePeer::IsBandwidthResumptionEnabled(session_.get())); + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(session_->perspective())); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); EXPECT_FALSE( @@ -726,6 +736,9 @@ TEST_P(QuicServerSessionBaseTest, TurnOffServerPush) { QuicTagVector copt; copt.push_back(kQNSP); QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(session_->perspective())); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); session_->OnConfigNegotiated(); EXPECT_FALSE(session_->server_push_enabled()); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc index c5ef0c4c596..d7a7b034bfe 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.cc @@ -57,10 +57,7 @@ bool QuicSpdyClientSession::ShouldCreateOutgoingBidirectionalStream() { QUIC_DLOG(INFO) << "Encryption not active so no outgoing stream created."; return false; } - bool goaway_received = VersionUsesHttp3(transport_version()) - ? http3_goaway_received() - : QuicSession::goaway_received(); - if (goaway_received && respect_goaway_) { + if (goaway_received() && respect_goaway_) { QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. " << "Already received goaway."; return false; @@ -131,10 +128,7 @@ bool QuicSpdyClientSession::ShouldCreateIncomingStream(QuicStreamId id) { QUIC_BUG << "ShouldCreateIncomingStream called when disconnected"; return false; } - bool goaway_received = quic::VersionUsesHttp3(transport_version()) - ? http3_goaway_received() - : QuicSession::goaway_received(); - if (goaway_received && respect_goaway_) { + if (goaway_received() && respect_goaway_) { QUIC_DLOG(INFO) << "Failed to create a new outgoing stream. " << "Already received goaway."; return false; diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc index 46305a6386c..1bfe2a74e68 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.cc @@ -213,13 +213,6 @@ void QuicSpdyClientSessionBase::ResetPromised( } } -void QuicSpdyClientSessionBase::CloseStream(QuicStreamId stream_id) { - QuicSpdySession::CloseStream(stream_id); - if (!VersionUsesHttp3(transport_version())) { - headers_stream()->MaybeReleaseSequencerBuffer(); - } -} - void QuicSpdyClientSessionBase::OnStreamClosed(QuicStreamId stream_id) { QuicSpdySession::OnStreamClosed(stream_id); if (!VersionUsesHttp3(transport_version())) { @@ -239,12 +232,12 @@ bool QuicSpdyClientSessionBase::ShouldKeepConnectionAlive() const { bool QuicSpdyClientSessionBase::OnSettingsFrame(const SettingsFrame& frame) { if (!was_zero_rtt_rejected()) { if (max_outbound_header_list_size() != std::numeric_limits<size_t>::max() && - frame.values.find(SETTINGS_MAX_HEADER_LIST_SIZE) == + frame.values.find(SETTINGS_MAX_FIELD_SECTION_SIZE) == frame.values.end()) { CloseConnectionWithDetails( QUIC_HTTP_ZERO_RTT_RESUMPTION_SETTINGS_MISMATCH, "Server accepted 0-RTT but omitted non-default " - "SETTINGS_MAX_HEADER_LIST_SIZE"); + "SETTINGS_MAX_FIELD_SECTION_SIZE"); return false; } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h index 31924793f6b..e09f7cfdac6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_base.h @@ -102,9 +102,6 @@ class QUIC_EXPORT_PRIVATE QuicSpdyClientSessionBase void ResetPromised(QuicStreamId id, QuicRstStreamErrorCode error_code); // Release headers stream's sequencer buffer if it's empty. - void CloseStream(QuicStreamId stream_id) override; - - // Release headers stream's sequencer buffer if it's empty. void OnStreamClosed(QuicStreamId stream_id) override; // Returns true if there are no active requests and no promised streams. diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc index 70b7b360f0b..c3fc0e0ff76 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_session_test.cc @@ -97,7 +97,6 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { QuicUtils::GetInvalidStreamId(GetParam().transport_version)) { auto client_cache = std::make_unique<test::SimpleSessionCache>(); client_session_cache_ = client_cache.get(); - SetQuicRestartFlag(quic_enable_tls_resumption_v4, true); SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true); client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( crypto_test_utils::ProofVerifierForTesting(), std::move(client_cache)); @@ -204,7 +203,7 @@ class QuicSpdyClientSessionTest : public QuicTestWithParam<ParsedQuicVersion> { if (session_->version().UsesHttp3()) { SettingsFrame settings; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; settings.values[256] = 4; // unknown setting session_->OnSettingsFrame(settings); } @@ -969,7 +968,7 @@ TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) { CompleteCryptoHandshake(); SettingsFrame settings; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; settings.values[256] = 4; // unknown setting char application_state[] = {// type (SETTINGS) 0x04, @@ -979,7 +978,7 @@ TEST_P(QuicSpdyClientSessionTest, OnSettingsFrame) { 0x01, // content 0x02, - // identifier (SETTINGS_MAX_HEADER_LIST_SIZE) + // identifier (SETTINGS_MAX_FIELD_SECTION_SIZE) 0x06, // content 0x05, @@ -1078,7 +1077,7 @@ TEST_P(QuicSpdyClientSessionTest, IetfZeroRttSetup) { if (session_->version().UsesHttp3()) { SettingsFrame settings; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; settings.values[256] = 4; // unknown setting session_->OnSettingsFrame(settings); } @@ -1400,7 +1399,7 @@ TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttResumption) { // Let the session receive a different SETTINGS frame. SettingsFrame settings; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; settings.values[256] = 4; // unknown setting session_->OnSettingsFrame(settings); } @@ -1430,8 +1429,8 @@ TEST_P(QuicSpdyClientSessionTest, BadSettingsInZeroRttRejection) { // Let the session receive a different SETTINGS frame. SettingsFrame settings; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 2; - // setting on SETTINGS_MAX_HEADER_LIST_SIZE is reduced. - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 4; + // setting on SETTINGS_MAX_FIELD_SECTION_SIZE is reduced. + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 4; settings.values[256] = 4; // unknown setting session_->OnSettingsFrame(settings); } @@ -1455,8 +1454,8 @@ TEST_P(QuicSpdyClientSessionTest, ServerAcceptsZeroRttButOmitSetting) { // Let the session receive a different SETTINGS frame. SettingsFrame settings; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 1; - // Intentionally omit SETTINGS_MAX_HEADER_LIST_SIZE which was previously sent - // with a non-zero value. + // Intentionally omit SETTINGS_MAX_FIELD_SECTION_SIZE which was previously + // sent with a non-zero value. settings.values[256] = 4; // unknown setting session_->OnSettingsFrame(settings); } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc index ffd4590285a..c8653ed3129 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream_test.cc @@ -46,8 +46,6 @@ class MockQuicSpdyClientSession : public QuicSpdyClientSession { delete; ~MockQuicSpdyClientSession() override = default; - MOCK_METHOD(void, CloseStream, (QuicStreamId stream_id), (override)); - using QuicSession::ActivateStream; private: diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc index a32de6168ee..1d08da3d568 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_server_stream_base_test.cc @@ -75,9 +75,8 @@ TEST_F(QuicSpdyServerStreamBaseTest, if (VersionHasIetfQuicFrames(session_.transport_version())) { // Create and inject a STOP SENDING frame to complete the close // of the stream. This is only needed for version 99/IETF QUIC. - QuicStopSendingFrame stop_sending( - kInvalidControlFrameId, stream_->id(), - static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED)); + QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_->id(), + QUIC_STREAM_CANCELLED); session_.OnStopSendingFrame(stop_sending); } diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc index 3345feadc96..0f806f70bae 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.cc @@ -404,8 +404,8 @@ QuicSpdySession::QuicSpdySession( server_push_enabled_(true), ietf_server_push_enabled_( GetQuicFlag(FLAGS_quic_enable_http3_server_push)), - http3_goaway_sent_(false), - http3_max_push_id_sent_(false) { + http3_max_push_id_sent_(false), + reject_spdy_settings_(GetQuicReloadableFlag(quic_reject_spdy_settings)) { h2_deframer_.set_visitor(spdy_framer_visitor_.get()); h2_deframer_.set_debug_visitor(spdy_framer_visitor_.get()); spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); @@ -415,21 +415,22 @@ QuicSpdySession::~QuicSpdySession() { QUIC_BUG_IF(destruction_indicator_ != 123456789) << "QuicSpdyStream use after free. " << destruction_indicator_ << QuicStackTrace(); + destruction_indicator_ = 987654321; + + if (GetQuicReloadableFlag(quic_clean_up_spdy_session_destructor)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_clean_up_spdy_session_destructor); + return; + } // Set the streams' session pointers in closed and dynamic stream lists // to null to avoid subsequent use of this session. for (auto& stream : *closed_streams()) { static_cast<QuicSpdyStream*>(stream.get())->ClearSession(); } - DCHECK(!remove_zombie_streams() || zombie_streams().empty()); - for (auto const& kv : zombie_streams()) { - static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession(); - } for (auto const& kv : stream_map()) { if (!kv.second->is_static()) { static_cast<QuicSpdyStream*>(kv.second.get())->ClearSession(); } } - destruction_indicator_ = 987654321; } void QuicSpdySession::Initialize() { @@ -471,7 +472,7 @@ void QuicSpdySession::FillSettingsFrame() { qpack_maximum_dynamic_table_capacity_; settings_.values[SETTINGS_QPACK_BLOCKED_STREAMS] = qpack_maximum_blocked_streams_; - settings_.values[SETTINGS_MAX_HEADER_LIST_SIZE] = + settings_.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = max_inbound_header_list_size_; } @@ -660,42 +661,21 @@ void QuicSpdySession::OnHttp3GoAway(uint64_t id) { QUIC_BUG_IF(!version().UsesHttp3()) << "HTTP/3 GOAWAY received on version " << version(); - if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) { - if (last_received_http3_goaway_id_.has_value() && - id > last_received_http3_goaway_id_.value()) { - CloseConnectionWithDetails( - QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS, - quiche::QuicheStrCat("GOAWAY received with ID ", id, - " greater than previously received ID ", - last_received_http3_goaway_id_.value())); - return; - } - last_received_http3_goaway_id_ = id; - - if (perspective() == Perspective::IS_SERVER) { - // TODO(b/151749109): Cancel server pushes with push ID larger than |id|. - return; - } - - // QuicStreamId is uint32_t. Casting to this narrower type is well-defined - // and preserves the lower 32 bits. Both IsBidirectionalStreamId() and - // IsIncomingStream() give correct results, because their return value is - // determined by the least significant two bits. - QuicStreamId stream_id = static_cast<QuicStreamId>(id); - if (!QuicUtils::IsBidirectionalStreamId(stream_id, version()) || - IsIncomingStream(stream_id)) { - CloseConnectionWithDetails(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID, - "GOAWAY with invalid stream ID"); - return; - } - - // TODO(b/161252736): Cancel client requests with ID larger than |id|. - // If |id| is larger than numeric_limits<QuicStreamId>::max(), then use - // max() instead of downcast value. + if (last_received_http3_goaway_id_.has_value() && + id > last_received_http3_goaway_id_.value()) { + CloseConnectionWithDetails( + QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS, + quiche::QuicheStrCat("GOAWAY received with ID ", id, + " greater than previously received ID ", + last_received_http3_goaway_id_.value())); return; } + last_received_http3_goaway_id_ = id; - DCHECK_EQ(perspective(), Perspective::IS_CLIENT); + if (perspective() == Perspective::IS_SERVER) { + // TODO(b/151749109): Cancel server pushes with push ID larger than |id|. + return; + } // QuicStreamId is uint32_t. Casting to this narrower type is well-defined // and preserves the lower 32 bits. Both IsBidirectionalStreamId() and @@ -704,12 +684,14 @@ void QuicSpdySession::OnHttp3GoAway(uint64_t id) { QuicStreamId stream_id = static_cast<QuicStreamId>(id); if (!QuicUtils::IsBidirectionalStreamId(stream_id, version()) || IsIncomingStream(stream_id)) { - CloseConnectionWithDetails( - QUIC_INVALID_STREAM_ID, - "GOAWAY's last stream id has to point to a request stream"); + CloseConnectionWithDetails(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID, + "GOAWAY with invalid stream ID"); return; } - last_received_http3_goaway_id_ = id; + + // TODO(b/161252736): Cancel client requests with ID larger than |id|. + // If |id| is larger than numeric_limits<QuicStreamId>::max(), then use + // max() instead of downcast value. } bool QuicSpdySession::OnStreamsBlockedFrame( @@ -731,9 +713,51 @@ bool QuicSpdySession::OnStreamsBlockedFrame( void QuicSpdySession::SendHttp3GoAway() { DCHECK_EQ(perspective(), Perspective::IS_SERVER); DCHECK(VersionUsesHttp3(transport_version())); - http3_goaway_sent_ = true; - send_control_stream_->SendGoAway( - GetLargestPeerCreatedStreamId(/*unidirectional = */ false)); + + QuicStreamId stream_id = + GetLargestPeerCreatedStreamId(/*unidirectional = */ false); + + if (GetQuicReloadableFlag(quic_fix_http3_goaway_stream_id)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_http3_goaway_stream_id); + if (stream_id == QuicUtils::GetInvalidStreamId(transport_version())) { + // No client-initiated bidirectional streams received yet. + // Send 0 to let client know that all requests can be retried. + stream_id = 0; + } else { + // Tell client that streams starting with the next after the largest + // received one can be retried. + stream_id += QuicUtils::StreamIdDelta(transport_version()); + } + if (last_sent_http3_goaway_id_.has_value() && + last_sent_http3_goaway_id_.value() <= stream_id) { + // MUST not send GOAWAY with identifier larger than previously sent. + // Do not bother sending one with same identifier as before, since GOAWAY + // frames on the control stream are guaranteed to be processed in order. + return; + } + } + + send_control_stream_->SendGoAway(stream_id); + last_sent_http3_goaway_id_ = stream_id; +} + +void QuicSpdySession::SendHttp3Shutdown() { + DCHECK_EQ(perspective(), Perspective::IS_SERVER); + DCHECK(VersionUsesHttp3(transport_version())); + QuicStreamCount advertised_max_incoming_bidirectional_streams = + GetAdvertisedMaxIncomingBidirectionalStreams(); + const QuicStreamId stream_id = + QuicUtils::GetFirstBidirectionalStreamId(transport_version(), + Perspective::IS_CLIENT) + + QuicUtils::StreamIdDelta(transport_version()) * + advertised_max_incoming_bidirectional_streams; + if (last_sent_http3_goaway_id_.has_value() && + last_sent_http3_goaway_id_.value() < stream_id) { + send_control_stream_->SendGoAway(last_sent_http3_goaway_id_.value()); + return; + } + send_control_stream_->SendGoAway(stream_id); + last_sent_http3_goaway_id_ = stream_id; } void QuicSpdySession::WritePushPromise(QuicStreamId original_stream_id, @@ -944,6 +968,9 @@ bool QuicSpdySession::OnSettingsFrame(const SettingsFrame& frame) { bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { if (VersionUsesHttp3(transport_version())) { + if (reject_spdy_settings_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_reject_spdy_settings); + } // SETTINGS frame received on the control stream. switch (id) { case SETTINGS_QPACK_MAX_TABLE_CAPACITY: { @@ -974,9 +1001,9 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { std::min(value, qpack_maximum_dynamic_table_capacity_)); break; } - case SETTINGS_MAX_HEADER_LIST_SIZE: + case SETTINGS_MAX_FIELD_SECTION_SIZE: QUIC_DVLOG(1) << ENDPOINT - << "SETTINGS_MAX_HEADER_LIST_SIZE received with value " + << "SETTINGS_MAX_FIELD_SECTION_SIZE received with value " << value; if (GetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2) && max_outbound_header_list_size_ != @@ -990,7 +1017,7 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { was_zero_rtt_rejected() ? "Server rejected 0-RTT, aborting because " : "", - "Server sent an SETTINGS_MAX_HEADER_LIST_SIZE: ", value, + "Server sent an SETTINGS_MAX_FIELD_SECTION_SIZE: ", value, "which reduces current value: ", max_outbound_header_list_size_)); return false; @@ -1018,6 +1045,21 @@ bool QuicSpdySession::OnSetting(uint64_t id, uint64_t value) { } break; } + case spdy::SETTINGS_ENABLE_PUSH: + QUIC_FALLTHROUGH_INTENDED; + case spdy::SETTINGS_MAX_CONCURRENT_STREAMS: + QUIC_FALLTHROUGH_INTENDED; + case spdy::SETTINGS_INITIAL_WINDOW_SIZE: + QUIC_FALLTHROUGH_INTENDED; + case spdy::SETTINGS_MAX_FRAME_SIZE: + if (reject_spdy_settings_) { + CloseConnectionWithDetails( + QUIC_HTTP_RECEIVE_SPDY_SETTING, + quiche::QuicheStrCat( + "received HTTP/2 specific setting in HTTP/3 session: ", id)); + return false; + } + break; default: QUIC_DVLOG(1) << ENDPOINT << "Unknown setting identifier " << id << " received with value " << value; @@ -1239,7 +1281,7 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) { return false; } auto encoder_receive = std::make_unique<QpackReceiveStream>( - pending, qpack_decoder_->encoder_stream_receiver()); + pending, this, qpack_decoder_->encoder_stream_receiver()); qpack_encoder_receive_stream_ = encoder_receive.get(); ActivateStream(std::move(encoder_receive)); qpack_encoder_receive_stream_->SetUnblocked(); @@ -1256,7 +1298,7 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) { return false; } auto decoder_receive = std::make_unique<QpackReceiveStream>( - pending, qpack_encoder_->decoder_stream_receiver()); + pending, this, qpack_encoder_->decoder_stream_receiver()); qpack_decoder_receive_stream_ = decoder_receive.get(); ActivateStream(std::move(decoder_receive)); qpack_decoder_receive_stream_->SetUnblocked(); @@ -1268,9 +1310,13 @@ bool QuicSpdySession::ProcessPendingStream(PendingStream* pending) { return true; } default: - SendStopSending(static_cast<QuicApplicationErrorCode>( - QuicHttp3ErrorCode::STREAM_CREATION_ERROR), - pending->id()); + if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) { + SendStopSending(QUIC_STREAM_STREAM_CREATION_ERROR, pending->id()); + } else { + SendStopSending(static_cast<QuicRstStreamErrorCode>( + QuicHttp3ErrorCode::STREAM_CREATION_ERROR), + pending->id()); + } pending->StopReading(); } return false; @@ -1403,6 +1449,18 @@ void QuicSpdySession::EnableServerPush() { ietf_server_push_enabled_ = true; } +bool QuicSpdySession::goaway_received() const { + return VersionUsesHttp3(transport_version()) + ? last_received_http3_goaway_id_.has_value() + : transport_goaway_received(); +} + +bool QuicSpdySession::goaway_sent() const { + return VersionUsesHttp3(transport_version()) + ? last_sent_http3_goaway_id_.has_value() + : transport_goaway_sent(); +} + bool QuicSpdySession::CanCreatePushStreamWithId(PushId push_id) { DCHECK(VersionUsesHttp3(transport_version())); diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h index 4c50e7fd001..db8fc6b2df2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session.h @@ -225,9 +225,17 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // Send GOAWAY if the peer is blocked on the implementation max. bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override; - // Write the GOAWAY |frame| on control stream. + // Write GOAWAY frame on the control stream to notify the client that every + // stream that has not reached the server yet can be retried. Do not send a + // GOAWAY frame if it could not convey new information to the client with + // respect to the previous GOAWAY frame. void SendHttp3GoAway(); + // Write advisory GOAWAY frame on the control stream with the max stream ID + // that the client could send. If GOAWAY has already been sent, the lesser of + // its max stream ID and the one advertised via MAX_STREAMS is used. + void SendHttp3Shutdown(); + // Write |headers| for |promised_stream_id| on |original_stream_id| in a // PUSH_PROMISE frame to peer. virtual void WritePushPromise(QuicStreamId original_stream_id, @@ -353,11 +361,12 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession Http3DebugVisitor* debug_visitor() { return debug_visitor_; } - bool http3_goaway_received() const { - return last_received_http3_goaway_id_.has_value(); - } - - bool http3_goaway_sent() const { return http3_goaway_sent_; } + // When using Google QUIC, return whether a transport layer GOAWAY frame has + // been received or sent. + // When using IETF QUIC, return whether an HTTP/3 GOAWAY frame has been + // received or sent. + bool goaway_received() const; + bool goaway_sent() const; // Log header compression ratio histogram. // |using_qpack| is true for QPACK, false for HPACK. @@ -581,13 +590,17 @@ class QUIC_EXPORT_PRIVATE QuicSpdySession // The identifier in the most recently received GOAWAY frame. Unset if no // GOAWAY frame has been received yet. quiche::QuicheOptional<uint64_t> last_received_http3_goaway_id_; - // If the endpoint has sent HTTP/3 GOAWAY frame. - bool http3_goaway_sent_; + // The identifier in the most recently sent GOAWAY frame. Unset if no GOAWAY + // frame has been sent yet. + quiche::QuicheOptional<uint64_t> last_sent_http3_goaway_id_; // Only used by a client, only with IETF QUIC. True if a MAX_PUSH_ID frame // has been sent, in which case |max_push_id_| has the value sent in the most // recent MAX_PUSH_ID frame. Once true, never goes back to false. bool http3_max_push_id_sent_; + + // Latched value of reloadable flag quic_reject_spdy_settings. + const bool reject_spdy_settings_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc index fd0c645ab19..6f7d85f68d2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_session_test.cc @@ -131,6 +131,9 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { } // QuicCryptoStream implementation + ssl_early_data_reason_t EarlyDataReason() const override { + return ssl_early_data_unknown; + } bool encryption_established() const override { return encryption_established_; } @@ -1080,9 +1083,88 @@ TEST_P(QuicSpdySessionTestServer, SendHttp3GoAway) { EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); + // No client-initiated stream has been received, therefore a GOAWAY frame with + // stream ID = 0 is sent to notify the client that all requests can be retried + // on a different connection. + EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 0)); + session_.SendHttp3GoAway(); + EXPECT_TRUE(session_.goaway_sent()); + + const QuicStreamId kTestStreamId = + GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0); + EXPECT_CALL(*connection_, OnStreamReset(kTestStreamId, _)).Times(0); + EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId)); +} + +TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayAfterStreamIsCreated) { + if (!VersionUsesHttp3(transport_version())) { + return; + } + + if (!GetQuicReloadableFlag(quic_fix_http3_goaway_stream_id)) { + return; + } + + CompleteHandshake(); + StrictMock<MockHttp3DebugVisitor> debug_visitor; + session_.set_debug_visitor(&debug_visitor); + + const QuicStreamId kTestStreamId = + GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0); + EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId)); + + EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); + // The first stream, of kTestStreamId = 0, could already have been processed. + // A GOAWAY frame is sent to notify the client that requests starting with + // stream ID = 4 can be retried on a different connection. + EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(/* stream_id = */ 4)); + session_.SendHttp3GoAway(); + EXPECT_TRUE(session_.goaway_sent()); + + // No more GOAWAY frames are sent because they could not convey new + // information to the client. + session_.SendHttp3GoAway(); +} + +TEST_P(QuicSpdySessionTestServer, SendHttp3Shutdown) { + if (!VersionUsesHttp3(transport_version())) { + return; + } + + CompleteHandshake(); + StrictMock<MockHttp3DebugVisitor> debug_visitor; + session_.set_debug_visitor(&debug_visitor); + + EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _)) + .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(_)); + session_.SendHttp3Shutdown(); + EXPECT_TRUE(session_.goaway_sent()); + + const QuicStreamId kTestStreamId = + GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0); + EXPECT_CALL(*connection_, OnStreamReset(kTestStreamId, _)).Times(0); + EXPECT_TRUE(session_.GetOrCreateStream(kTestStreamId)); +} + +TEST_P(QuicSpdySessionTestServer, SendHttp3GoAwayAfterShutdownNotice) { + if (!VersionUsesHttp3(transport_version())) { + return; + } + + CompleteHandshake(); + StrictMock<MockHttp3DebugVisitor> debug_visitor; + session_.set_debug_visitor(&debug_visitor); + + EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _)) + .Times(2) + .WillRepeatedly(Return(WriteResult(WRITE_STATUS_OK, 0))); + EXPECT_CALL(debug_visitor, OnGoAwayFrameSent(_)).Times(2); + + session_.SendHttp3Shutdown(); + EXPECT_TRUE(session_.goaway_sent()); session_.SendHttp3GoAway(); - EXPECT_TRUE(session_.http3_goaway_sent()); const QuicStreamId kTestStreamId = GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0); @@ -1116,14 +1198,11 @@ TEST_P(QuicSpdySessionTestServer, Http3GoAwayLargerIdThanBefore) { if (!VersionUsesHttp3(transport_version())) { return; } - if (!GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) { - return; - } - EXPECT_FALSE(session_.http3_goaway_received()); + EXPECT_FALSE(session_.goaway_received()); PushId push_id1 = 0; session_.OnHttp3GoAway(push_id1); - EXPECT_TRUE(session_.http3_goaway_received()); + EXPECT_TRUE(session_.goaway_received()); EXPECT_CALL( *connection_, @@ -1138,6 +1217,7 @@ TEST_P(QuicSpdySessionTestServer, Http3GoAwayLargerIdThanBefore) { // Test that server session will send a connectivity probe in response to a // connectivity probe on the same path. TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) { + connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); QuicSocketAddress old_peer_address = QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort); EXPECT_EQ(old_peer_address, session_.peer_address()); @@ -1145,8 +1225,14 @@ TEST_P(QuicSpdySessionTestServer, ServerReplyToConnecitivityProbe) { QuicSocketAddress new_peer_address = QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort + 1); - EXPECT_CALL(*connection_, - SendConnectivityProbingResponsePacket(new_peer_address)); + if (connection_->send_path_response()) { + EXPECT_CALL(*connection_, + SendConnectivityProbingPacket(nullptr, new_peer_address)); + } else { + EXPECT_CALL(*connection_, + SendConnectivityProbingResponsePacket(new_peer_address)); + } + if (VersionHasIetfQuicFrames(transport_version())) { // Need to explicitly do this to emulate the reception of a PathChallenge, // which stores its payload for use in generating the response. @@ -1198,9 +1284,9 @@ TEST_P(QuicSpdySessionTestServer, RstStreamBeforeHeadersDecompressed) { // one-way close. if (VersionHasIetfQuicFrames(transport_version())) { // Only needed for version 99/IETF QUIC. - QuicStopSendingFrame stop_sending( - kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0), - static_cast<QuicApplicationErrorCode>(QUIC_ERROR_PROCESSING_STREAM)); + QuicStopSendingFrame stop_sending(kInvalidControlFrameId, + GetNthClientInitiatedBidirectionalId(0), + QUIC_ERROR_PROCESSING_STREAM); // Expect the RESET_STREAM that is generated in response to receiving a // STOP_SENDING. EXPECT_CALL(*connection_, @@ -1480,9 +1566,8 @@ TEST_P(QuicSpdySessionTestServer, // one-way close. if (VersionHasIetfQuicFrames(transport_version())) { // Only needed for version 99/IETF QUIC. - QuicStopSendingFrame stop_sending( - kInvalidControlFrameId, stream->id(), - static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED)); + QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream->id(), + QUIC_STREAM_CANCELLED); // Expect the RESET_STREAM that is generated in response to receiving a // STOP_SENDING. EXPECT_CALL(*connection_, @@ -2143,7 +2228,7 @@ TEST_P(QuicSpdySessionTestServer, OnPriorityUpdateFrame) { // PRIORITY_UPDATE frame arrives after stream creation. TestStream* stream1 = session_.CreateIncomingStream(stream_id1); - EXPECT_EQ(QuicStream::kDefaultUrgency, + EXPECT_EQ(QuicStream::DefaultUrgency(), stream1->precedence().spdy3_priority()); EXPECT_CALL(debug_visitor, OnPriorityUpdateFrameReceived(priority_update1)); session_.OnStreamFrame(data3); @@ -2193,9 +2278,15 @@ TEST_P(QuicSpdySessionTestServer, SimplePendingStreamType) { QuicStopSendingFrame* stop_sending = frame.stop_sending_frame; EXPECT_EQ(stream_id, stop_sending->stream_id); - EXPECT_EQ(QuicHttp3ErrorCode::STREAM_CREATION_ERROR, - static_cast<QuicHttp3ErrorCode>( - stop_sending->application_error_code)); + EXPECT_EQ( + GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code) + ? QUIC_STREAM_STREAM_CREATION_ERROR + : static_cast<QuicRstStreamErrorCode>( + QuicHttp3ErrorCode::STREAM_CREATION_ERROR), + stop_sending->error_code); + EXPECT_EQ( + static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR), + stop_sending->ietf_error_code); return ClearControlFrame(frame); })); @@ -2324,7 +2415,7 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStream) { SettingsFrame settings; settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] = 512; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] = 42; std::string data = EncodeSettings(settings); QuicStreamFrame frame(stream_id, false, 1, quiche::QuicheStringPiece(data)); @@ -2356,8 +2447,8 @@ TEST_P(QuicSpdySessionTestServer, ReceiveControlStreamOutOfOrderDelivery) { GetNthClientInitiatedUnidirectionalStreamId(transport_version(), 3); char type[] = {kControlStream}; SettingsFrame settings; - settings.values[3] = 2; - settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] = 5; + settings.values[10] = 2; + settings.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; std::string data = EncodeSettings(settings); QuicStreamFrame data1(stream_id, false, 1, quiche::QuicheStringPiece(data)); @@ -2679,17 +2770,9 @@ TEST_P(QuicSpdySessionTestClient, InvalidHttp3GoAway) { if (!VersionUsesHttp3(transport_version())) { return; } - if (GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) { - EXPECT_CALL(*connection_, - CloseConnection(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID, - "GOAWAY with invalid stream ID", _)); - } else { - EXPECT_CALL( - *connection_, - CloseConnection( - QUIC_INVALID_STREAM_ID, - "GOAWAY's last stream id has to point to a request stream", _)); - } + EXPECT_CALL(*connection_, + CloseConnection(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID, + "GOAWAY with invalid stream ID", _)); QuicStreamId stream_id = GetNthServerInitiatedUnidirectionalStreamId(transport_version(), 0); session_.OnHttp3GoAway(stream_id); @@ -2699,15 +2782,12 @@ TEST_P(QuicSpdySessionTestClient, Http3GoAwayLargerIdThanBefore) { if (!VersionUsesHttp3(transport_version())) { return; } - if (!GetQuicReloadableFlag(quic_http3_goaway_new_behavior)) { - return; - } - EXPECT_FALSE(session_.http3_goaway_received()); + EXPECT_FALSE(session_.goaway_received()); QuicStreamId stream_id1 = GetNthClientInitiatedBidirectionalStreamId(transport_version(), 0); session_.OnHttp3GoAway(stream_id1); - EXPECT_TRUE(session_.http3_goaway_received()); + EXPECT_TRUE(session_.goaway_received()); EXPECT_CALL( *connection_, @@ -2777,7 +2857,7 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) { if (VersionUsesHttp3(transport_version())) { EXPECT_EQ(std::numeric_limits<size_t>::max(), session_.max_outbound_header_list_size()); - session_.OnSetting(SETTINGS_MAX_HEADER_LIST_SIZE, 5); + session_.OnSetting(SETTINGS_MAX_FIELD_SECTION_SIZE, 5); EXPECT_EQ(5u, session_.max_outbound_header_list_size()); EXPECT_CALL(*writer_, WritePacket(_, _, _, _, _)) @@ -2798,7 +2878,7 @@ TEST_P(QuicSpdySessionTestServer, OnSetting) { EXPECT_EQ(std::numeric_limits<size_t>::max(), session_.max_outbound_header_list_size()); - session_.OnSetting(SETTINGS_MAX_HEADER_LIST_SIZE, 5); + session_.OnSetting(SETTINGS_MAX_FIELD_SECTION_SIZE, 5); EXPECT_EQ(5u, session_.max_outbound_header_list_size()); EXPECT_TRUE(session_.server_push_enabled()); @@ -2900,8 +2980,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) { ASSERT_TRUE(control_stream); QuicStopSendingFrame stop_sending_control_stream( - kInvalidControlFrameId, control_stream->id(), - static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED)); + kInvalidControlFrameId, control_stream->id(), QUIC_STREAM_CANCELLED); EXPECT_CALL( *connection_, CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM, @@ -2913,8 +2992,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) { ASSERT_TRUE(decoder_stream); QuicStopSendingFrame stop_sending_decoder_stream( - kInvalidControlFrameId, decoder_stream->id(), - static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED)); + kInvalidControlFrameId, decoder_stream->id(), QUIC_STREAM_CANCELLED); EXPECT_CALL( *connection_, CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM, @@ -2926,8 +3004,7 @@ TEST_P(QuicSpdySessionTestServer, PeerClosesCriticalSendStream) { ASSERT_TRUE(encoder_stream); QuicStopSendingFrame stop_sending_encoder_stream( - kInvalidControlFrameId, encoder_stream->id(), - static_cast<QuicApplicationErrorCode>(QUIC_STREAM_CANCELLED)); + kInvalidControlFrameId, encoder_stream->id(), QUIC_STREAM_CANCELLED); EXPECT_CALL( *connection_, CloseConnection(QUIC_HTTP_CLOSED_CRITICAL_STREAM, @@ -3027,6 +3104,25 @@ TEST_P(QuicSpdySessionTestClient, DoNotSendInitialMaxPushIdIfSetToDefaut) { CompleteHandshake(); } +TEST_P(QuicSpdySessionTestClient, ReceiveSpdySettingInHttp3) { + if (!VersionUsesHttp3(transport_version()) || + !GetQuicReloadableFlag(quic_reject_spdy_settings)) { + return; + } + + SettingsFrame frame; + frame.values[SETTINGS_MAX_FIELD_SECTION_SIZE] = 5; + // https://datatracker.ietf.org/doc/html/draft-ietf-quic-http-30#section-7.2.4.1 + // specifies the presence of HTTP/2 setting as error. + frame.values[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 100; + + CompleteHandshake(); + + EXPECT_CALL(*connection_, + CloseConnection(QUIC_HTTP_RECEIVE_SPDY_SETTING, _, _)); + session_.OnSettingsFrame(frame); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc index 259493f3862..1c5f9645822 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.cc @@ -199,7 +199,7 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id, sequencer_offset_(0), is_decoder_processing_input_(false), ack_listener_(nullptr), - last_sent_urgency_(kDefaultUrgency) { + last_sent_urgency_(DefaultUrgency()) { DCHECK_EQ(session()->connection(), spdy_session->connection()); DCHECK_EQ(transport_version(), spdy_session->transport_version()); DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); @@ -220,7 +220,7 @@ QuicSpdyStream::QuicSpdyStream(QuicStreamId id, QuicSpdyStream::QuicSpdyStream(PendingStream* pending, QuicSpdySession* spdy_session, StreamType type) - : QuicStream(pending, type, /*is_static=*/false), + : QuicStream(pending, spdy_session, type, /*is_static=*/false), spdy_session_(spdy_session), on_body_available_called_because_sequencer_is_closed_(false), visitor_(nullptr), @@ -235,7 +235,7 @@ QuicSpdyStream::QuicSpdyStream(PendingStream* pending, sequencer_offset_(sequencer()->NumBytesConsumed()), is_decoder_processing_input_(false), ack_listener_(nullptr), - last_sent_urgency_(kDefaultUrgency) { + last_sent_urgency_(DefaultUrgency()) { DCHECK_EQ(session()->connection(), spdy_session->connection()); DCHECK_EQ(transport_version(), spdy_session->transport_version()); DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id())); @@ -801,6 +801,11 @@ void QuicSpdyStream::OnDataAvailable() { void QuicSpdyStream::OnClose() { QuicStream::OnClose(); + if (GetQuicReloadableFlag(quic_abort_qpack_on_stream_close)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_abort_qpack_on_stream_close); + qpack_decoded_headers_accumulator_.reset(); + } + if (visitor_) { Visitor* visitor = visitor_; // Calling Visitor::OnClose() may result the destruction of the visitor, diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h index 61bc1fb35c9..5a58842e1f8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h @@ -209,11 +209,13 @@ class QUIC_EXPORT_PRIVATE QuicSpdyStream // Called when owning session is getting deleted to avoid subsequent // use of the spdy_session_ member. + // TODO(b/136274541): Remove this method once + // flag_quic_clean_up_spdy_session_destructor is deprecated. void ClearSession(); // Returns true if the sequencer has delivered the FIN, and no more body bytes // will be available. - bool IsClosed() { return sequencer()->IsClosed(); } + bool IsSequencerClosed() { return sequencer()->IsClosed(); } // QpackDecodedHeadersAccumulator::Visitor implementation. void OnHeadersDecoded(QuicHeaderList headers, diff --git a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc index cc0e3ec2e80..1c55c96af0b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/quic_spdy_stream_test.cc @@ -119,6 +119,9 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { } // QuicCryptoStream implementation + ssl_early_data_reason_t EarlyDataReason() const override { + return ssl_early_data_unknown; + } bool encryption_established() const override { return encryption_established_; } @@ -2416,6 +2419,64 @@ TEST_P(QuicSpdyStreamTest, AsyncErrorDecodingTrailers) { session_->qpack_decoder()->OnInsertWithoutNameReference("trailing", "foobar"); } +// Regression test for b/132603592: QPACK decoding unblocked after stream is +// closed. +TEST_P(QuicSpdyStreamTest, HeaderDecodingUnblockedAfterStreamClosed) { + if (!UsesHttp3()) { + return; + } + + Initialize(kShouldProcessData); + testing::InSequence s; + session_->qpack_decoder()->OnSetDynamicTableCapacity(1024); + StrictMock<MockHttp3DebugVisitor> debug_visitor; + session_->set_debug_visitor(&debug_visitor); + + // HEADERS frame referencing first dynamic table entry. + std::string encoded_headers = quiche::QuicheTextUtils::HexDecode("020080"); + std::string headers = HeadersFrame(encoded_headers); + EXPECT_CALL(debug_visitor, + OnHeadersFrameReceived(stream_->id(), encoded_headers.length())); + stream_->OnStreamFrame(QuicStreamFrame(stream_->id(), false, 0, headers)); + + // Decoding is blocked because dynamic table entry has not been received yet. + EXPECT_FALSE(stream_->headers_decompressed()); + + // Decoder stream type and stream cancellation instruction. + auto decoder_send_stream = + QuicSpdySessionPeer::GetQpackDecoderSendStream(session_.get()); + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 0, _, _, _)); + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 1, _, _, _)); + + // Reset stream. + EXPECT_CALL(*session_, + SendRstStream(stream_->id(), QUIC_STREAM_CANCELLED, _, _)); + stream_->Reset(QUIC_STREAM_CANCELLED); + + if (!GetQuicReloadableFlag(quic_abort_qpack_on_stream_close)) { + // Header acknowledgement. + EXPECT_CALL(*session_, + WritevData(decoder_send_stream->id(), /* write_length = */ 1, + /* offset = */ 2, _, _, _)); + EXPECT_CALL(debug_visitor, OnHeadersDecoded(stream_->id(), _)); + } + + // Deliver dynamic table entry to decoder. + session_->qpack_decoder()->OnInsertWithoutNameReference("foo", "bar"); + + if (GetQuicReloadableFlag(quic_abort_qpack_on_stream_close)) { + EXPECT_FALSE(stream_->headers_decompressed()); + } else { + // Verify headers. + EXPECT_TRUE(stream_->headers_decompressed()); + EXPECT_THAT(stream_->header_list(), ElementsAre(Pair("foo", "bar"))); + } +} + class QuicSpdyStreamIncrementalConsumptionTest : public QuicSpdyStreamTest { protected: QuicSpdyStreamIncrementalConsumptionTest() : offset_(0), consumed_bytes_(0) {} diff --git a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc index 69dd3d0a221..847408d89cc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/http/spdy_utils.cc @@ -160,7 +160,7 @@ std::string SpdyUtils::H3SettingsToString( Http3AndQpackSettingsIdentifiers identifier) { switch (identifier) { RETURN_STRING_LITERAL(SETTINGS_QPACK_MAX_TABLE_CAPACITY); - RETURN_STRING_LITERAL(SETTINGS_MAX_HEADER_LIST_SIZE); + RETURN_STRING_LITERAL(SETTINGS_MAX_FIELD_SECTION_SIZE); RETURN_STRING_LITERAL(SETTINGS_QPACK_BLOCKED_STREAMS); } return quiche::QuicheStrCat("UNSUPPORTED_SETTINGS_TYPE(", identifier, ")"); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc index d2fc88b9ecd..b2f15c4ecb3 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.cc @@ -9,8 +9,9 @@ namespace quic { QpackReceiveStream::QpackReceiveStream(PendingStream* pending, + QuicSession* session, QpackStreamReceiver* receiver) - : QuicStream(pending, READ_UNIDIRECTIONAL, /*is_static=*/true), + : QuicStream(pending, session, READ_UNIDIRECTIONAL, /*is_static=*/true), receiver_(receiver) {} void QpackReceiveStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) { diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h index 0613871625e..0814985760c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_receive_stream.h @@ -19,7 +19,9 @@ class QUIC_EXPORT_PRIVATE QpackReceiveStream : public QuicStream { public: // Construct receive stream from pending stream, the |pending| object needs // to be deleted after the construction. - QpackReceiveStream(PendingStream* pending, QpackStreamReceiver* receiver); + QpackReceiveStream(PendingStream* pending, + QuicSession* session, + QpackStreamReceiver* receiver); QpackReceiveStream(const QpackReceiveStream&) = delete; QpackReceiveStream& operator=(const QpackReceiveStream&) = delete; ~QpackReceiveStream() override = default; diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc index 15525b593d5..176c431afb9 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.cc @@ -20,7 +20,7 @@ void QpackSendStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) { QUIC_BUG << "OnStreamReset() called for write unidirectional stream."; } -bool QpackSendStream::OnStopSending(uint16_t /* code */) { +bool QpackSendStream::OnStopSending(QuicRstStreamErrorCode /* code */) { stream_delegate()->OnStreamError( QUIC_HTTP_CLOSED_CRITICAL_STREAM, "STOP_SENDING received for QPACK send stream"); diff --git a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h index 50d2808a46e..e8a4ea797d2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/qpack/qpack_send_stream.h @@ -33,7 +33,7 @@ class QUIC_EXPORT_PRIVATE QpackSendStream : public QuicStream, // Overriding QuicStream::OnStopSending() to make sure QPACK stream is never // closed before connection. void OnStreamReset(const QuicRstStreamFrame& frame) override; - bool OnStopSending(uint16_t code) override; + bool OnStopSending(QuicRstStreamErrorCode code) override; // The send QPACK stream is write unidirectional, so this method // should never be called. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc index 23597e289e9..bac4e181c20 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_config.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_config.cc @@ -1326,6 +1326,7 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( *error_details = "MinAckDelay is greater than MaxAckDelay."; return IETF_QUIC_PROTOCOL_VIOLATION; } + QUIC_RELOADABLE_FLAG_COUNT(quic_record_received_min_ack_delay); min_ack_delay_ms_.SetReceivedValue(params.min_ack_delay_us.value() / kNumMicrosPerMilli); } @@ -1353,14 +1354,11 @@ QuicErrorCode QuicConfig::ProcessTransportParameters( } } - bool google_params_already_parsed = false; if (params.initial_round_trip_time_us.value() > 0) { - google_params_already_parsed = true; initial_round_trip_time_us_.SetReceivedValue( params.initial_round_trip_time_us.value()); } if (params.google_connection_options.has_value()) { - google_params_already_parsed = true; connection_options_.SetReceivedValues( params.google_connection_options.value()); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc index 5d32a5f171c..e1799817168 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.cc @@ -26,6 +26,7 @@ #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_legacy_version_encapsulator.h" +#include "net/third_party/quiche/src/quic/core/quic_packet_creator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" @@ -37,6 +38,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_hostname_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_utils.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -65,6 +67,7 @@ class AckAlarmDelegate : public QuicAlarm::Delegate { void OnAlarm() override { DCHECK(connection_->ack_frame_updated()); + DCHECK(connection_->connected()); QuicConnection::ScopedPacketFlusher flusher(connection_); if (connection_->SupportsMultiplePacketNumberSpaces()) { connection_->SendAllPendingAcks(); @@ -88,7 +91,10 @@ class RetransmissionAlarmDelegate : public QuicAlarm::Delegate { RetransmissionAlarmDelegate& operator=(const RetransmissionAlarmDelegate&) = delete; - void OnAlarm() override { connection_->OnRetransmissionTimeout(); } + void OnAlarm() override { + DCHECK(connection_->connected()); + connection_->OnRetransmissionTimeout(); + } private: QuicConnection* connection_; @@ -103,7 +109,10 @@ class SendAlarmDelegate : public QuicAlarm::Delegate { SendAlarmDelegate(const SendAlarmDelegate&) = delete; SendAlarmDelegate& operator=(const SendAlarmDelegate&) = delete; - void OnAlarm() override { connection_->WriteAndBundleAcksIfNotBlocked(); } + void OnAlarm() override { + DCHECK(connection_->connected()); + connection_->WriteAndBundleAcksIfNotBlocked(); + } private: QuicConnection* connection_; @@ -116,7 +125,10 @@ class PingAlarmDelegate : public QuicAlarm::Delegate { PingAlarmDelegate(const PingAlarmDelegate&) = delete; PingAlarmDelegate& operator=(const PingAlarmDelegate&) = delete; - void OnAlarm() override { connection_->OnPingTimeout(); } + void OnAlarm() override { + DCHECK(connection_->connected()); + connection_->OnPingTimeout(); + } private: QuicConnection* connection_; @@ -130,7 +142,10 @@ class MtuDiscoveryAlarmDelegate : public QuicAlarm::Delegate { MtuDiscoveryAlarmDelegate& operator=(const MtuDiscoveryAlarmDelegate&) = delete; - void OnAlarm() override { connection_->DiscoverMtu(); } + void OnAlarm() override { + DCHECK(connection_->connected()); + connection_->DiscoverMtu(); + } private: QuicConnection* connection_; @@ -146,6 +161,7 @@ class ProcessUndecryptablePacketsAlarmDelegate : public QuicAlarm::Delegate { const ProcessUndecryptablePacketsAlarmDelegate&) = delete; void OnAlarm() override { + DCHECK(connection_->connected()); QuicConnection::ScopedPacketFlusher flusher(connection_); connection_->MaybeProcessUndecryptablePackets(); } @@ -208,6 +224,7 @@ QuicConnection::QuicConnection( server_connection_id.length()), current_packet_content_(NO_FRAMES_RECEIVED), is_current_packet_connectivity_probing_(false), + has_path_challenge_in_current_packet_(false), current_effective_peer_migration_type_(NO_CHANGE), helper_(helper), alarm_factory_(alarm_factory), @@ -230,9 +247,6 @@ QuicConnection::QuicConnection( should_last_packet_instigate_acks_(false), max_undecryptable_packets_(0), max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)), - pending_version_negotiation_packet_(false), - send_ietf_version_negotiation_packet_(false), - send_version_negotiation_packet_with_prefixed_lengths_(false), idle_timeout_connection_close_behavior_( ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET), num_rtos_for_blackhole_detection_(0), @@ -304,6 +318,10 @@ QuicConnection::QuicConnection( &arena_, alarm_factory_), support_handshake_done_(version().HasHandshakeDone()) { + QUIC_BUG_IF(!start_peer_migration_earlier_ && send_path_response_); + if (fix_missing_connected_checks_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_add_missing_connected_checks); + } QUIC_DLOG(INFO) << ENDPOINT << "Created connection with server connection ID " << server_connection_id << " and version: " << ParsedQuicVersionToString(version()); @@ -347,6 +365,7 @@ QuicConnection::QuicConnection( blackhole_detection_disabled_ = true; } } + packet_creator_.SetDefaultPeerAddress(initial_peer_address); } void QuicConnection::InstallInitialCrypters(QuicConnectionId connection_id) { @@ -519,9 +538,7 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { idle_timeout_connection_close_behavior_ = ConnectionCloseBehavior:: SILENT_CLOSE_WITH_CONNECTION_CLOSE_PACKET_SERIALIZED; } - if (GetQuicReloadableFlag(quic_no_silent_close_for_idle_timeout) && - config.HasClientRequestedIndependentOption(kNSLC, perspective_)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_no_silent_close_for_idle_timeout); + if (config.HasClientRequestedIndependentOption(kNSLC, perspective_)) { idle_timeout_connection_close_behavior_ = ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET; } @@ -581,6 +598,12 @@ void QuicConnection::SetFromConfig(const QuicConfig& config) { if (config.HasClientRequestedIndependentOption(kFIDT, perspective_)) { idle_network_detector_.enable_shorter_idle_timeout_on_sent_packet(); } + if (config.HasClientRequestedIndependentOption(k3AFF, perspective_)) { + anti_amplification_factor_ = 3; + } + if (config.HasClientRequestedIndependentOption(k10AF, perspective_)) { + anti_amplification_factor_ = 10; + } if (debug_visitor_ != nullptr) { debug_visitor_->OnSetFromConfig(config); @@ -1103,6 +1126,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { // Initialize the current packet content state. current_packet_content_ = NO_FRAMES_RECEIVED; is_current_packet_connectivity_probing_ = false; + has_path_challenge_in_current_packet_ = false; current_effective_peer_migration_type_ = NO_CHANGE; if (perspective_ == Perspective::IS_CLIENT) { @@ -1112,7 +1136,7 @@ bool QuicConnection::OnPacketHeader(const QuicPacketHeader& header) { // client connections. // TODO(fayang): only change peer addresses in application data packet // number space. - direct_peer_address_ = last_packet_source_address_; + UpdatePeerAddress(last_packet_source_address_); effective_peer_address_ = GetEffectivePeerAddressFromCurrentPacket(); } } else { @@ -1293,6 +1317,8 @@ bool QuicConnection::OnAckFrameEnd(QuicPacketNumber start) { } const bool one_rtt_packet_was_acked = sent_packet_manager_.one_rtt_packet_acked(); + const bool zero_rtt_packet_was_acked = + sent_packet_manager_.zero_rtt_packet_acked(); const AckResult ack_result = sent_packet_manager_.OnAckFrameEnd( idle_network_detector_.time_of_last_received_packet(), last_header_.packet_number, last_decrypted_packet_level_); @@ -1309,6 +1335,11 @@ bool QuicConnection::OnAckFrameEnd(QuicPacketNumber start) { sent_packet_manager_.one_rtt_packet_acked()) { visitor_->OnOneRttPacketAcknowledged(); } + if (debug_visitor_ != nullptr && version().UsesTls() && + !zero_rtt_packet_was_acked && + sent_packet_manager_.zero_rtt_packet_acked()) { + debug_visitor_->OnZeroRttPacketAcked(); + } // Cancel the send alarm because new packets likely have been acked, which // may change the congestion window and/or pacing rate. Canceling the alarm // causes CanWrite to recalculate the next send time. @@ -1451,23 +1482,49 @@ bool QuicConnection::OnStopSendingFrame(const QuicStopSendingFrame& frame) { QUIC_DLOG(INFO) << ENDPOINT << "STOP_SENDING frame received for stream: " << frame.stream_id - << " with error: " << frame.application_error_code; + << " with error: " << frame.ietf_error_code; visitor_->OnStopSendingFrame(frame); return connected_; } bool QuicConnection::OnPathChallengeFrame(const QuicPathChallengeFrame& frame) { + if (has_path_challenge_in_current_packet_) { + DCHECK(send_path_response_); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 2, 5); + // Only respond to the 1st PATH_CHALLENGE. + return true; + } UpdatePacketContent(PATH_CHALLENGE_FRAME); if (debug_visitor_ != nullptr) { debug_visitor_->OnPathChallengeFrame(frame); } - // Save the path challenge's payload, for later use in generating the - // response. - received_path_challenge_payloads_.push_back(frame.data_buffer); + if (!send_path_response_) { + // Save the path challenge's payload, for later use in generating the + // response. + received_path_challenge_payloads_.push_back(frame.data_buffer); + + MaybeUpdateAckTimeout(); + return true; + } + QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 3, 5); + has_path_challenge_in_current_packet_ = true; MaybeUpdateAckTimeout(); - return true; + // Queue or send PATH_RESPONSE. No matter where the pending data are supposed + // to sent, PATH_RESPONSE should always be sent to the source address of the + // current incoming packet. + if (!SendPathResponse(frame.data_buffer, last_packet_source_address_)) { + // Queue the payloads to re-try later. + pending_path_challenge_payloads_.push_back( + {frame.data_buffer, last_packet_source_address_}); + } + // TODO(b/150095588): change the stats to + // num_valid_path_challenge_received. + ++stats_.num_connectivity_probing_received; + + // SendPathResponse() might cause connection to be closed. + return connected_; } bool QuicConnection::OnPathResponseFrame(const QuicPathResponseFrame& frame) { @@ -1656,13 +1713,25 @@ bool QuicConnection::OnHandshakeDoneFrame(const QuicHandshakeDoneFrame& frame) { return connected_; } -bool QuicConnection::OnAckFrequencyFrame( - const QuicAckFrequencyFrame& /*frame*/) { +bool QuicConnection::OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame) { UpdatePacketContent(ACK_FREQUENCY_FRAME); - // TODO(b/148614353): implement this fully. - QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame."; - return false; + if (!can_receive_ack_frequency_frame_) { + QUIC_LOG_EVERY_N_SEC(ERROR, 120) << "Get unexpected AckFrequencyFrame."; + return false; + } + if (auto packet_number_space = + QuicUtils::GetPacketNumberSpace(last_decrypted_packet_level_) == + APPLICATION_DATA) { + uber_received_packet_manager_.OnAckFrequencyFrame(frame); + } else { + QUIC_LOG_EVERY_N_SEC(ERROR, 120) + << "Get AckFrequencyFrame in packet number space " + << packet_number_space; + } + MaybeUpdateAckTimeout(); + return true; } + bool QuicConnection::OnBlockedFrame(const QuicBlockedFrame& frame) { DCHECK(connected_); @@ -1716,7 +1785,6 @@ void QuicConnection::OnPacketComplete() { uber_received_packet_manager_.MaybeUpdateAckTimeout( should_last_packet_instigate_acks_, last_decrypted_packet_level_, last_header_.packet_number, - idle_network_detector_.time_of_last_received_packet(), clock_->ApproximateNow(), sent_packet_manager_.GetRttStats()); } @@ -1726,6 +1794,9 @@ void QuicConnection::OnPacketComplete() { void QuicConnection::MaybeRespondToConnectivityProbingOrMigration() { if (version().HasIetfQuicFrames()) { + if (send_path_response_) { + return; + } if (perspective_ == Perspective::IS_CLIENT) { // This node is a client, notify that a speculative connectivity probing // packet has been received anyway. @@ -1772,7 +1843,8 @@ void QuicConnection::MaybeRespondToConnectivityProbingOrMigration() { } // Server starts to migrate connection upon receiving of non-probing packet // from a new peer address. - if (last_header_.packet_number == GetLargestReceivedPacket()) { + if (!start_peer_migration_earlier_ && + last_header_.packet_number == GetLargestReceivedPacket()) { direct_peer_address_ = last_packet_source_address_; if (current_effective_peer_migration_type_ != NO_CHANGE) { // TODO(fayang): When multiple packet number spaces is supported, only @@ -1875,47 +1947,6 @@ void QuicConnection::MaybeSendInResponseToPacket() { } } -void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic, - bool has_length_prefix) { - pending_version_negotiation_packet_ = true; - send_ietf_version_negotiation_packet_ = ietf_quic; - send_version_negotiation_packet_with_prefixed_lengths_ = has_length_prefix; - - if (HandleWriteBlocked()) { - return; - } - - QUIC_DLOG(INFO) << ENDPOINT << "Sending version negotiation packet: {" - << ParsedQuicVersionVectorToString( - framer_.supported_versions()) - << "}, " << (ietf_quic ? "" : "!") << "ietf_quic"; - std::unique_ptr<QuicEncryptedPacket> version_packet( - packet_creator_.SerializeVersionNegotiationPacket( - ietf_quic, has_length_prefix, framer_.supported_versions())); - QUIC_DVLOG(2) << ENDPOINT << "Sending version negotiation packet: {" - << ParsedQuicVersionVectorToString(framer_.supported_versions()) - << "}, " << (ietf_quic ? "" : "!") << "ietf_quic:" << std::endl - << quiche::QuicheTextUtils::HexDump(quiche::QuicheStringPiece( - version_packet->data(), version_packet->length())); - WriteResult result = writer_->WritePacket( - version_packet->data(), version_packet->length(), self_address().host(), - peer_address(), per_packet_options_); - - if (IsWriteError(result.status)) { - OnWriteError(result.error_code); - return; - } - if (IsWriteBlockedStatus(result.status)) { - visitor_->OnWriteBlocked(); - if (result.status == WRITE_STATUS_BLOCKED_DATA_BUFFERED) { - pending_version_negotiation_packet_ = false; - } - return; - } - - pending_version_negotiation_packet_ = false; -} - void QuicConnection::MaybeActivateLegacyVersionEncapsulation() { if (!legacy_version_encapsulation_enabled_) { return; @@ -2143,10 +2174,6 @@ void QuicConnection::MaybeUpdatePacketCreatorMaxPacketLengthAndPadding() { max_packet_length -= minimum_overhead; } packet_creator_.SetMaxPacketLength(max_packet_length); - if (legacy_version_encapsulation_enabled_) { - packet_creator_.set_disable_padding_override( - legacy_version_encapsulation_in_progress_); - } } void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, @@ -2174,7 +2201,7 @@ void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, } if (!direct_peer_address_.IsInitialized()) { - direct_peer_address_ = last_packet_source_address_; + UpdatePeerAddress(last_packet_source_address_); } if (!effective_peer_address_.IsInitialized()) { @@ -2255,7 +2282,21 @@ void QuicConnection::OnCanWrite() { if (!connected_) { return; } - DCHECK(!writer_->IsWriteBlocked()); + if (GetQuicReloadableFlag( + quic_close_connection_in_on_can_write_with_blocked_writer)) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_close_connection_in_on_can_write_with_blocked_writer); + if (writer_->IsWriteBlocked()) { + const std::string error_details = + "Writer is blocked while calling OnCanWrite."; + QUIC_BUG << ENDPOINT << error_details; + CloseConnection(QUIC_INTERNAL_ERROR, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return; + } + } else { + DCHECK(!writer_->IsWriteBlocked()); + } // Add a flusher to ensure the connection is marked app-limited. ScopedPacketFlusher flusher(this); @@ -2274,6 +2315,17 @@ void QuicConnection::OnCanWrite() { } } + // TODO(danzh) PATH_RESPONSE is of more interest to the peer than ACK, + // evaluate if it's worth to send them before sending ACKs. + while (!pending_path_challenge_payloads_.empty()) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 4, 5); + std::pair<QuicPathFrameBuffer, QuicSocketAddress> pair = + pending_path_challenge_payloads_.front(); + if (!SendPathResponse(pair.first, pair.second)) { + break; + } + pending_path_challenge_payloads_.pop_front(); + } WriteNewData(); } @@ -2399,12 +2451,6 @@ bool QuicConnection::ValidateReceivedPacketNumber( void QuicConnection::WriteQueuedPackets() { DCHECK(!writer_->IsWriteBlocked()); - if (pending_version_negotiation_packet_) { - SendVersionNegotiationPacket( - send_ietf_version_negotiation_packet_, - send_version_negotiation_packet_with_prefixed_lengths_); - } - QUIC_CLIENT_HISTOGRAM_COUNTS("QuicSession.NumQueuedPacketsBeforeWrite", buffered_packets_.size(), 1, 1000, 50, ""); @@ -2453,16 +2499,17 @@ void QuicConnection::SendProbingRetransmissions() { } } -void QuicConnection::MarkZeroRttPacketsForRetransmission() { +void QuicConnection::MarkZeroRttPacketsForRetransmission(int reject_reason) { + sent_packet_manager_.MarkZeroRttPacketsForRetransmission(); if (debug_visitor_ != nullptr && version().UsesTls()) { - debug_visitor_->OnZeroRttRejected(); + debug_visitor_->OnZeroRttRejected(reject_reason); } - sent_packet_manager_.MarkZeroRttPacketsForRetransmission(); } void QuicConnection::NeuterUnencryptedPackets() { sent_packet_manager_.NeuterUnencryptedPackets(); - if (GetQuicReloadableFlag( + if (!fix_missing_initial_keys_ && + GetQuicReloadableFlag( quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded) && version().CanSendCoalescedPackets()) { QUIC_RELOADABLE_FLAG_COUNT( @@ -2603,11 +2650,6 @@ QuicTime QuicConnection::CalculatePacketSentTime() { } bool QuicConnection::WritePacket(SerializedPacket* packet) { - if (!packet_creator_.determine_serialized_packet_fate_early() && - ShouldDiscardPacket(packet->encryption_level)) { - ++stats_.packets_discarded; - return true; - } if (sent_packet_manager_.GetLargestSentPacket().IsInitialized() && packet->packet_number < sent_packet_manager_.GetLargestSentPacket()) { QUIC_BUG << "Attempt to write packet:" << packet->packet_number @@ -2618,10 +2660,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { } const bool is_mtu_discovery = QuicUtils::ContainsFrameType( packet->nonretransmittable_frames, MTU_DISCOVERY_FRAME); - const SerializedPacketFate fate = - packet_creator_.determine_serialized_packet_fate_early() - ? packet->fate - : GetSerializedPacketFate(is_mtu_discovery, packet->encryption_level); + const SerializedPacketFate fate = packet->fate; // Termination packets are encrypted and saved, so don't exit early. QuicErrorCode error_code = QUIC_NO_ERROR; const bool is_termination_packet = IsTerminationPacket(*packet, &error_code); @@ -2675,15 +2714,17 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // during the WritePacket below. QuicTime packet_send_time = CalculatePacketSentTime(); WriteResult result(WRITE_STATUS_OK, encrypted_length); + QuicSocketAddress send_to_address = + (send_path_response_) ? packet->peer_address : peer_address(); switch (fate) { case DISCARD: - DCHECK(packet_creator_.determine_serialized_packet_fate_early()); ++stats_.packets_discarded; return true; case COALESCE: QUIC_BUG_IF(!version().CanSendCoalescedPackets()); + QUIC_BUG_IF(fix_out_of_order_sending_ && coalescing_done_); if (!coalesced_packet_.MaybeCoalescePacket( - *packet, self_address(), peer_address(), + *packet, self_address(), send_to_address, helper_->GetStreamSendBufferAllocator(), packet_creator_.max_packet_length())) { // Failed to coalesce packet, flush current coalesced packet. @@ -2691,8 +2732,21 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // Failed to flush coalesced packet, write error has been handled. return false; } + if (!fix_missing_initial_keys_ && + GetQuicReloadableFlag( + quic_discard_initial_packet_with_key_dropped)) { + QUIC_RELOADABLE_FLAG_COUNT( + quic_discard_initial_packet_with_key_dropped); + if (packet->encryption_level == ENCRYPTION_INITIAL && + !framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) { + // Discard initial packet since flush of coalesce packet could + // cause initial keys to be dropped. + ++stats_.packets_discarded; + return true; + } + } if (!coalesced_packet_.MaybeCoalescePacket( - *packet, self_address(), peer_address(), + *packet, self_address(), send_to_address, helper_->GetStreamSendBufferAllocator(), packet_creator_.max_packet_length())) { // Failed to coalesce packet even it is the only packet, raise a write @@ -2713,9 +2767,13 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { case BUFFER: QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number << " to buffered packets"; - buffered_packets_.emplace_back(*packet, self_address(), peer_address()); + buffered_packets_.emplace_back(*packet, self_address(), send_to_address); break; case SEND_TO_WRITER: + if (fix_out_of_order_sending_ && !coalescing_done_) { + // Stop using coalsecer from now on. + coalescing_done_ = true; + } // At this point, packet->release_encrypted_buffer is either nullptr, // meaning |packet->encrypted_buffer| is a stack buffer, or not-nullptr, /// meaning it's a writer-allocated buffer. Note that connectivity probing @@ -2725,7 +2783,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { // writer_->WritePacket transfers buffer ownership back to the writer. packet->release_encrypted_buffer = nullptr; result = writer_->WritePacket(packet->encrypted_buffer, encrypted_length, - self_address().host(), peer_address(), + self_address().host(), send_to_address, per_packet_options_); // This is a work around for an issue with linux UDP GSO batch writers. // When sending a GSO packet with 2 segments, if the first segment is @@ -2738,11 +2796,6 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { result = writer_->Flush(); } break; - case FAILED_TO_WRITE_COALESCED_PACKET: - // Failed to send existing coalesced packet when determining packet fate, - // write error has been handled. - QUIC_BUG_IF(!version().CanSendCoalescedPackets()); - return false; case LEGACY_VERSION_ENCAPSULATE: { DCHECK(!is_mtu_discovery); DCHECK_EQ(perspective_, Perspective::IS_CLIENT); @@ -2776,13 +2829,14 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { } if (!buffered_packets_.empty() || HandleWriteBlocked()) { // Buffer the packet. - buffered_packets_.emplace_back(*packet, self_address(), peer_address()); + buffered_packets_.emplace_back(*packet, self_address(), + send_to_address); } else { // Send the packet to the writer. // writer_->WritePacket transfers buffer ownership back to the writer. packet->release_encrypted_buffer = nullptr; result = writer_->WritePacket(packet->encrypted_buffer, encrypted_length, self_address().host(), - peer_address(), per_packet_options_); + send_to_address, per_packet_options_); } } break; default: @@ -2807,7 +2861,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) { QUIC_DVLOG(1) << ENDPOINT << "Adding packet: " << packet->packet_number << " to buffered packets"; - buffered_packets_.emplace_back(*packet, self_address(), peer_address()); + buffered_packets_.emplace_back(*packet, self_address(), send_to_address); } } @@ -2830,7 +2884,7 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { QUIC_LOG_FIRST_N(ERROR, 10) << ENDPOINT << "Failed writing packet " << packet_number << " of " << encrypted_length << " bytes from " << self_address().host() << " to " - << peer_address() << ", with error code " << result.error_code + << send_to_address << ", with error code " << result.error_code << ". long_term_mtu_:" << long_term_mtu_ << ", previous_validated_mtu_:" << previous_validated_mtu_ << ", max_packet_length():" << max_packet_length() @@ -2849,7 +2903,8 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { packet_send_time = packet_send_time + result.send_time_offset; } - if (debug_visitor_ != nullptr) { + if (!sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() && + debug_visitor_ != nullptr) { // Pass the write result to the visitor. debug_visitor_->OnPacketSent(*packet, packet->transmission_type, packet_send_time); @@ -2882,15 +2937,42 @@ bool QuicConnection::WritePacket(SerializedPacket* packet) { bytes_sent_before_address_validation_ += encrypted_length; } + // Do not measure rtt of this packet if it's not sent on current path. + const bool measure_rtt = send_to_address == peer_address(); + QUIC_DLOG_IF(INFO, !measure_rtt) + << ENDPOINT << " Sent packet " << packet->packet_number + << " on a different path with remote address " << send_to_address + << " while current path has peer address " << peer_address(); const bool in_flight = sent_packet_manager_.OnPacketSent( packet, packet_send_time, packet->transmission_type, - IsRetransmittable(*packet)); + IsRetransmittable(*packet), measure_rtt); QUIC_BUG_IF(default_enable_5rto_blackhole_detection_ && blackhole_detector_.IsDetectionInProgress() && !sent_packet_manager_.HasInFlightPackets()) << ENDPOINT << "Trying to start blackhole detection without no bytes in flight"; + if (sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() && + debug_visitor_ != nullptr) { + QUIC_RELOADABLE_FLAG_COUNT_N( + quic_give_sent_packet_to_debug_visitor_after_sent, 1, 2); + if (sent_packet_manager_.unacked_packets().empty()) { + QUIC_BUG << "Unacked map is empty right after packet is sent"; + } else { + debug_visitor_->OnPacketSent( + packet->packet_number, packet->encrypted_length, + packet->has_crypto_handshake, packet->transmission_type, + packet->encryption_level, + sent_packet_manager_.unacked_packets() + .rbegin() + ->retransmittable_frames, + packet->nonretransmittable_frames, packet_send_time); + } + } + if (packet->encryption_level == ENCRYPTION_HANDSHAKE) { + handshake_packet_sent_ = true; + } + if (in_flight || !retransmission_alarm_->IsSet()) { SetRetransmissionAlarm(); } @@ -2971,9 +3053,6 @@ bool QuicConnection::ShouldDiscardPacket(EncryptionLevel encryption_level) { } QuicTime QuicConnection::GetPathMtuReductionDeadline() const { - if (!blackhole_detector_.revert_mtu_after_two_ptos()) { - return QuicTime::Zero(); - } if (previous_validated_mtu_ == 0) { return QuicTime::Zero(); } @@ -3026,7 +3105,14 @@ void QuicConnection::OnWriteError(int error_code) { } QuicPacketBuffer QuicConnection::GetPacketBuffer() { - if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) { + if (fix_out_of_order_sending_) { + if (version().CanSendCoalescedPackets() && !coalescing_done_) { + // Do not use writer's packet buffer for coalesced packets which may + // contain + // multiple QUIC packets. + return {nullptr, nullptr}; + } + } else if (version().CanSendCoalescedPackets() && !IsHandshakeConfirmed()) { // Do not use writer's packet buffer for coalesced packets which may contain // multiple QUIC packets. return {nullptr, nullptr}; @@ -3131,10 +3217,7 @@ void QuicConnection::SendOrQueuePacket(SerializedPacket packet) { } void QuicConnection::OnPingTimeout() { - if (retransmission_alarm_->IsSet()) { - return; - } - if (GetQuicReloadableFlag(quic_fix_on_ping_timeout) && + if (retransmission_alarm_->IsSet() || !visitor_->ShouldKeepConnectionAlive()) { return; } @@ -3175,6 +3258,9 @@ void QuicConnection::OnRetransmissionTimeout() { DCHECK(!IsHandshakeComplete()); } #endif + if (fix_missing_connected_checks_ && !connected_) { + return; + } QuicPacketNumber previous_created_packet_number = packet_creator_.packet_number(); @@ -3288,11 +3374,9 @@ void QuicConnection::SetDefaultEncryptionLevel(EncryptionLevel level) { } encryption_level_ = level; packet_creator_.set_encryption_level(level); - - if (!sent_packet_manager_.fix_packet_number_length()) { - return; - } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_packet_number_length, 2, 2); + QUIC_BUG_IF(!framer_.HasEncrypterOfEncryptionLevel(level)) + << ENDPOINT << "Trying to set encryption level to " + << EncryptionLevelToString(level) << " while the key is missing"; if (!changing_level) { return; @@ -3369,6 +3453,11 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { encryption_level_ == ENCRYPTION_INITIAL) { return; } + const bool fix_undecryptable_packets = + GetQuicReloadableFlag(quic_fix_undecryptable_packets2); + if (fix_undecryptable_packets) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_undecryptable_packets2); + } auto iter = undecryptable_packets_.begin(); while (connected_ && iter != undecryptable_packets_.end()) { @@ -3379,9 +3468,11 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { return; } UndecryptablePacket* undecryptable_packet = &*iter; - ++iter; - if (undecryptable_packet->processed) { - continue; + if (!fix_undecryptable_packets) { + ++iter; + if (undecryptable_packet->processed) { + continue; + } } QUIC_DVLOG(1) << ENDPOINT << "Attempting to process undecryptable packet"; if (debug_visitor_ != nullptr) { @@ -3390,7 +3481,11 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { } if (framer_.ProcessPacket(*undecryptable_packet->packet)) { QUIC_DVLOG(1) << ENDPOINT << "Processed undecryptable packet!"; - undecryptable_packet->processed = true; + if (fix_undecryptable_packets) { + iter = undecryptable_packets_.erase(iter); + } else { + undecryptable_packet->processed = true; + } ++stats_.packets_processed; continue; } @@ -3403,14 +3498,21 @@ void QuicConnection::MaybeProcessUndecryptablePackets() { QUIC_DVLOG(1) << ENDPOINT << "Need to attempt to process this undecryptable packet later"; + if (fix_undecryptable_packets) { + ++iter; + } continue; } - undecryptable_packet->processed = true; + if (fix_undecryptable_packets) { + iter = undecryptable_packets_.erase(iter); + } else { + undecryptable_packet->processed = true; + } } // Remove processed packets. We cannot remove elements in the while loop // above because currently QuicCircularDeque does not support removing // mid elements. - while (!undecryptable_packets_.empty()) { + while (!fix_undecryptable_packets && !undecryptable_packets_.empty()) { if (!undecryptable_packets_.front().processed) { break; } @@ -3489,6 +3591,9 @@ void QuicConnection::CloseConnection( void QuicConnection::SendConnectionClosePacket(QuicErrorCode error, const std::string& details) { + // Always use the current path to send CONNECTION_CLOSE. + QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_, + peer_address()); if (!SupportsMultiplePacketNumberSpaces()) { QUIC_DLOG(INFO) << ENDPOINT << "Sending connection close packet."; SetDefaultEncryptionLevel(GetConnectionCloseEncryptionLevel()); @@ -3617,8 +3722,7 @@ void QuicConnection::SetMaxPacketLength(QuicByteCount length) { } bool QuicConnection::HasQueuedData() const { - return pending_version_negotiation_packet_ || - packet_creator_.HasPendingFrames() || !buffered_packets_.empty(); + return packet_creator_.HasPendingFrames() || !buffered_packets_.empty(); } void QuicConnection::SetNetworkTimeouts(QuicTime::Delta handshake_timeout, @@ -3692,6 +3796,13 @@ void QuicConnection::SetPingAlarm() { } void QuicConnection::SetRetransmissionAlarm() { + if (fix_missing_connected_checks_ && !connected_) { + if (retransmission_alarm_->IsSet()) { + QUIC_BUG << ENDPOINT << "Retransmission alarm is set while disconnected"; + retransmission_alarm_->Cancel(); + } + return; + } if (packet_creator_.PacketFlusherAttached()) { pending_retransmission_alarm_ = true; return; @@ -3718,7 +3829,9 @@ void QuicConnection::MaybeSetMtuAlarm(QuicPacketNumber sent_packet_number) { QuicConnection::ScopedPacketFlusher::ScopedPacketFlusher( QuicConnection* connection) : connection_(connection), - flush_and_set_pending_retransmission_alarm_on_delete_(false) { + flush_and_set_pending_retransmission_alarm_on_delete_(false), + handshake_packet_sent_(connection != nullptr && + connection->handshake_packet_sent_) { if (connection_ == nullptr) { return; } @@ -3767,13 +3880,17 @@ QuicConnection::ScopedPacketFlusher::~ScopedPacketFlusher() { } connection_->packet_creator_.Flush(); if (connection_->version().CanSendCoalescedPackets()) { - if (connection_->packet_creator().coalesced_packet_of_higher_space()) { - QUIC_RELOADABLE_FLAG_COUNT(quic_coalesced_packet_of_higher_space2); - connection_->MaybeCoalescePacketOfHigherSpace(); - } + connection_->MaybeCoalescePacketOfHigherSpace(); connection_->FlushCoalescedPacket(); } connection_->FlushPackets(); + if (connection_->fix_missing_initial_keys_ && !handshake_packet_sent_ && + connection_->handshake_packet_sent_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_missing_initial_keys2, 1, 2); + // This would cause INITIAL key to be dropped. Drop keys here to avoid + // missing the write keys in the middle of writing. + connection_->visitor_->OnHandshakePacketSent(); + } // Reset transmission type. connection_->SetTransmissionType(NOT_RETRANSMISSION); @@ -3944,6 +4061,7 @@ bool QuicConnection::SendGenericPathProbePacket( // request or a response. probing_packet = packet_creator_.SerializeConnectivityProbingPacket(); } else if (is_response) { + DCHECK(!send_path_response_); // IETF QUIC path response. // Respond to path probe request using IETF QUIC PATH_RESPONSE frame. probing_packet = @@ -3991,15 +4109,34 @@ bool QuicConnection::SendGenericPathProbePacket( return false; } - if (debug_visitor_ != nullptr) { + if (!sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() && + debug_visitor_ != nullptr) { debug_visitor_->OnPacketSent( *probing_packet, probing_packet->transmission_type, packet_send_time); } - // Call OnPacketSent regardless of the write result. - sent_packet_manager_.OnPacketSent(probing_packet.get(), packet_send_time, - probing_packet->transmission_type, - NO_RETRANSMITTABLE_DATA); + // Send in currrent path. Call OnPacketSent regardless of the write result. + sent_packet_manager_.OnPacketSent( + probing_packet.get(), packet_send_time, probing_packet->transmission_type, + NO_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + + if (sent_packet_manager_.give_sent_packet_to_debug_visitor_after_sent() && + debug_visitor_ != nullptr) { + QUIC_RELOADABLE_FLAG_COUNT_N( + quic_give_sent_packet_to_debug_visitor_after_sent, 2, 2); + if (sent_packet_manager_.unacked_packets().empty()) { + QUIC_BUG << "Unacked map is empty right after packet is sent"; + } else { + debug_visitor_->OnPacketSent( + probing_packet->packet_number, probing_packet->encrypted_length, + probing_packet->has_crypto_handshake, + probing_packet->transmission_type, probing_packet->encryption_level, + sent_packet_manager_.unacked_packets() + .rbegin() + ->retransmittable_frames, + probing_packet->nonretransmittable_frames, packet_send_time); + } + } if (IsWriteBlockedStatus(result.status)) { if (probing_writer == writer_) { @@ -4066,6 +4203,13 @@ void QuicConnection::StartEffectivePeerMigration(AddressChangeType type) { } void QuicConnection::OnConnectionMigration(AddressChangeType addr_change_type) { + if (debug_visitor_ != nullptr) { + const QuicTime now = clock_->ApproximateNow(); + if (now >= stats_.handshake_completion_time) { + debug_visitor_->OnPeerAddressChange( + addr_change_type, now - stats_.handshake_completion_time); + } + } visitor_->OnConnectionMigration(addr_change_type); sent_packet_manager_.OnConnectionMigration(addr_change_type); } @@ -4130,7 +4274,8 @@ void QuicConnection::MaybeSendProbingRetransmissions() { } void QuicConnection::CheckIfApplicationLimited() { - if (probing_retransmission_pending_) { + if ((fix_missing_connected_checks_ && !connected_) || + probing_retransmission_pending_) { return; } @@ -4152,14 +4297,14 @@ void QuicConnection::CheckIfApplicationLimited() { } void QuicConnection::UpdatePacketContent(QuicFrameType type) { + if (version().HasIetfQuicFrames()) { + MaybeStartIetfPeerMigration(type); + return; + } // Packet content is tracked to identify connectivity probe in non-IETF // version, where a connectivity probe is defined as // - a padded PING packet with peer address change received by server, // - a padded PING packet on new path received by client. - if (version().HasIetfQuicFrames()) { - // TODO(b/149315151) detect IETF non-probing packet. - return; - } if (current_packet_content_ == NOT_PADDED_PING) { // We have already learned the current packet is not a connectivity @@ -4207,10 +4352,28 @@ void QuicConnection::UpdatePacketContent(QuicFrameType type) { current_packet_content_ = NOT_PADDED_PING; if (GetLargestReceivedPacket().IsInitialized() && last_header_.packet_number == GetLargestReceivedPacket()) { - direct_peer_address_ = last_packet_source_address_; + UpdatePeerAddress(last_packet_source_address_); if (current_effective_peer_migration_type_ != NO_CHANGE) { // Start effective peer migration immediately when the current packet is // confirmed not a connectivity probing packet. + StartEffectivePeerMigration(current_effective_peer_migration_type_); + } + } + current_effective_peer_migration_type_ = NO_CHANGE; +} + +void QuicConnection::MaybeStartIetfPeerMigration(QuicFrameType type) { + DCHECK(version().HasIetfQuicFrames()); + if (!start_peer_migration_earlier_ || QuicUtils::IsProbingFrame(type)) { + return; + } + QUIC_CODE_COUNT(quic_start_peer_migration_earlier); + if (GetLargestReceivedPacket().IsInitialized() && + last_header_.packet_number == GetLargestReceivedPacket()) { + UpdatePeerAddress(last_packet_source_address_); + if (current_effective_peer_migration_type_ != NO_CHANGE) { + // Start effective peer migration when the current packet contains a + // non-probing frame. // TODO(fayang): When multiple packet number spaces is supported, only // start peer migration for the application data. StartEffectivePeerMigration(current_effective_peer_migration_type_); @@ -4345,23 +4508,15 @@ EncryptionLevel QuicConnection::GetConnectionCloseEncryptionLevel() const { void QuicConnection::MaybeBundleCryptoDataWithAcks() { DCHECK(SupportsMultiplePacketNumberSpaces()); - if (GetQuicReloadableFlag(quic_retransmit_handshake_data_early) && - IsHandshakeConfirmed()) { + if (IsHandshakeConfirmed()) { return; } PacketNumberSpace space = HANDSHAKE_DATA; - if (perspective() == Perspective::IS_SERVER) { - // On the server side, sends INITIAL data with INITIAL ACK. On the client - // side, sends HANDSHAKE data (containing client Finished) with HANDSHAKE - // ACK. + if (perspective() == Perspective::IS_SERVER && + framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) { + // On the server side, sends INITIAL data with INITIAL ACK if initial key is + // available. space = INITIAL_DATA; - if (GetQuicReloadableFlag(quic_retransmit_handshake_data_early)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_retransmit_handshake_data_early); - if (!framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) { - // Retransmit HANDSHAKE data early. - space = HANDSHAKE_DATA; - } - } } const QuicTime ack_timeout = uber_received_packet_manager_.GetAckTimeout(space); @@ -4377,6 +4532,16 @@ void QuicConnection::MaybeBundleCryptoDataWithAcks() { return; } + if (check_keys_before_writing_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_keys_before_writing, 1, 2); + if (!framer_.HasAnEncrypterForSpace(space)) { + QUIC_BUG << ENDPOINT + << "Try to bundle crypto with ACK with missing key of space " + << PacketNumberSpaceToString(space); + return; + } + } + sent_packet_manager_.RetransmitDataOfSpaceIfAny(space); } @@ -4400,6 +4565,13 @@ void QuicConnection::SendAllPendingAcks() { if (!ack_timeout.IsInitialized()) { continue; } + if (check_keys_before_writing_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_check_keys_before_writing, 2, 2); + if (!framer_.HasAnEncrypterForSpace(static_cast<PacketNumberSpace>(i))) { + // The key has been dropped. + continue; + } + } if (ack_timeout > clock_->ApproximateNow() && ack_timeout > earliest_ack_timeout) { // Always send the earliest ACK to make forward progress in case alarm @@ -4500,10 +4672,25 @@ void QuicConnection::MaybeCoalescePacketOfHigherSpace() { bool QuicConnection::FlushCoalescedPacket() { ScopedCoalescedPacketClearer clearer(&coalesced_packet_); + if (fix_missing_connected_checks_ && !connected_) { + return false; + } if (!version().CanSendCoalescedPackets()) { QUIC_BUG_IF(coalesced_packet_.length() > 0); return true; } + if (fix_missing_initial_keys_) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_missing_initial_keys2, 2, 2); + if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_INITIAL) && + !framer_.HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL)) { + // Initial packet will be re-serialized. Neuter it in case initial key has + // been dropped. + QUIC_BUG << ENDPOINT + << "Coalescer contains initial packet while initial key has " + "been dropped."; + coalesced_packet_.NeuterInitialPacket(); + } + } if (coalesced_packet_.length() == 0) { return true; } @@ -4520,13 +4707,14 @@ bool QuicConnection::FlushCoalescedPacket() { if (!buffered_packets_.empty() || HandleWriteBlocked()) { QUIC_DVLOG(1) << ENDPOINT << "Buffering coalesced packet of len: " << length; - buffered_packets_.emplace_back(buffer, length, - coalesced_packet_.self_address(), - coalesced_packet_.peer_address()); + buffered_packets_.emplace_back( + buffer, static_cast<QuicPacketLength>(length), + coalesced_packet_.self_address(), coalesced_packet_.peer_address()); if (debug_visitor_ != nullptr) { debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length); } - if (coalesced_packet_.ContainsPacketOfEncryptionLevel( + if (!fix_missing_initial_keys_ && + coalesced_packet_.ContainsPacketOfEncryptionLevel( ENCRYPTION_HANDSHAKE)) { // This is only called in coalescer because all ENCRYPTION_HANDSHAKE // packets go through the coalescer. @@ -4547,15 +4735,16 @@ bool QuicConnection::FlushCoalescedPacket() { if (result.status != WRITE_STATUS_BLOCKED_DATA_BUFFERED) { QUIC_DVLOG(1) << ENDPOINT << "Buffering coalesced packet of len: " << length; - buffered_packets_.emplace_back(buffer, length, - coalesced_packet_.self_address(), - coalesced_packet_.peer_address()); + buffered_packets_.emplace_back( + buffer, static_cast<QuicPacketLength>(length), + coalesced_packet_.self_address(), coalesced_packet_.peer_address()); } } if (debug_visitor_ != nullptr) { debug_visitor_->OnCoalescedPacketSent(coalesced_packet_, length); } - if (coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_HANDSHAKE)) { + if (!fix_missing_initial_keys_ && + coalesced_packet_.ContainsPacketOfEncryptionLevel(ENCRYPTION_HANDSHAKE)) { // This is only called in coalescer because all ENCRYPTION_HANDSHAKE // packets go through the coalescer. visitor_->OnHandshakePacketSent(); @@ -4651,34 +4840,34 @@ bool QuicConnection::EnforceAntiAmplificationLimit() const { bool QuicConnection::LimitedByAmplificationFactor() const { return EnforceAntiAmplificationLimit() && bytes_sent_before_address_validation_ >= - GetQuicFlag(FLAGS_quic_anti_amplification_factor) * + anti_amplification_factor_ * bytes_received_before_address_validation_; } SerializedPacketFate QuicConnection::GetSerializedPacketFate( bool is_mtu_discovery, EncryptionLevel encryption_level) { - if (packet_creator_.determine_serialized_packet_fate_early()) { - if (ShouldDiscardPacket(encryption_level)) { - return DISCARD; - } + if (ShouldDiscardPacket(encryption_level)) { + return DISCARD; } if (legacy_version_encapsulation_in_progress_) { DCHECK(!is_mtu_discovery); return LEGACY_VERSION_ENCAPSULATE; } - if (version().CanSendCoalescedPackets()) { - // Disable coalescing when Legacy Version Encapsulation is in use to avoid - // having to reframe encapsulated packets. - if (!IsHandshakeConfirmed() && !is_mtu_discovery) { + if (version().CanSendCoalescedPackets() && !coalescing_done_ && + !is_mtu_discovery) { + if (!IsHandshakeConfirmed()) { // Before receiving ACK for any 1-RTT packets, always try to coalesce // packet (except MTU discovery packet). return COALESCE; } - // Packet cannot be coalesced, flush existing coalesced packet. - if (!packet_creator_.determine_serialized_packet_fate_early() && - !FlushCoalescedPacket()) { - return FAILED_TO_WRITE_COALESCED_PACKET; + if (fix_out_of_order_sending_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_out_of_order_sending2); + if (coalesced_packet_.length() > 0) { + // If the coalescer is not empty, let this packet go through coalescer + // to avoid potential out of order sending. + return COALESCE; + } } } if (!buffered_packets_.empty() || HandleWriteBlocked()) { @@ -4705,11 +4894,6 @@ void QuicConnection::set_min_received_before_ack_decimation(size_t new_value) { new_value); } -void QuicConnection::set_ack_frequency(size_t new_value) { - DCHECK_GT(new_value, 0u); - uber_received_packet_manager_.set_ack_frequency(new_value); -} - const QuicAckFrame& QuicConnection::ack_frame() const { if (SupportsMultiplePacketNumberSpaces()) { return uber_received_packet_manager_.GetAckFrame( @@ -4755,12 +4939,7 @@ void QuicConnection::OnBlackholeDetected() { } void QuicConnection::OnPathMtuReductionDetected() { - DCHECK(blackhole_detector_.revert_mtu_after_two_ptos()); - if (MaybeRevertToPreviousMtu()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_revert_mtu_after_two_ptos, 1, 2); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_revert_mtu_after_two_ptos, 2, 2); - } + MaybeRevertToPreviousMtu(); } void QuicConnection::OnHandshakeTimeout() { @@ -4783,15 +4962,23 @@ void QuicConnection::OnIdleNetworkDetected() { const QuicTime::Delta duration = clock_->ApproximateNow() - idle_network_detector_.last_network_activity_time(); - const std::string error_details = quiche::QuicheStrCat( + std::string error_details = quiche::QuicheStrCat( "No recent network activity after ", duration.ToDebuggingValue(), ". Timeout:", idle_network_detector_.idle_network_timeout().ToDebuggingValue()); QUIC_DVLOG(1) << ENDPOINT << error_details; - if ((sent_packet_manager_.GetConsecutiveTlpCount() > 0 || - sent_packet_manager_.GetConsecutiveRtoCount() > 0 || - sent_packet_manager_.GetConsecutivePtoCount() > 0 || - visitor_->ShouldKeepConnectionAlive())) { + const bool has_consecutive_pto = + sent_packet_manager_.GetConsecutiveTlpCount() > 0 || + sent_packet_manager_.GetConsecutiveRtoCount() > 0 || + sent_packet_manager_.GetConsecutivePtoCount() > 0; + if (has_consecutive_pto || visitor_->ShouldKeepConnectionAlive()) { + if (GetQuicReloadableFlag(quic_add_stream_info_to_idle_close_detail) && + !has_consecutive_pto) { + // Include stream information in error detail if there are open streams. + QUIC_RELOADABLE_FLAG_COUNT(quic_add_stream_info_to_idle_close_detail); + error_details = quiche::QuicheStrCat( + error_details, ", ", visitor_->GetStreamsInfoForLogging()); + } CloseConnection(QUIC_NETWORK_IDLE_TIMEOUT, error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); return; @@ -4814,7 +5001,6 @@ void QuicConnection::MaybeUpdateAckTimeout() { uber_received_packet_manager_.MaybeUpdateAckTimeout( /*should_last_packet_instigate_acks=*/true, last_decrypted_packet_level_, last_header_.packet_number, - idle_network_detector_.time_of_last_received_packet(), clock_->ApproximateNow(), sent_packet_manager_.GetRttStats()); } @@ -4864,5 +5050,21 @@ bool QuicConnection::ShouldDetectBlackhole() const { return num_rtos_for_blackhole_detection_ > 0; } +bool QuicConnection::SendPathResponse(const QuicPathFrameBuffer& data_buffer, + QuicSocketAddress peer_address_to_send) { + // Send PATH_RESPONSE using the provided peer address. If the creator has been + // using a different peer address, it will flush before and after serializing + // the current PATH_RESPONSE. + QUIC_DVLOG(1) << ENDPOINT << "Send PATH_RESPONSE to " << peer_address_to_send; + QuicPacketCreator::ScopedPeerAddressContext context(&packet_creator_, + peer_address_to_send); + return packet_creator_.AddPathResponseFrame(data_buffer); +} + +void QuicConnection::UpdatePeerAddress(QuicSocketAddress peer_address) { + direct_peer_address_ = peer_address; + packet_creator_.SetDefaultPeerAddress(peer_address); +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h index ba04b9f740c..9b4544ff7b4 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection.h @@ -170,6 +170,9 @@ class QUIC_EXPORT_PRIVATE QuicConnectionVisitorInterface { // transactions expecting a response. virtual bool ShouldKeepConnectionAlive() const = 0; + // Called to retrieve streams information for logging purpose. + virtual std::string GetStreamsInfoForLogging() const = 0; + // Called when a self address change is observed. Returns true if self address // change is allowed. virtual bool AllowSelfAddressChange() const = 0; @@ -199,10 +202,21 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor ~QuicConnectionDebugVisitor() override {} // Called when a packet has been sent. + // TODO(wub): Delete when deprecating + // --quic_give_sent_packet_to_debug_visitor_after_sent. virtual void OnPacketSent(const SerializedPacket& /*serialized_packet*/, TransmissionType /*transmission_type*/, QuicTime /*sent_time*/) {} + virtual void OnPacketSent(QuicPacketNumber /*packet_number*/, + QuicPacketLength /*packet_length*/, + bool /*has_crypto_handshake*/, + TransmissionType /*transmission_type*/, + EncryptionLevel /*encryption_level*/, + const QuicFrames& /*retransmittable_frames*/, + const QuicFrames& /*nonretransmittable_frames*/, + QuicTime /*sent_time*/) {} + // Called when a coalesced packet has been sent. virtual void OnCoalescedPacketSent( const QuicCoalescedPacket& /*coalesced_packet*/, @@ -361,7 +375,14 @@ class QUIC_EXPORT_PRIVATE QuicConnectionDebugVisitor const TransportParameters& /*transport_parameters*/) {} // Called for QUIC+TLS versions when 0-RTT is rejected. - virtual void OnZeroRttRejected() {} + virtual void OnZeroRttRejected(int /*reject_reason*/) {} + + // Called for QUIC+TLS versions when 0-RTT packet gets acked. + virtual void OnZeroRttPacketAcked() {} + + // Called on peer address change. + virtual void OnPeerAddressChange(AddressChangeType /*type*/, + QuicTime::Delta /*connection_time*/) {} }; class QUIC_EXPORT_PRIVATE QuicConnectionHelperInterface { @@ -716,8 +737,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Mark all sent 0-RTT encrypted packets for retransmission. Called when new // 0-RTT or 1-RTT key is available in gQUIC, or when 0-RTT is rejected in IETF - // QUIC. - void MarkZeroRttPacketsForRetransmission(); + // QUIC. |reject_reason| is used in TLS-QUIC to log why 0-RTT was rejected. + void MarkZeroRttPacketsForRetransmission(int reject_reason); // Calls |sent_packet_manager_|'s NeuterUnencryptedPackets. Used when the // connection becomes forward secure and hasn't received acks for all packets. @@ -800,6 +821,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // If true, when this flusher goes out of scope, flush connection and set // retransmission alarm if there is one pending. bool flush_and_set_pending_retransmission_alarm_on_delete_; + // Latched connection's handshake_packet_sent_ on creation of this flusher. + const bool handshake_packet_sent_; }; QuicPacketWriter* writer() { return writer_; } @@ -823,6 +846,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Sends response to a connectivity probe. Sends either a Padded Ping // or an IETF PATH_RESPONSE based on the version of the connection. // Is the counterpart to SendConnectivityProbingPacket(). + // TODO(danzh): remove this method after deprecating + // --gfe2_reloadable_flag_quic_send_path_response. virtual void SendConnectivityProbingResponsePacket( const QuicSocketAddress& peer_address); @@ -909,8 +934,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection size_t min_received_before_ack_decimation() const; void set_min_received_before_ack_decimation(size_t new_value); - void set_ack_frequency(size_t new_value); - // If |defer| is true, configures the connection to defer sending packets in // response to an ACK to the SendAlarm. If |defer| is false, packets may be // sent immediately after receiving an ACK. @@ -1007,11 +1030,23 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Can only be set if this is a client connection. void EnableLegacyVersionEncapsulation(const std::string& server_name); + bool send_path_response() const { return send_path_response_; } + // If now is close to idle timeout, returns true and sends a connectivity // probing packet to test the connection for liveness. Otherwise, returns // false. bool MaybeTestLiveness(); + bool can_receive_ack_frequency_frame() const { + return can_receive_ack_frequency_frame_; + } + + void set_can_receive_ack_frequency_frame() { + can_receive_ack_frequency_frame_ = true; + } + + bool check_keys_before_writing() const { return check_keys_before_writing_; } + protected: // Calls cancel() on all the alarms owned by this connection. void CancelAllAlarms(); @@ -1131,6 +1166,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // This gets set to true if 1) connection sucessfully processed the packet // or 2) connection failed to process the packet and will not try to process // it later. + // TODO(fayang): Remove this when deprecating + // quic_fix_undecryptable_packets2. bool processed; }; @@ -1247,9 +1284,9 @@ class QUIC_EXPORT_PRIVATE QuicConnection void UpdateReleaseTimeIntoFuture(); // Sends generic path probe packet to the peer. If we are not IETF QUIC, will - // always send a padded ping, regardless of whether this is a request or - // response. If version 99/ietf quic, will send a PATH_RESPONSE if - // |is_response| is true, a PATH_CHALLENGE if not. + // always send a padded ping, regardless of whether this is a request or not. + // TODO(danzh): remove |is_response| after deprecating + // --gfe2_reloadable_flag_quic_send_path_response. bool SendGenericPathProbePacket(QuicPacketWriter* probing_writer, const QuicSocketAddress& peer_address, bool is_response); @@ -1368,6 +1405,17 @@ class QUIC_EXPORT_PRIVATE QuicConnection // deprecated. void MaybeRespondToConnectivityProbingOrMigration(); + // Called in IETF QUIC. Start peer migration if a non-probing frame is + // received and the current packet number is largest received so far. + void MaybeStartIetfPeerMigration(QuicFrameType type); + + // Send PATH_RESPONSE to the given peer address. + bool SendPathResponse(const QuicPathFrameBuffer& data_buffer, + QuicSocketAddress peer_address_to_send); + + // Update both connection's and packet creator's peer address. + void UpdatePeerAddress(QuicSocketAddress peer_address); + QuicFramer framer_; // Contents received in the current packet, especially used to identify @@ -1378,6 +1426,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Always false outside the context of ProcessUdpPacket(). bool is_current_packet_connectivity_probing_; + bool has_path_challenge_in_current_packet_; + // Caches the current effective peer migration type if a effective peer // migration might be initiated. As soon as the current packet is confirmed // not a connectivity probe, effective peer migration will start. @@ -1403,6 +1453,8 @@ class QUIC_EXPORT_PRIVATE QuicConnection QuicSocketAddress self_address_; QuicSocketAddress peer_address_; + // Other than initialization, do not modify it directly, use + // UpdatePeerAddress() instead. QuicSocketAddress direct_peer_address_; // Address of the endpoint behind the proxy if the connection is proxied. // Otherwise it is the same as |peer_address_|. @@ -1448,7 +1500,7 @@ class QUIC_EXPORT_PRIVATE QuicConnection // established, but which could not be decrypted. We buffer these on // the assumption that they could not be processed because they were // sent with the INITIAL encryption and the CHLO message was lost. - QuicCircularDeque<UndecryptablePacket> undecryptable_packets_; + std::deque<UndecryptablePacket> undecryptable_packets_; // Collection of coalesced packets which were received while processing // the current packet. @@ -1461,13 +1513,6 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Maximum number of tracked packets. QuicPacketCount max_tracked_packets_; - // When the version negotiation packet could not be sent because the socket - // was not writable, this is set to true. - bool pending_version_negotiation_packet_; - // Used when pending_version_negotiation_packet_ is true. - bool send_ietf_version_negotiation_packet_; - bool send_version_negotiation_packet_with_prefixed_lengths_; - // Contains the connection close packets if the connection has been closed. std::unique_ptr<std::vector<std::unique_ptr<QuicEncryptedPacket>>> termination_packets_; @@ -1651,8 +1696,16 @@ class QUIC_EXPORT_PRIVATE QuicConnection // Deque because the peer might no be using this implementation, and others // might send a packet with more than one PATH_CHALLENGE, so all need to be // saved and responded to. + // TODO(danzh) deprecate this field when deprecating + // --quic_send_path_response. QuicCircularDeque<QuicPathFrameBuffer> received_path_challenge_payloads_; + // Buffer outstanding PATH_CHALLENGEs if socket write is blocked, future + // OnCanWrite will attempt to respond with PATH_RESPONSEs using the retained + // payload and peer addresses. + QuicCircularDeque<std::pair<QuicPathFrameBuffer, QuicSocketAddress>> + pending_path_challenge_payloads_; + // Set of connection IDs that should be accepted as destination on // received packets. This is conceptually a set but is implemented as a // vector to improve performance since it is expected to be very small. @@ -1720,6 +1773,37 @@ class QUIC_EXPORT_PRIVATE QuicConnection // True if next packet is intended to consume remaining space in the // coalescer. bool fill_coalesced_packet_ = false; + + size_t anti_amplification_factor_ = + GetQuicFlag(FLAGS_quic_anti_amplification_factor); + + bool start_peer_migration_earlier_ = + GetQuicReloadableFlag(quic_start_peer_migration_earlier); + + bool fix_missing_connected_checks_ = + GetQuicReloadableFlag(quic_add_missing_connected_checks); + + // latch --gfe2_reloadable_flag_quic_send_path_response and + // --gfe2_reloadable_flag_quic_start_peer_migration_earlier. + bool send_path_response_ = start_peer_migration_earlier_ && + GetQuicReloadableFlag(quic_send_path_response); + // True if AckFrequencyFrame is supported. + bool can_receive_ack_frequency_frame_ = false; + + // Indicate whether coalescing is done. + bool coalescing_done_ = false; + + // Indicate whether any ENCRYPTION_HANDSHAKE packet has been sent. + bool handshake_packet_sent_ = false; + + const bool fix_missing_initial_keys_ = + GetQuicReloadableFlag(quic_fix_missing_initial_keys2); + + const bool fix_out_of_order_sending_ = + GetQuicReloadableFlag(quic_fix_out_of_order_sending2); + + const bool check_keys_before_writing_ = + GetQuicReloadableFlag(quic_check_keys_before_writing); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc index d33cb353a76..3acac1c22dc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_connection_test.cc @@ -24,7 +24,6 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_error_code_wrappers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" @@ -40,7 +39,6 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/test_tools/simple_data_producer.h" -#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h" #include "net/third_party/quiche/src/quic/test_tools/simple_session_notifier.h" #include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" @@ -110,162 +108,6 @@ QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) { } } -// TaggingEncrypter appends kTagSize bytes of |tag| to the end of each message. -class TaggingEncrypter : public QuicEncrypter { - public: - explicit TaggingEncrypter(uint8_t tag) : tag_(tag) {} - TaggingEncrypter(const TaggingEncrypter&) = delete; - TaggingEncrypter& operator=(const TaggingEncrypter&) = delete; - - ~TaggingEncrypter() override {} - - // QuicEncrypter interface. - bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; } - - bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override { - return true; - } - - bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; } - - bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override { - return true; - } - - bool EncryptPacket(uint64_t /*packet_number*/, - quiche::QuicheStringPiece /*associated_data*/, - quiche::QuicheStringPiece plaintext, - char* output, - size_t* output_length, - size_t max_output_length) override { - const size_t len = plaintext.size() + kTagSize; - if (max_output_length < len) { - return false; - } - // Memmove is safe for inplace encryption. - memmove(output, plaintext.data(), plaintext.size()); - output += plaintext.size(); - memset(output, tag_, kTagSize); - *output_length = len; - return true; - } - - std::string GenerateHeaderProtectionMask( - quiche::QuicheStringPiece /*sample*/) override { - return std::string(5, 0); - } - - size_t GetKeySize() const override { return 0; } - size_t GetNoncePrefixSize() const override { return 0; } - size_t GetIVSize() const override { return 0; } - - size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { - return ciphertext_size - kTagSize; - } - - size_t GetCiphertextSize(size_t plaintext_size) const override { - return plaintext_size + kTagSize; - } - - quiche::QuicheStringPiece GetKey() const override { - return quiche::QuicheStringPiece(); - } - - quiche::QuicheStringPiece GetNoncePrefix() const override { - return quiche::QuicheStringPiece(); - } - - private: - enum { - kTagSize = 12, - }; - - const uint8_t tag_; -}; - -// TaggingDecrypter ensures that the final kTagSize bytes of the message all -// have the same value and then removes them. -class TaggingDecrypter : public QuicDecrypter { - public: - ~TaggingDecrypter() override {} - - // QuicDecrypter interface - bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; } - - bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override { - return true; - } - - bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; } - - bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override { - return true; - } - - bool SetPreliminaryKey(quiche::QuicheStringPiece /*key*/) override { - QUIC_BUG << "should not be called"; - return false; - } - - bool SetDiversificationNonce(const DiversificationNonce& /*key*/) override { - return true; - } - - bool DecryptPacket(uint64_t /*packet_number*/, - quiche::QuicheStringPiece /*associated_data*/, - quiche::QuicheStringPiece ciphertext, - char* output, - size_t* output_length, - size_t /*max_output_length*/) override { - if (ciphertext.size() < kTagSize) { - return false; - } - if (!CheckTag(ciphertext, GetTag(ciphertext))) { - return false; - } - *output_length = ciphertext.size() - kTagSize; - memcpy(output, ciphertext.data(), *output_length); - return true; - } - - std::string GenerateHeaderProtectionMask( - QuicDataReader* /*sample_reader*/) override { - return std::string(5, 0); - } - - size_t GetKeySize() const override { return 0; } - size_t GetNoncePrefixSize() const override { return 0; } - size_t GetIVSize() const override { return 0; } - quiche::QuicheStringPiece GetKey() const override { - return quiche::QuicheStringPiece(); - } - quiche::QuicheStringPiece GetNoncePrefix() const override { - return quiche::QuicheStringPiece(); - } - // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. - uint32_t cipher_id() const override { return 0xFFFFFFF0; } - - protected: - virtual uint8_t GetTag(quiche::QuicheStringPiece ciphertext) { - return ciphertext.data()[ciphertext.size() - 1]; - } - - private: - enum { - kTagSize = 12, - }; - - bool CheckTag(quiche::QuicheStringPiece ciphertext, uint8_t tag) { - for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) { - if (ciphertext.data()[i] != tag) { - return false; - } - } - - return true; - } -}; - // StringTaggingDecrypter ensures that the final kTagSize bytes of the message // match the expected value. class StrictTaggingDecrypter : public TaggingDecrypter { @@ -336,345 +178,6 @@ class TestAlarmFactory : public QuicAlarmFactory { } }; -class TestPacketWriter : public QuicPacketWriter { - struct PacketBuffer { - QUIC_CACHELINE_ALIGNED char buffer[1500]; - bool in_use = false; - }; - - public: - TestPacketWriter(ParsedQuicVersion version, MockClock* clock) - : version_(version), - framer_(SupportedVersions(version_), Perspective::IS_SERVER), - clock_(clock) { - QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(), - TestConnectionId()); - framer_.framer()->SetInitialObfuscators(TestConnectionId()); - - for (int i = 0; i < 128; ++i) { - PacketBuffer* p = new PacketBuffer(); - packet_buffer_pool_.push_back(p); - packet_buffer_pool_index_[p->buffer] = p; - packet_buffer_free_list_.push_back(p); - } - } - TestPacketWriter(const TestPacketWriter&) = delete; - TestPacketWriter& operator=(const TestPacketWriter&) = delete; - - ~TestPacketWriter() override { - EXPECT_EQ(packet_buffer_pool_.size(), packet_buffer_free_list_.size()) - << packet_buffer_pool_.size() - packet_buffer_free_list_.size() - << " out of " << packet_buffer_pool_.size() - << " packet buffers have been leaked."; - for (auto p : packet_buffer_pool_) { - delete p; - } - } - - // QuicPacketWriter interface - WriteResult WritePacket(const char* buffer, - size_t buf_len, - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/, - PerPacketOptions* /*options*/) override { - // If the buffer is allocated from the pool, return it back to the pool. - // Note the buffer content doesn't change. - if (packet_buffer_pool_index_.find(const_cast<char*>(buffer)) != - packet_buffer_pool_index_.end()) { - FreePacketBuffer(buffer); - } - - QuicEncryptedPacket packet(buffer, buf_len); - ++packets_write_attempts_; - - if (packet.length() >= sizeof(final_bytes_of_last_packet_)) { - final_bytes_of_previous_packet_ = final_bytes_of_last_packet_; - memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4, - sizeof(final_bytes_of_last_packet_)); - } - - if (use_tagging_decrypter_) { - if (framer_.framer()->version().KnowsWhichDecrypterToUse()) { - framer_.framer()->InstallDecrypter( - ENCRYPTION_INITIAL, std::make_unique<TaggingDecrypter>()); - framer_.framer()->InstallDecrypter( - ENCRYPTION_HANDSHAKE, std::make_unique<TaggingDecrypter>()); - framer_.framer()->InstallDecrypter( - ENCRYPTION_ZERO_RTT, std::make_unique<TaggingDecrypter>()); - framer_.framer()->InstallDecrypter( - ENCRYPTION_FORWARD_SECURE, std::make_unique<TaggingDecrypter>()); - } else { - framer_.framer()->SetDecrypter(ENCRYPTION_INITIAL, - std::make_unique<TaggingDecrypter>()); - } - } else if (framer_.framer()->version().KnowsWhichDecrypterToUse()) { - framer_.framer()->InstallDecrypter( - ENCRYPTION_FORWARD_SECURE, - std::make_unique<NullDecrypter>(Perspective::IS_SERVER)); - } - EXPECT_TRUE(framer_.ProcessPacket(packet)) - << framer_.framer()->detailed_error(); - if (block_on_next_write_) { - write_blocked_ = true; - block_on_next_write_ = false; - } - if (next_packet_too_large_) { - next_packet_too_large_ = false; - return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE); - } - if (always_get_packet_too_large_) { - return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE); - } - if (IsWriteBlocked()) { - return WriteResult(is_write_blocked_data_buffered_ - ? WRITE_STATUS_BLOCKED_DATA_BUFFERED - : WRITE_STATUS_BLOCKED, - 0); - } - - if (ShouldWriteFail()) { - return WriteResult(WRITE_STATUS_ERROR, 0); - } - - last_packet_size_ = packet.length(); - last_packet_header_ = framer_.header(); - if (!framer_.connection_close_frames().empty()) { - ++connection_close_packets_; - } - if (!write_pause_time_delta_.IsZero()) { - clock_->AdvanceTime(write_pause_time_delta_); - } - if (is_batch_mode_) { - bytes_buffered_ += last_packet_size_; - return WriteResult(WRITE_STATUS_OK, 0); - } - return WriteResult(WRITE_STATUS_OK, last_packet_size_); - } - - bool ShouldWriteFail() { return write_should_fail_; } - - bool IsWriteBlocked() const override { return write_blocked_; } - - void SetWriteBlocked() { write_blocked_ = true; } - - void SetWritable() override { write_blocked_ = false; } - - void SetShouldWriteFail() { write_should_fail_ = true; } - - QuicByteCount GetMaxPacketSize( - const QuicSocketAddress& /*peer_address*/) const override { - return max_packet_size_; - } - - bool SupportsReleaseTime() const override { return supports_release_time_; } - - bool IsBatchMode() const override { return is_batch_mode_; } - - QuicPacketBuffer GetNextWriteLocation( - const QuicIpAddress& /*self_address*/, - const QuicSocketAddress& /*peer_address*/) override { - return {AllocPacketBuffer(), - [this](const char* p) { FreePacketBuffer(p); }}; - } - - WriteResult Flush() override { - flush_attempts_++; - if (block_on_next_flush_) { - block_on_next_flush_ = false; - SetWriteBlocked(); - return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1); - } - if (write_should_fail_) { - return WriteResult(WRITE_STATUS_ERROR, /*errno*/ -1); - } - int bytes_flushed = bytes_buffered_; - bytes_buffered_ = 0; - return WriteResult(WRITE_STATUS_OK, bytes_flushed); - } - - void BlockOnNextFlush() { block_on_next_flush_ = true; } - - void BlockOnNextWrite() { block_on_next_write_ = true; } - - void SimulateNextPacketTooLarge() { next_packet_too_large_ = true; } - - void AlwaysGetPacketTooLarge() { always_get_packet_too_large_ = true; } - - // Sets the amount of time that the writer should before the actual write. - void SetWritePauseTimeDelta(QuicTime::Delta delta) { - write_pause_time_delta_ = delta; - } - - void SetBatchMode(bool new_value) { is_batch_mode_ = new_value; } - - const QuicPacketHeader& header() { return framer_.header(); } - - size_t frame_count() const { return framer_.num_frames(); } - - const std::vector<QuicAckFrame>& ack_frames() const { - return framer_.ack_frames(); - } - - const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const { - return framer_.stop_waiting_frames(); - } - - const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const { - return framer_.connection_close_frames(); - } - - const std::vector<QuicRstStreamFrame>& rst_stream_frames() const { - return framer_.rst_stream_frames(); - } - - const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const { - return framer_.stream_frames(); - } - - const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const { - return framer_.crypto_frames(); - } - - const std::vector<QuicPingFrame>& ping_frames() const { - return framer_.ping_frames(); - } - - const std::vector<QuicMessageFrame>& message_frames() const { - return framer_.message_frames(); - } - - const std::vector<QuicWindowUpdateFrame>& window_update_frames() const { - return framer_.window_update_frames(); - } - - const std::vector<QuicPaddingFrame>& padding_frames() const { - return framer_.padding_frames(); - } - - const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const { - return framer_.path_challenge_frames(); - } - - const std::vector<QuicPathResponseFrame>& path_response_frames() const { - return framer_.path_response_frames(); - } - - const QuicEncryptedPacket* coalesced_packet() const { - return framer_.coalesced_packet(); - } - - size_t last_packet_size() { return last_packet_size_; } - - const QuicPacketHeader& last_packet_header() const { - return last_packet_header_; - } - - const QuicVersionNegotiationPacket* version_negotiation_packet() { - return framer_.version_negotiation_packet(); - } - - void set_is_write_blocked_data_buffered(bool buffered) { - is_write_blocked_data_buffered_ = buffered; - } - - void set_perspective(Perspective perspective) { - // We invert perspective here, because the framer needs to parse packets - // we send. - QuicFramerPeer::SetPerspective(framer_.framer(), - QuicUtils::InvertPerspective(perspective)); - } - - // final_bytes_of_last_packet_ returns the last four bytes of the previous - // packet as a little-endian, uint32_t. This is intended to be used with a - // TaggingEncrypter so that tests can determine which encrypter was used for - // a given packet. - uint32_t final_bytes_of_last_packet() { return final_bytes_of_last_packet_; } - - // Returns the final bytes of the second to last packet. - uint32_t final_bytes_of_previous_packet() { - return final_bytes_of_previous_packet_; - } - - void use_tagging_decrypter() { use_tagging_decrypter_ = true; } - - uint32_t packets_write_attempts() const { return packets_write_attempts_; } - - uint32_t flush_attempts() const { return flush_attempts_; } - - uint32_t connection_close_packets() const { - return connection_close_packets_; - } - - void Reset() { framer_.Reset(); } - - void SetSupportedVersions(const ParsedQuicVersionVector& versions) { - framer_.SetSupportedVersions(versions); - } - - void set_max_packet_size(QuicByteCount max_packet_size) { - max_packet_size_ = max_packet_size; - } - - void set_supports_release_time(bool supports_release_time) { - supports_release_time_ = supports_release_time; - } - - SimpleQuicFramer* framer() { return &framer_; } - - private: - char* AllocPacketBuffer() { - PacketBuffer* p = packet_buffer_free_list_.front(); - EXPECT_FALSE(p->in_use); - p->in_use = true; - packet_buffer_free_list_.pop_front(); - return p->buffer; - } - - void FreePacketBuffer(const char* buffer) { - auto iter = packet_buffer_pool_index_.find(const_cast<char*>(buffer)); - ASSERT_TRUE(iter != packet_buffer_pool_index_.end()); - PacketBuffer* p = iter->second; - ASSERT_TRUE(p->in_use); - p->in_use = false; - packet_buffer_free_list_.push_back(p); - } - - ParsedQuicVersion version_; - SimpleQuicFramer framer_; - size_t last_packet_size_ = 0; - QuicPacketHeader last_packet_header_; - bool write_blocked_ = false; - bool write_should_fail_ = false; - bool block_on_next_flush_ = false; - bool block_on_next_write_ = false; - bool next_packet_too_large_ = false; - bool always_get_packet_too_large_ = false; - bool is_write_blocked_data_buffered_ = false; - bool is_batch_mode_ = false; - // Number of times Flush() was called. - uint32_t flush_attempts_ = 0; - // (Batch mode only) Number of bytes buffered in writer. It is used as the - // return value of a successful Flush(). - uint32_t bytes_buffered_ = 0; - uint32_t final_bytes_of_last_packet_ = 0; - uint32_t final_bytes_of_previous_packet_ = 0; - bool use_tagging_decrypter_ = false; - uint32_t packets_write_attempts_ = 0; - uint32_t connection_close_packets_ = 0; - MockClock* clock_ = nullptr; - // If non-zero, the clock will pause during WritePacket for this amount of - // time. - QuicTime::Delta write_pause_time_delta_ = QuicTime::Delta::Zero(); - QuicByteCount max_packet_size_ = kMaxOutgoingPacketSize; - bool supports_release_time_ = false; - // Used to verify writer-allocated packet buffers are properly released. - std::vector<PacketBuffer*> packet_buffer_pool_; - // Buffer address => Address of the owning PacketBuffer. - QuicHashMap<char*, PacketBuffer*> packet_buffer_pool_index_; - // Indices in packet_buffer_pool_ that are not allocated. - std::list<PacketBuffer*> packet_buffer_free_list_; -}; - class TestConnection : public QuicConnection { public: TestConnection(QuicConnectionId connection_id, @@ -724,6 +227,7 @@ class TestConnection : public QuicConnection { SerializedPacket serialized_packet( QuicPacketNumber(packet_number), PACKET_4BYTE_PACKET_NUMBER, buffer, encrypted_length, has_ack, has_pending_frames); + serialized_packet.peer_address = kPeerAddress; if (retransmittable == HAS_RETRANSMITTABLE_DATA) { serialized_packet.retransmittable_frames.push_back( QuicFrame(QuicPingFrame())); @@ -854,9 +358,26 @@ class TestConnection : public QuicConnection { writer()->SetSupportedVersions(versions); } + // This should be called before setting customized encrypters/decrypters for + // connection and peer creator. void set_perspective(Perspective perspective) { writer()->set_perspective(perspective); QuicConnectionPeer::SetPerspective(this, perspective); + QuicSentPacketManagerPeer::SetPerspective( + QuicConnectionPeer::GetSentPacketManager(this), perspective); + QuicConnectionPeer::GetFramer(this)->SetInitialObfuscators( + TestConnectionId()); + for (EncryptionLevel level : {ENCRYPTION_ZERO_RTT, ENCRYPTION_HANDSHAKE, + ENCRYPTION_FORWARD_SECURE}) { + if (QuicConnectionPeer::GetFramer(this)->HasEncrypterOfEncryptionLevel( + level)) { + SetEncrypter(level, std::make_unique<NullEncrypter>(perspective)); + } + if (QuicConnectionPeer::GetFramer(this)->HasDecrypterOfEncryptionLevel( + level)) { + InstallDecrypter(level, std::make_unique<NullDecrypter>(perspective)); + } + } } // Enable path MTU discovery. Assumes that the test is performed from the @@ -1069,7 +590,8 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { peer_creator_(connection_id_, &peer_framer_, /*delegate=*/nullptr), - writer_(new TestPacketWriter(version(), &clock_)), + writer_( + new TestPacketWriter(version(), &clock_, Perspective::IS_CLIENT)), connection_(connection_id_, kPeerAddress, helper_.get(), @@ -1170,6 +692,7 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { ENCRYPTION_FORWARD_SECURE, std::make_unique<NullDecrypter>(Perspective::IS_CLIENT)); } + peer_creator_.SetDefaultPeerAddress(kSelfAddress); } QuicConnectionTest(const QuicConnectionTest&) = delete; @@ -1338,6 +861,70 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { return encrypted_length; } + struct PacketInfo { + PacketInfo(uint64_t packet_number, QuicFrames frames, EncryptionLevel level) + : packet_number(packet_number), frames(frames), level(level) {} + + uint64_t packet_number; + QuicFrames frames; + EncryptionLevel level; + }; + + size_t ProcessCoalescedPacket(std::vector<PacketInfo> packets) { + char coalesced_buffer[kMaxOutgoingPacketSize]; + size_t coalesced_size = 0; + bool contains_initial = false; + for (const auto& packet : packets) { + QuicPacketHeader header = + ConstructPacketHeader(packet.packet_number, packet.level); + // Set the correct encryption level and encrypter on peer_creator and + // peer_framer, respectively. + peer_creator_.set_encryption_level(packet.level); + if (packet.level == ENCRYPTION_INITIAL) { + contains_initial = true; + } + if (QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_) > + ENCRYPTION_INITIAL) { + peer_framer_.SetEncrypter( + QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_), + std::make_unique<TaggingEncrypter>(0x01)); + // Set the corresponding decrypter. + if (connection_.version().KnowsWhichDecrypterToUse()) { + connection_.InstallDecrypter( + QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_), + std::make_unique<StrictTaggingDecrypter>(0x01)); + } else { + connection_.SetDecrypter( + QuicPacketCreatorPeer::GetEncryptionLevel(&peer_creator_), + std::make_unique<StrictTaggingDecrypter>(0x01)); + } + } + std::unique_ptr<QuicPacket> constructed_packet( + ConstructPacket(header, packet.frames)); + + char buffer[kMaxOutgoingPacketSize]; + size_t encrypted_length = peer_framer_.EncryptPayload( + packet.level, QuicPacketNumber(packet.packet_number), + *constructed_packet, buffer, kMaxOutgoingPacketSize); + DCHECK_LE(coalesced_size + encrypted_length, kMaxOutgoingPacketSize); + memcpy(coalesced_buffer + coalesced_size, buffer, encrypted_length); + coalesced_size += encrypted_length; + } + if (contains_initial) { + // Padded coalesced packet to full if it contains initial packet. + memset(coalesced_buffer + coalesced_size, '0', + kMaxOutgoingPacketSize - coalesced_size); + } + connection_.ProcessUdpPacket( + kSelfAddress, kPeerAddress, + QuicReceivedPacket(coalesced_buffer, coalesced_size, clock_.Now(), + false)); + if (connection_.GetSendAlarm()->IsSet()) { + connection_.GetSendAlarm()->Fire(); + } + return coalesced_size; + } + size_t ProcessDataPacket(uint64_t number) { return ProcessDataPacketAtLevel(number, false, ENCRYPTION_FORWARD_SECURE); } @@ -1362,7 +949,9 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { } else { frames.push_back(QuicFrame(frame1_)); } - frames.push_back(QuicFrame(QuicPaddingFrame(-1))); + if (level == ENCRYPTION_INITIAL) { + frames.push_back(QuicFrame(QuicPaddingFrame(-1))); + } std::unique_ptr<QuicPacket> packet = ConstructPacket(header, frames); char buffer[kMaxOutgoingPacketSize]; peer_creator_.set_encryption_level(level); @@ -1678,6 +1267,14 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { } QuicFramerPeer::SetPerspective(&peer_framer_, QuicUtils::InvertPerspective(perspective)); + peer_framer_.SetInitialObfuscators(TestConnectionId()); + for (EncryptionLevel level : {ENCRYPTION_ZERO_RTT, ENCRYPTION_HANDSHAKE, + ENCRYPTION_FORWARD_SECURE}) { + if (peer_framer_.HasEncrypterOfEncryptionLevel(level)) { + peer_creator_.SetEncrypter( + level, std::make_unique<NullEncrypter>(peer_framer_.perspective())); + } + } } void set_packets_between_probes_base( @@ -1759,6 +1356,9 @@ class QuicConnectionTest : public QuicTestWithParam<TestParams> { } connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + // Prevent packets from being coalesced. + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); } void TestClientRetryHandling(bool invalid_retry_tag, @@ -1958,6 +1558,11 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); EXPECT_EQ(Perspective::IS_SERVER, connection_.perspective()); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + peer_creator_.set_encryption_level(ENCRYPTION_FORWARD_SECURE); + // Prevent packets from being coalesced. + EXPECT_CALL(visitor_, GetHandshakeState()) + .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); // Clear direct_peer_address. QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); @@ -1967,23 +1572,30 @@ TEST_P(QuicConnectionTest, PeerAddressChangeAtServer) { QuicSocketAddress()); EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); - if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { - EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); - } else { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); - } - ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, - kPeerAddress); + const QuicSocketAddress kNewPeerAddress = + QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); + EXPECT_CALL(visitor_, OnStreamFrame(_)) + .WillOnce(Invoke( + [=]() { EXPECT_EQ(kPeerAddress, connection_.peer_address()); })) + .WillOnce(Invoke([=]() { + EXPECT_EQ((GetQuicReloadableFlag(quic_start_peer_migration_earlier) || + !GetParam().version.HasIetfQuicFrames() + ? kNewPeerAddress + : kPeerAddress), + connection_.peer_address()); + })); + QuicFrames frames; + frames.push_back(QuicFrame(frame1_)); + ProcessFramesPacketWithAddresses(frames, kSelfAddress, kPeerAddress); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); // Process another packet with a different peer address on server side will // start connection migration. - const QuicSocketAddress kNewPeerAddress = - QuicSocketAddress(QuicIpAddress::Loopback6(), /*port=*/23456); EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(1); - ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, - kNewPeerAddress); + QuicFrames frames2; + frames2.push_back(QuicFrame(frame2_)); + ProcessFramesPacketWithAddresses(frames2, kSelfAddress, kNewPeerAddress); EXPECT_EQ(kNewPeerAddress, connection_.peer_address()); EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } @@ -2099,8 +1711,9 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(0); - // Process a padded PING or PATH CHALLENGE packet with no peer address change - // on server side will be ignored. + // Process a padded PING packet with no peer address change on server side + // will be ignored. But a PATH CHALLENGE packet with no peer address change + // will be considered as path probing. std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( @@ -2112,7 +1725,10 @@ TEST_P(QuicConnectionTest, ReceivePathProbeWithNoAddressChangeAtServer) { connection_.GetStats().num_connectivity_probing_received; ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received); - EXPECT_EQ(num_probing_received, + EXPECT_EQ(num_probing_received + (GetParam().version.HasIetfQuicFrames() && + connection_.send_path_response() + ? 1u + : 0u), connection_.GetStats().num_connectivity_probing_received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2434,7 +2050,7 @@ TEST_P(QuicConnectionTest, MigrateAfterProbingAtServer) { EXPECT_EQ(kNewPeerAddress, connection_.effective_peer_address()); } -TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { +TEST_P(QuicConnectionTest, ReceiveConnectivityProbingPacketAtClient) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); PathProbeTestInit(Perspective::IS_CLIENT); @@ -2459,7 +2075,9 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { // Client takes all padded PING packet as speculative connectivity // probing packet, and reports to visitor. EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); - EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(1); + if (!connection_.send_path_response()) { + EXPECT_CALL(visitor_, OnPacketReceived(_, _, false)).Times(1); + } std::unique_ptr<SerializedPacket> probing_packet = ConstructProbingPacket(); std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket( @@ -2470,7 +2088,10 @@ TEST_P(QuicConnectionTest, ReceivePaddedPingAtClient) { connection_.GetStats().num_connectivity_probing_received; ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received); - EXPECT_EQ(num_probing_received, + EXPECT_EQ(num_probing_received + (GetParam().version.HasIetfQuicFrames() && + connection_.send_path_response() + ? 1u + : 0u), connection_.GetStats().num_connectivity_probing_received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); @@ -2939,16 +2560,47 @@ TEST_P(QuicConnectionTest, AckReceiptCausesAckSend) { ProcessAckPacket(&frame2); } -TEST_P(QuicConnectionTest, AckSentEveryNthPacket) { - connection_.set_ack_frequency(3); +TEST_P(QuicConnectionTest, AckFrequencyUpdatedFromAckFrequencyFrame) { + if (!GetParam().version.HasIetfQuicFrames()) { + return; + } + connection_.set_can_receive_ack_frequency_frame(); + // Expect 13 acks, every 3rd packet including the first packet with + // AckFrequencyFrame. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(13); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(39); - // Expect 13 acks, every 3rd packet. - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(13); - // Receives packets 1 - 39. - for (size_t i = 1; i <= 39; ++i) { + QuicAckFrequencyFrame ack_frequency_frame; + ack_frequency_frame.packet_tolerance = 3; + ProcessFramePacketAtLevel(1, QuicFrame(&ack_frequency_frame), + ENCRYPTION_FORWARD_SECURE); + + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(38); + // Receives packets 2 - 39. + for (size_t i = 2; i <= 39; ++i) { + ProcessDataPacket(i); + } +} + +TEST_P(QuicConnectionTest, + AckFrequencyFrameOutsideApplicationDataNumberSpaceIsIgnored) { + if (!GetParam().version.HasIetfQuicFrames()) { + return; + } + connection_.set_can_receive_ack_frequency_frame(); + + QuicAckFrequencyFrame ack_frequency_frame; + ack_frequency_frame.packet_tolerance = 3; + ProcessFramePacketAtLevel(1, QuicFrame(&ack_frequency_frame), + ENCRYPTION_HANDSHAKE); + + // Expect 30 acks, every 2nd (instead of 3rd) packet including the first + // packet with AckFrequencyFrame. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(30); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(60); + // Receives packets 2 - 61. + for (size_t i = 2; i <= 61; ++i) { ProcessDataPacket(i); } } @@ -2960,7 +2612,6 @@ TEST_P(QuicConnectionTest, AckDecimationReducesAcks) { QuicTime::Delta::Zero(), QuicTime::Zero()); EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); // Start ack decimation from 10th packet. connection_.set_min_received_before_ack_decimation(10); @@ -3043,6 +2694,8 @@ TEST_P(QuicConnectionTest, AckNeedsRetransmittableFramesAfterPto) { connection_.SetFromConfig(config); connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + connection_.OnHandshakeComplete(); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(10); @@ -4538,7 +4191,7 @@ TEST_P(QuicConnectionTest, RetransmitPacketsWithInitialEncryption) { SendStreamDataToPeer(2, "bar", 0, NO_FIN, nullptr); EXPECT_FALSE(notifier_.HasLostStreamData()); - connection_.MarkZeroRttPacketsForRetransmission(); + connection_.MarkZeroRttPacketsForRetransmission(0); EXPECT_TRUE(notifier_.HasLostStreamData()); } @@ -4565,9 +4218,9 @@ TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) { // which should result in the original packet being processed. SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, std::make_unique<TaggingEncrypter>(tag)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2); ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); @@ -4640,9 +4293,9 @@ TEST_P(QuicConnectionTest, Buffer100NonDecryptablePacketsThenKeyChange) { SetDecrypter(ENCRYPTION_ZERO_RTT, std::make_unique<StrictTaggingDecrypter>(tag)); EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, std::make_unique<TaggingEncrypter>(tag)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(100); connection_.GetProcessUndecryptablePacketsAlarm()->Fire(); @@ -5445,11 +5098,6 @@ TEST_P(QuicConnectionTest, MtuDiscoverySecondProbeFailed) { EXPECT_EQ(third_probe_size, connection_.max_packet_length()); SendStreamDataToPeer(3, "$", stream_offset++, NO_FIN, nullptr); - if (!GetQuicReloadableFlag(quic_revert_mtu_after_two_ptos)) { - EXPECT_FALSE(connection_.PathMtuReductionDetectionInProgress()); - return; - } - EXPECT_TRUE(connection_.PathMtuReductionDetectionInProgress()); if (connection_.PathDegradingDetectionInProgress() && @@ -5938,6 +5586,9 @@ TEST_P(QuicConnectionTest, TimeoutAfterSendSilentCloseWithOpenStreams) { // Indicate streams are still open. EXPECT_CALL(visitor_, ShouldKeepConnectionAlive()) .WillRepeatedly(Return(true)); + if (GetQuicReloadableFlag(quic_add_stream_info_to_idle_close_detail)) { + EXPECT_CALL(visitor_, GetStreamsInfoForLogging()).WillOnce(Return("")); + } // This time, we should time out and send a connection close due to the TLP. EXPECT_CALL(visitor_, @@ -6254,85 +5905,8 @@ TEST_P(QuicConnectionTest, SendDelayedAck) { EXPECT_FALSE(connection_.HasPendingAcks()); } -TEST_P(QuicConnectionTest, SendDelayedAfterQuiescence) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - QuicConnectionPeer::SetFastAckAfterQuiescence(&connection_, true); - - // The beginning of the connection counts as quiescence. - QuicTime ack_time = clock_.ApproximateNow() + kAlarmGranularity; - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.HasPendingAcks()); - const uint8_t tag = 0x07; - SetDecrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<TaggingEncrypter>(tag)); - // Process a packet from the non-crypto stream. - frame1_.stream_id = 3; - - // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used - // instead of ENCRYPTION_INITIAL. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(DefaultDelayedAckTime()); - connection_.GetAckAlarm()->Fire(); - // Check that ack is sent and that delayed ack alarm is reset. - size_t padding_frame_count = writer_->padding_frames().size(); - if (GetParam().no_stop_waiting) { - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - - // Process another packet immedately after sending the ack and expect the - // ack alarm to be set delayed ack time in the future. - ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime(); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(DefaultDelayedAckTime()); - connection_.GetAckAlarm()->Fire(); - // Check that ack is sent and that delayed ack alarm is reset. - padding_frame_count = writer_->padding_frames().size(); - if (GetParam().no_stop_waiting) { - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - - // Wait 1 second and ensure the ack alarm is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); -} - TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); const size_t kMinRttMs = 40; RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); @@ -6389,141 +5963,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { EXPECT_FALSE(connection_.HasPendingAcks()); } -TEST_P(QuicConnectionTest, SendDelayedAckAckDecimationAfterQuiescence) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); - QuicConnectionPeer::SetFastAckAfterQuiescence(&connection_, true); - - const size_t kMinRttMs = 40; - RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), - QuicTime::Delta::Zero(), QuicTime::Zero()); - - // The beginning of the connection counts as quiescence. - QuicTime ack_time = - clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.HasPendingAcks()); - const uint8_t tag = 0x07; - SetDecrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<TaggingEncrypter>(tag)); - // Process a packet from the non-crypto stream. - frame1_.stream_id = 3; - - // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used - // instead of ENCRYPTION_INITIAL. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(DefaultDelayedAckTime()); - connection_.GetAckAlarm()->Fire(); - // Check that ack is sent and that delayed ack alarm is reset. - size_t padding_frame_count = writer_->padding_frames().size(); - if (GetParam().no_stop_waiting) { - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - - // Process another packet immedately after sending the ack and expect the - // ack alarm to be set delayed ack time in the future. - ack_time = clock_.ApproximateNow() + DefaultDelayedAckTime(); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(DefaultDelayedAckTime()); - connection_.GetAckAlarm()->Fire(); - // Check that ack is sent and that delayed ack alarm is reset. - padding_frame_count = writer_->padding_frames().size(); - if (GetParam().no_stop_waiting) { - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - - // Wait 1 second and enesure the ack alarm is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // Process enough packets to get into ack decimation behavior. - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - ack_time = clock_.ApproximateNow() + - QuicTime::Delta::FromMilliseconds(kMinRttMs / 4); - uint64_t kFirstDecimatedPacket = 101; - for (unsigned int i = 0; i < kFirstDecimatedPacket - 4; ++i) { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - } - EXPECT_FALSE(connection_.HasPendingAcks()); - // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used - // instead of ENCRYPTION_INITIAL. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // The 10th received packet causes an ack to be sent. - for (int i = 0; i < 9; ++i) { - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - } - // Check that ack is sent and that delayed ack alarm is reset. - padding_frame_count = writer_->padding_frames().size(); - if (GetParam().no_stop_waiting) { - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - - // Wait 1 second and enesure the ack alarm is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); -} - TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -6585,7 +6024,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationUnlimitedAggregation) { TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION); QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); const size_t kMinRttMs = 40; @@ -6643,319 +6081,6 @@ TEST_P(QuicConnectionTest, SendDelayedAckDecimationEighthRtt) { EXPECT_FALSE(connection_.HasPendingAcks()); } -TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); - - const size_t kMinRttMs = 40; - RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), - QuicTime::Delta::Zero(), QuicTime::Zero()); - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + - QuicTime::Delta::FromMilliseconds(kMinRttMs / 4); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.HasPendingAcks()); - const uint8_t tag = 0x07; - SetDecrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<TaggingEncrypter>(tag)); - // Process a packet from the non-crypto stream. - frame1_.stream_id = 3; - - // Process all the initial packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - } - EXPECT_FALSE(connection_.HasPendingAcks()); - - // Receive one packet out of order and then the rest in order. - // The loop leaves a one packet gap between acks sent to simulate some loss. - for (int j = 0; j < 3; ++j) { - // Process packet 10 first and ensure the alarm is one eighth min_rtt. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9 + (j * 11), - !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // The 10th received packet causes an ack to be sent. - writer_->Reset(); - for (int i = 0; i < 9; ++i) { - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - // The ACK shouldn't be sent until the 10th packet is processed. - EXPECT_TRUE(writer_->ack_frames().empty()); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + i + (j * 11), - !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - } - // Check that ack is sent and that delayed ack alarm is reset. - size_t padding_frame_count = writer_->padding_frames().size(); - if (GetParam().no_stop_waiting) { - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - } -} - -TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); - - const size_t kMinRttMs = 40; - RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), - QuicTime::Delta::Zero(), QuicTime::Zero()); - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + - QuicTime::Delta::FromMilliseconds(kMinRttMs / 4); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.HasPendingAcks()); - const uint8_t tag = 0x07; - SetDecrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<TaggingEncrypter>(tag)); - // Process a packet from the non-crypto stream. - frame1_.stream_id = 3; - - // Process all the initial packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - } - EXPECT_FALSE(connection_.HasPendingAcks()); - // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used - // instead of ENCRYPTION_INITIAL. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // Process packet 10 first and ensure the alarm is one eighth min_rtt. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // The 10th received packet causes an ack to be sent. - for (int i = 0; i < 8; ++i) { - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - } - // Check that ack is sent and that delayed ack alarm is reset. - if (GetParam().no_stop_waiting) { - EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - - // The next packet received in order will cause an immediate ack, - // because it fills a hole. - EXPECT_FALSE(connection_.HasPendingAcks()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - // Check that ack is sent and that delayed ack alarm is reset. - if (GetParam().no_stop_waiting) { - EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); -} - -TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReorderingEighthRtt) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); - QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); - - const size_t kMinRttMs = 40; - RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), - QuicTime::Delta::Zero(), QuicTime::Zero()); - // The ack time should be based on min_rtt/8, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + - QuicTime::Delta::FromMilliseconds(kMinRttMs / 8); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.HasPendingAcks()); - const uint8_t tag = 0x07; - SetDecrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<TaggingEncrypter>(tag)); - // Process a packet from the non-crypto stream. - frame1_.stream_id = 3; - - // Process all the initial packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - } - EXPECT_FALSE(connection_.HasPendingAcks()); - // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used - // instead of ENCRYPTION_INITIAL. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // Process packet 10 first and ensure the alarm is one eighth min_rtt. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // The 10th received packet causes an ack to be sent. - for (int i = 0; i < 8; ++i) { - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - } - // Check that ack is sent and that delayed ack alarm is reset. - size_t padding_frame_count = writer_->padding_frames().size(); - if (GetParam().no_stop_waiting) { - EXPECT_EQ(padding_frame_count + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(padding_frame_count + 2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); -} - -TEST_P(QuicConnectionTest, - SendDelayedAckDecimationWithLargeReorderingEighthRtt) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(AnyNumber()); - QuicConnectionPeer::SetAckMode(&connection_, ACK_DECIMATION_WITH_REORDERING); - QuicConnectionPeer::SetAckDecimationDelay(&connection_, 0.125); - - const size_t kMinRttMs = 40; - RttStats* rtt_stats = const_cast<RttStats*>(manager_->GetRttStats()); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), - QuicTime::Delta::Zero(), QuicTime::Zero()); - // The ack time should be based on min_rtt/8, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + - QuicTime::Delta::FromMilliseconds(kMinRttMs / 8); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_FALSE(connection_.HasPendingAcks()); - const uint8_t tag = 0x07; - SetDecrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, - std::make_unique<TaggingEncrypter>(tag)); - // Process a packet from the non-crypto stream. - frame1_.stream_id = 3; - - // Process all the initial packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); - } - EXPECT_FALSE(connection_.HasPendingAcks()); - // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used - // instead of ENCRYPTION_INITIAL. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - - // Check if delayed ack timer is running for the expected interval. - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // Process packet 10 first and ensure the alarm is one eighth min_rtt. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); - - // The 10th received packet causes an ack to be sent. - for (int i = 0; i < 8; ++i) { - EXPECT_TRUE(connection_.HasPendingAcks()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - } - // Check that ack is sent and that delayed ack alarm is reset. - if (GetParam().no_stop_waiting) { - EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); - - // The next packet received in order will cause an immediate ack, - // because it fills a hole. - EXPECT_FALSE(connection_.HasPendingAcks()); - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, - ENCRYPTION_ZERO_RTT); - // Check that ack is sent and that delayed ack alarm is reset. - if (GetParam().no_stop_waiting) { - EXPECT_EQ(writer_->padding_frames().size() + 1u, writer_->frame_count()); - EXPECT_TRUE(writer_->stop_waiting_frames().empty()); - } else { - EXPECT_EQ(2u, writer_->frame_count()); - EXPECT_FALSE(writer_->stop_waiting_frames().empty()); - } - EXPECT_FALSE(writer_->ack_frames().empty()); - EXPECT_FALSE(connection_.HasPendingAcks()); -} - TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(1); @@ -7259,20 +6384,8 @@ TEST_P(QuicConnectionTest, SendWhenDisconnected) { ConnectionCloseBehavior::SILENT_CLOSE); EXPECT_FALSE(connection_.connected()); EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)); - if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early)) { - EXPECT_EQ(DISCARD, connection_.GetSerializedPacketFate( - /*is_mtu_discovery=*/false, ENCRYPTION_INITIAL)); - return; - } - std::unique_ptr<QuicPacket> packet = - ConstructDataPacket(1, !kHasStopWaiting, ENCRYPTION_INITIAL); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(1), _, _)) - .Times(0); - connection_.SendPacket(ENCRYPTION_INITIAL, 1, std::move(packet), - HAS_RETRANSMITTABLE_DATA, false, false); - EXPECT_EQ(1, connection_close_frame_count_); - EXPECT_THAT(saved_connection_close_frame_.quic_error_code, - IsError(QUIC_PEER_GOING_AWAY)); + EXPECT_EQ(DISCARD, connection_.GetSerializedPacketFate( + /*is_mtu_discovery=*/false, ENCRYPTION_INITIAL)); } TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { @@ -7303,7 +6416,7 @@ TEST_P(QuicConnectionTest, SendConnectivityProbingWhenDisconnected) { TEST_P(QuicConnectionTest, WriteBlockedAfterClientSendsConnectivityProbe) { PathProbeTestInit(Perspective::IS_CLIENT); - TestPacketWriter probing_writer(version(), &clock_); + TestPacketWriter probing_writer(version(), &clock_, Perspective::IS_CLIENT); // Block next write so that sending connectivity probe will encounter a // blocked write when send a connectivity probe to the peer. probing_writer.BlockOnNextWrite(); @@ -7335,7 +6448,7 @@ TEST_P(QuicConnectionTest, WriterBlockedAfterServerSendsConnectivityProbe) { TEST_P(QuicConnectionTest, WriterErrorWhenClientSendsConnectivityProbe) { PathProbeTestInit(Perspective::IS_CLIENT); - TestPacketWriter probing_writer(version(), &clock_); + TestPacketWriter probing_writer(version(), &clock_, Perspective::IS_CLIENT); probing_writer.SetShouldWriteFail(); // Connection should not be closed if a connectivity probe is failed to be @@ -7674,10 +6787,20 @@ TEST_P(QuicConnectionTest, OnPacketSentDebugVisitor) { MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + } connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + } connection_.SendConnectivityProbingPacket(writer_.get(), connection_.peer_address()); } @@ -7804,7 +6927,12 @@ TEST_P(QuicConnectionTest, SendPingImmediately) { CongestionBlockWrites(); connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + } EXPECT_CALL(debug_visitor, OnPingSent()).Times(1); connection_.SendControlFrame(QuicFrame(QuicPingFrame(1))); EXPECT_FALSE(connection_.HasQueuedData()); @@ -7816,7 +6944,12 @@ TEST_P(QuicConnectionTest, SendBlockedImmediately) { connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + } EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent); connection_.SendControlFrame(QuicFrame(new QuicBlockedFrame(1, 3))); EXPECT_EQ(1u, connection_.GetStats().blocked_frames_sent); @@ -7832,7 +6965,12 @@ TEST_P(QuicConnectionTest, FailedToSendBlockedFrames) { QuicBlockedFrame blocked(1, 3); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(0); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0); + } EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent); connection_.SendControlFrame(QuicFrame(&blocked)); EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent); @@ -8555,21 +7693,45 @@ TEST_P(QuicConnectionTest, SendProbingRetransmissions) { } // Expect them retransmitted in cyclic order (foo, bar, test, foo, bar...). QuicPacketCount sent_count = 0; - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)) - .WillRepeatedly(Invoke([this, &sent_count](const SerializedPacket&, - TransmissionType, QuicTime) { - ASSERT_EQ(1u, writer_->stream_frames().size()); - if (connection_.version().CanSendCoalescedPackets()) { - // There is a delay of sending coalesced packet, so (6, 0, 3, 6, - // 0...). - EXPECT_EQ(3 * ((sent_count + 2) % 3), - writer_->stream_frames()[0]->offset); - } else { - // Identify the frames by stream offset (0, 3, 6, 0, 3...). - EXPECT_EQ(3 * (sent_count % 3), writer_->stream_frames()[0]->offset); - } - sent_count++; - })); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)) + .WillRepeatedly( + Invoke([this, &sent_count](QuicPacketNumber, QuicPacketLength, bool, + TransmissionType, EncryptionLevel, + const QuicFrames&, const QuicFrames&, + QuicTime) { + ASSERT_EQ(1u, writer_->stream_frames().size()); + if (connection_.version().CanSendCoalescedPackets()) { + // There is a delay of sending coalesced packet, so (6, 0, 3, 6, + // 0...). + EXPECT_EQ(3 * ((sent_count + 2) % 3), + writer_->stream_frames()[0]->offset); + } else { + // Identify the frames by stream offset (0, 3, 6, 0, 3...). + EXPECT_EQ(3 * (sent_count % 3), + writer_->stream_frames()[0]->offset); + } + sent_count++; + })); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)) + .WillRepeatedly(Invoke([this, &sent_count](const SerializedPacket&, + TransmissionType, QuicTime) { + ASSERT_EQ(1u, writer_->stream_frames().size()); + if (connection_.version().CanSendCoalescedPackets()) { + // There is a delay of sending coalesced packet, so (6, 0, 3, 6, + // 0...). + EXPECT_EQ(3 * ((sent_count + 2) % 3), + writer_->stream_frames()[0]->offset); + } else { + // Identify the frames by stream offset (0, 3, 6, 0, 3...). + EXPECT_EQ(3 * (sent_count % 3), + writer_->stream_frames()[0]->offset); + } + sent_count++; + })); + } EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket()) .WillRepeatedly(Return(true)); EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] { @@ -8593,7 +7755,12 @@ TEST_P(QuicConnectionTest, MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(0); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(0); + } EXPECT_CALL(*send_algorithm_, ShouldSendProbingPacket()) .WillRepeatedly(Return(true)); EXPECT_CALL(visitor_, SendProbingData()).WillRepeatedly([this] { @@ -9163,12 +8330,13 @@ TEST_P(QuicConnectionTest, LimitedLargestMessagePayload) { // Test to check that the path challenge/path response logic works // correctly. This test is only for version-99 -TEST_P(QuicConnectionTest, PathChallengeResponse) { +TEST_P(QuicConnectionTest, ServerResponseToPathChallenge) { if (!VersionHasIetfQuicFrames(connection_.version().transport_version)) { return; } - // First check if we can probe from server to client and back - set_perspective(Perspective::IS_SERVER); + PathProbeTestInit(Perspective::IS_SERVER); + QuicConnectionPeer::SetAddressValidated(&connection_); + // First check if the server can send probing packet. QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); // Create and send the probe request (PATH_CHALLENGE frame). @@ -9188,21 +8356,61 @@ TEST_P(QuicConnectionTest, PathChallengeResponse) { // Normally, QuicConnection::OnPathChallengeFrame and OnPaddingFrame would be // called and it will perform actions to ensure that the rest of the protocol - // is performed (specifically, call UpdatePacketContent to say that this is a - // path challenge so that when QuicConnection::OnPacketComplete is called - // (again, out of the framer), the response is generated). Simulate those - // calls so that the right internal state is set up for generating - // the response. + // is performed. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); EXPECT_TRUE(connection_.OnPathChallengeFrame( writer_->path_challenge_frames().front())); EXPECT_TRUE(connection_.OnPaddingFrame(writer_->padding_frames().front())); - // Cause the response to be created and sent. Result is that the response - // should be stashed in writer's path_response_frames. + if (!connection_.send_path_response()) { + connection_.SendConnectivityProbingResponsePacket( + connection_.peer_address()); + } + creator_->FlushCurrentPacket(); + + // The final check is to ensure that the random data in the response matches + // the random data from the challenge. + EXPECT_EQ(1u, writer_->path_response_frames().size()); + EXPECT_EQ(0, memcmp(&challenge_data, + &(writer_->path_response_frames().front().data_buffer), + sizeof(challenge_data))); +} + +TEST_P(QuicConnectionTest, ClientResponseToPathChallenge) { + if (!VersionHasIetfQuicFrames(connection_.version().transport_version) || + !connection_.send_path_response()) { + return; + } + PathProbeTestInit(Perspective::IS_CLIENT); + // First check if the client can send probing packet. + QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); + + // Create and send the probe request (PATH_CHALLENGE frame). + // SendConnectivityProbingPacket ends up calling + // TestPacketWriter::WritePacket() which in turns receives and parses the + // packet by calling framer_.ProcessPacket() -- which in turn calls + // SimpleQuicFramer::OnPathChallengeFrame(). SimpleQuicFramer saves + // the packet in writer_->path_challenge_frames() EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - connection_.SendConnectivityProbingResponsePacket(connection_.peer_address()); + connection_.SendConnectivityProbingPacket(writer_.get(), + connection_.peer_address()); + // Save the random contents of the challenge for later validation against the + // response. + ASSERT_GE(writer_->path_challenge_frames().size(), 1u); + QuicPathFrameBuffer challenge_data = + writer_->path_challenge_frames().front().data_buffer; + + // Normally, QuicConnection::OnPathChallengeFrame would be + // called and it will perform actions to ensure that the rest of the protocol + // is performed. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + EXPECT_TRUE(connection_.OnPathChallengeFrame( + writer_->path_challenge_frames().front())); + EXPECT_TRUE(connection_.OnPaddingFrame(writer_->padding_frames().front())); + creator_->FlushCurrentPacket(); // The final check is to ensure that the random data in the response matches // the random data from the challenge. + EXPECT_EQ(1u, writer_->path_response_frames().size()); EXPECT_EQ(0, memcmp(&challenge_data, &(writer_->path_response_frames().front().data_buffer), sizeof(challenge_data))); @@ -9263,7 +8471,7 @@ TEST_P(QuicConnectionTest, // Simulate path degrading handling by sending a probe on an alternet path. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5)); - TestPacketWriter probing_writer(version(), &clock_); + TestPacketWriter probing_writer(version(), &clock_, Perspective::IS_CLIENT); connection_.SendConnectivityProbingPacket(&probing_writer, connection_.peer_address()); // Verify that path degrading detection is not reset. @@ -9941,8 +9149,9 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter6ClientPTOs) { connection_.SetFromConfig(config); if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { EXPECT_CALL(visitor_, GetHandshakeState()) - .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); } + connection_.OnHandshakeComplete(); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); // Send stream data. @@ -9992,8 +9201,9 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter7ClientPTOs) { connection_.SetFromConfig(config); if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { EXPECT_CALL(visitor_, GetHandshakeState()) - .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); } + connection_.OnHandshakeComplete(); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); // Send stream data. @@ -10042,8 +9252,9 @@ TEST_P(QuicConnectionTest, CloseConnectionAfter8ClientPTOs) { connection_.SetFromConfig(config); if (GetQuicReloadableFlag(quic_default_enable_5rto_blackhole_detection2)) { EXPECT_CALL(visitor_, GetHandshakeState()) - .WillRepeatedly(Return(HANDSHAKE_COMPLETE)); + .WillRepeatedly(Return(HANDSHAKE_CONFIRMED)); } + connection_.OnHandshakeComplete(); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); // Send stream data. @@ -10166,6 +9377,136 @@ TEST_P(QuicConnectionTest, AntiAmplificationLimit) { } } +TEST_P(QuicConnectionTest, 3AntiAmplificationLimit) { + if (!connection_.version().SupportsAntiAmplificationLimit()) { + return; + } + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + + set_perspective(Perspective::IS_SERVER); + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k3AFF); + config.SetInitialReceivedConnectionOptions(connection_options); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId(&config, + QuicConnectionId()); + } + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + + // Verify no data can be sent at the beginning because bytes received is 0. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.SendCryptoDataWithString("foo", 0); + EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)); + EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA)); + EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); + + // Receives packet 1. + ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL); + + const size_t anti_amplification_factor = 3; + // Verify now packets can be sent. + for (size_t i = 0; i < anti_amplification_factor; ++i) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + connection_.SendCryptoDataWithString("foo", i * 3); + // Verify retransmission alarm is not set if throttled by anti-amplification + // limit. + EXPECT_EQ(i != anti_amplification_factor - 1, + connection_.GetRetransmissionAlarm()->IsSet()); + } + // Verify server is throttled by anti-amplification limit. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3); + + // Receives packet 2. + ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL); + // Verify more packets can be sent. + for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2; + ++i) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + connection_.SendCryptoDataWithString("foo", i * 3); + } + // Verify server is throttled by anti-amplification limit. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.SendCryptoDataWithString("foo", + 2 * anti_amplification_factor * 3); + + ProcessPacket(3); + // Verify anti-amplification limit is gone after address validation. + for (size_t i = 0; i < 100; ++i) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + connection_.SendStreamDataWithString(3, "first", i * 0, NO_FIN); + } +} + +TEST_P(QuicConnectionTest, 10AntiAmplificationLimit) { + if (!connection_.version().SupportsAntiAmplificationLimit()) { + return; + } + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + + set_perspective(Perspective::IS_SERVER); + QuicConfig config; + QuicTagVector connection_options; + connection_options.push_back(k10AF); + config.SetInitialReceivedConnectionOptions(connection_options); + if (connection_.version().AuthenticatesHandshakeConnectionIds()) { + QuicConfigPeer::SetReceivedOriginalConnectionId( + &config, connection_.connection_id()); + QuicConfigPeer::SetReceivedInitialSourceConnectionId(&config, + QuicConnectionId()); + } + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + connection_.SetFromConfig(config); + + // Verify no data can be sent at the beginning because bytes received is 0. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.SendCryptoDataWithString("foo", 0); + EXPECT_FALSE(connection_.CanWrite(HAS_RETRANSMITTABLE_DATA)); + EXPECT_FALSE(connection_.CanWrite(NO_RETRANSMITTABLE_DATA)); + EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); + + // Receives packet 1. + ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL); + + const size_t anti_amplification_factor = 10; + // Verify now packets can be sent. + for (size_t i = 0; i < anti_amplification_factor; ++i) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + connection_.SendCryptoDataWithString("foo", i * 3); + // Verify retransmission alarm is not set if throttled by anti-amplification + // limit. + EXPECT_EQ(i != anti_amplification_factor - 1, + connection_.GetRetransmissionAlarm()->IsSet()); + } + // Verify server is throttled by anti-amplification limit. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.SendCryptoDataWithString("foo", anti_amplification_factor * 3); + + // Receives packet 2. + ProcessCryptoPacketAtLevel(2, ENCRYPTION_INITIAL); + // Verify more packets can be sent. + for (size_t i = anti_amplification_factor; i < anti_amplification_factor * 2; + ++i) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + connection_.SendCryptoDataWithString("foo", i * 3); + } + // Verify server is throttled by anti-amplification limit. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + connection_.SendCryptoDataWithString("foo", + 2 * anti_amplification_factor * 3); + + ProcessPacket(3); + // Verify anti-amplification limit is gone after address validation. + for (size_t i = 0; i < 100; ++i) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + connection_.SendStreamDataWithString(3, "first", i * 0, NO_FIN); + } +} + TEST_P(QuicConnectionTest, AckPendingWithAmplificationLimited) { if (!connection_.version().SupportsAntiAmplificationLimit()) { return; @@ -10308,7 +9649,12 @@ TEST_P(QuicConnectionTest, SendCoalescedPackets) { } MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(3); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(3); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(3); + } EXPECT_CALL(debug_visitor, OnCoalescedPacketSent(_, _)).Times(1); EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); { @@ -10350,7 +9696,12 @@ TEST_P(QuicConnectionTest, LegacyVersionEncapsulation) { MockQuicConnectionDebugVisitor debug_visitor; connection_.set_debug_visitor(&debug_visitor); - EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + if (connection_.sent_packet_manager() + .give_sent_packet_to_debug_visitor_after_sent()) { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1); + } else { + EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _)).Times(1); + } // Our TestPacketWriter normally parses the sent packet using the version // from the connection, so here we need to tell it to use the encapsulation @@ -10445,14 +9796,12 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { ? QuicPacketNumber(3) : QuicPacketNumber(4), _, _)); - EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); - connection_.GetRetransmissionAlarm()->Fire(); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - // Verify 1-RTT packet gets coalesced with handshake retransmission. - EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); - } else { - EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); + if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); } + connection_.GetRetransmissionAlarm()->Fire(); + // Verify 1-RTT packet gets coalesced with handshake retransmission. + EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); // Send application data. connection_.SendApplicationDataAtLevel(ENCRYPTION_FORWARD_SECURE, 5, "data", @@ -10466,21 +9815,17 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { QuicPacketNumber handshake_retransmission = GetQuicReloadableFlag(quic_default_on_pto) ? QuicPacketNumber(5) : QuicPacketNumber(7); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - handshake_retransmission += 1; - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, handshake_retransmission + 1, _, _)); - } + handshake_retransmission += 1; + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, _, handshake_retransmission + 1, _, _)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, handshake_retransmission, _, _)); - EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); - connection_.GetRetransmissionAlarm()->Fire(); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - // Verify 1-RTT packet gets coalesced with handshake retransmission. - EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); - } else { - EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); + if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); } + connection_.GetRetransmissionAlarm()->Fire(); + // Verify 1-RTT packet gets coalesced with handshake retransmission. + EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); // Discard handshake key. connection_.OnHandshakeComplete(); @@ -10492,9 +9837,7 @@ TEST_P(QuicConnectionTest, MultiplePacketNumberSpacePto) { QuicPacketNumber application_retransmission = GetQuicReloadableFlag(quic_default_on_pto) ? QuicPacketNumber(6) : QuicPacketNumber(9); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - application_retransmission += 2; - } + application_retransmission += 2; EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, application_retransmission, _, _)); connection_.GetRetransmissionAlarm()->Fire(); @@ -10853,6 +10196,7 @@ TEST_P(QuicConnectionTest, SendPingWhenSkipPacketNumberForPto) { } EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); connection_.SetFromConfig(config); + connection_.OnHandshakeComplete(); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_EQ(MESSAGE_STATUS_SUCCESS, SendMessage("message")); @@ -11209,13 +10553,17 @@ TEST_P(QuicConnectionTest, ProcessUndecryptablePacketsBasedOnEncryptionLevel) { SetDecrypter(ENCRYPTION_HANDSHAKE, std::make_unique<StrictTaggingDecrypter>(0x01)); EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<TaggingEncrypter>(0x01)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); // Verify all ENCRYPTION_HANDSHAKE packets get processed. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(6); connection_.GetProcessUndecryptablePacketsAlarm()->Fire(); - EXPECT_EQ(4u, QuicConnectionPeer::NumUndecryptablePackets(&connection_)); + if (GetQuicReloadableFlag(quic_fix_undecryptable_packets2)) { + EXPECT_EQ(1u, QuicConnectionPeer::NumUndecryptablePackets(&connection_)); + } else { + EXPECT_EQ(4u, QuicConnectionPeer::NumUndecryptablePackets(&connection_)); + } SetDecrypter(ENCRYPTION_FORWARD_SECURE, std::make_unique<StrictTaggingDecrypter>(0x02)); @@ -11254,10 +10602,10 @@ TEST_P(QuicConnectionTest, ServerBundlesInitialDataWithInitialAck) { connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); - } else { + if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } else { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); } connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); // Verify PTO time does not change. @@ -11297,8 +10645,11 @@ TEST_P(QuicConnectionTest, ClientBundlesHandshakeDataWithHandshakeAck) { // Receives packet 1000 in handshake data. ProcessCryptoPacketAtLevel(1000, ENCRYPTION_HANDSHAKE); EXPECT_TRUE(connection_.HasPendingAcks()); - - EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); + if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } else { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); + } connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); // Receives packet 1001 in handshake data. @@ -11361,7 +10712,11 @@ TEST_P(QuicConnectionTest, ServerRetransmitsHandshakeDataEarly) { connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); - EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(3); + if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } else { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(3); + } // Send HANDSHAKE 2 and 3. connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); connection_.SendCryptoDataWithString("bar", 3, ENCRYPTION_HANDSHAKE); @@ -11389,12 +10744,8 @@ TEST_P(QuicConnectionTest, ServerRetransmitsHandshakeDataEarly) { clock_.AdvanceTime(kAlarmGranularity); connection_.GetAckAlarm()->Fire(); EXPECT_FALSE(writer_->ack_frames().empty()); - if (GetQuicReloadableFlag(quic_retransmit_handshake_data_early)) { - // Verify handshake data gets retransmitted early. - EXPECT_FALSE(writer_->crypto_frames().empty()); - } else { - EXPECT_TRUE(writer_->crypto_frames().empty()); - } + // Verify handshake data gets retransmitted early. + EXPECT_FALSE(writer_->crypto_frames().empty()); } // Regression test for b/161228202 @@ -11431,11 +10782,10 @@ TEST_P(QuicConnectionTest, InflatedRttSample) { connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - // Verify HANDSHAKE packet is coalesced with INITIAL retransmission. - EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); - } else { + if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } else { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); } std::string handshake_crypto_data(1024, 'a'); connection_.SendCryptoDataWithString(handshake_crypto_data, 0, @@ -11460,26 +10810,15 @@ TEST_P(QuicConnectionTest, InflatedRttSample) { EXPECT_EQ(kTestRTT, rtt_stats->latest_rtt()); // Because retransmitted INITIAL gets received so HANDSHAKE 2 gets processed. frames.clear(); - QuicAckFrame ack_frame2; - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - // HANDSHAKE 5 is also processed. - ack_frame2 = InitAckFrame( - {{QuicPacketNumber(2), QuicPacketNumber(3)}, - {initial_retransmission + 1, initial_retransmission + 2}}); - } else { - ack_frame2 = InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}}); - } + // HANDSHAKE 5 is also processed. + QuicAckFrame ack_frame2 = + InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}, + {initial_retransmission + 1, initial_retransmission + 2}}); ack_frame2.ack_delay_time = QuicTime::Delta::Zero(); frames.push_back(QuicFrame(&ack_frame2)); ProcessFramesPacketAtLevel(1, frames, ENCRYPTION_HANDSHAKE); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - // Verify RTT inflation gets mitigated. - EXPECT_EQ(rtt_stats->latest_rtt(), kTestRTT); - } else { - // Verify this RTT sample gets inflated as it includes the PTO timeout and - // the actual RTT. - EXPECT_GE(rtt_stats->latest_rtt(), pto_timeout + kTestRTT); - } + // Verify RTT inflation gets mitigated. + EXPECT_EQ(rtt_stats->latest_rtt(), kTestRTT); } // Regression test for b/161228202 @@ -11518,11 +10857,11 @@ TEST_P(QuicConnectionTest, CoalscingPacketCausesInfiniteLoop) { connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); - if (GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2)) { - // Verify HANDSHAKE packet is coalesced with INITIAL retransmission. - EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); - } else { + // Verify HANDSHAKE packet is coalesced with INITIAL retransmission. + if (GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } else { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(2); } std::string handshake_crypto_data(1024, 'a'); connection_.SendCryptoDataWithString(handshake_crypto_data, 0, @@ -11615,6 +10954,7 @@ TEST_P(QuicConnectionTest, SilentIdleTimeout) { } TEST_P(QuicConnectionTest, NoSilentClose) { + SetQuicReloadableFlag(quic_add_silent_idle_timeout, false); set_perspective(Perspective::IS_SERVER); QuicPacketCreatorPeer::SetSendVersionInPacket(creator_, false); if (version().SupportsAntiAmplificationLimit()) { @@ -11641,13 +10981,7 @@ TEST_P(QuicConnectionTest, NoSilentClose) { EXPECT_CALL(visitor_, OnConnectionClosed(_, ConnectionCloseSource::FROM_SELF)); connection_.GetTimeoutAlarm()->Fire(); - if (GetQuicReloadableFlag(quic_no_silent_close_for_idle_timeout)) { - TestConnectionCloseQuicErrorCode(QUIC_NETWORK_IDLE_TIMEOUT); - } else { - // Verify no connection close packet is serialized. - EXPECT_EQ(nullptr, - QuicConnectionPeer::GetConnectionClosePacket(&connection_)); - } + TestConnectionCloseQuicErrorCode(QUIC_NETWORK_IDLE_TIMEOUT); } TEST_P(QuicConnectionTest, DonotSendPing) { @@ -11692,13 +11026,8 @@ TEST_P(QuicConnectionTest, DonotSendPing) { // Suppose now ShouldKeepConnectionAlive returns false. EXPECT_CALL(visitor_, ShouldKeepConnectionAlive()) .WillRepeatedly(Return(false)); - if (GetQuicReloadableFlag(quic_fix_on_ping_timeout)) { - // Verify PING does not get sent. - EXPECT_CALL(visitor_, SendPing()).Times(0); - } else { - // PING get sent even ShouldKeepConnectionAlive returns false. - EXPECT_CALL(visitor_, SendPing()).Times(1); - } + // Verify PING does not get sent. + EXPECT_CALL(visitor_, SendPing()).Times(0); connection_.GetPingAlarm()->Fire(); } @@ -11817,7 +11146,10 @@ TEST_P(QuicConnectionTest, ReserializeInitialPacketInCoalescerAfterDiscardingInitialKey) { SetQuicReloadableFlag( quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded, true); - if (!connection_.version().CanSendCoalescedPackets()) { + if (!connection_.version().CanSendCoalescedPackets() || + !GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + // Cannot set quic_fix_missing_initial_keys in the test since connection_ is + // created since the setup. return; } use_tagging_decrypter(); @@ -11830,15 +11162,17 @@ TEST_P(QuicConnectionTest, connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<TaggingEncrypter>(0x02)); connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() { + connection_.RemoveEncrypter(ENCRYPTION_INITIAL); + connection_.NeuterUnencryptedPackets(); + })); { QuicConnection::ScopedPacketFlusher flusher(&connection_); - connection_.GetAckAlarm()->Fire(); - // Verify this ACK packet is on hold. + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); + // Verify the packet is on hold. EXPECT_EQ(0u, writer_->packets_write_attempts()); - - // Discard INITIAL key while there is an INITIAL packet in the coalescer. - connection_.RemoveEncrypter(ENCRYPTION_INITIAL); - connection_.NeuterUnencryptedPackets(); + // Flush pending ACKs. + connection_.GetAckAlarm()->Fire(); } // If not setting // quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded, there @@ -11849,6 +11183,585 @@ TEST_P(QuicConnectionTest, // crashes). EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(1000, false, ENCRYPTION_FORWARD_SECURE); + EXPECT_TRUE(connection_.connected()); +} + +// Check that if there are two PATH_CHALLENGE frames in the packet, the latter +// one is ignored. +TEST_P(QuicConnectionTest, ReceiveMultiplePathChallenge) { + if (!VersionHasIetfQuicFrames(connection_.version().transport_version)) { + return; + } + PathProbeTestInit(Perspective::IS_SERVER); + + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + + QuicPathFrameBuffer path_frame_buffer1{0, 1, 2, 3, 4, 5, 6, 7}; + QuicPathFrameBuffer path_frame_buffer2{8, 9, 10, 11, 12, 13, 14, 15}; + QuicFrames frames; + frames.push_back( + QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer1))); + frames.push_back( + QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer2))); + const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(), + /*port=*/23456); + + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0); + + // Expect 2 packets to be sent: the first are padded PATH_RESPONSE(s) to the + // alternative peer address. The 2nd is a ACK-only packet to the original + // peer address. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .Times(2) + .WillOnce(Invoke([=]() { + EXPECT_EQ((connection_.send_path_response() ? 1u : 2u), + writer_->path_response_frames().size()); + // The final check is to ensure that the random data in the response + // matches the random data from the challenge. + EXPECT_EQ(0, + memcmp(path_frame_buffer1.data(), + &(writer_->path_response_frames().front().data_buffer), + sizeof(path_frame_buffer1))); + if (!connection_.send_path_response()) { + EXPECT_EQ( + 0, memcmp(path_frame_buffer2.data(), + &(writer_->path_response_frames().back().data_buffer), + sizeof(path_frame_buffer2))); + } else { + EXPECT_EQ(1u, writer_->padding_frames().size()); + } + EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address()); + })) + .WillOnce(Invoke([=]() { + // The last write of ACK-only packet should still use the old peer + // address. + EXPECT_EQ(kPeerAddress, writer_->last_write_peer_address()); + })); + ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress); +} + +TEST_P(QuicConnectionTest, ReceiveStreamFrameBeforePathChallenge) { + if (!VersionHasIetfQuicFrames(connection_.version().transport_version) || + !connection_.send_path_response()) { + return; + } + PathProbeTestInit(Perspective::IS_SERVER); + + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + + QuicFrames frames; + frames.push_back(QuicFrame(frame1_)); + QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7}; + frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer))); + const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(), + /*port=*/23456); + + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)); + EXPECT_CALL(visitor_, OnStreamFrame(_)) + .WillOnce(Invoke([=](const QuicStreamFrame& frame) { + // Send some data on the stream. The STREAM_FRAME should be built into + // one packet together with the latter PATH_RESPONSE. + std::string data{"response body"}; + struct iovec iov; + MakeIOVector(data, &iov); + connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u, + data.length()); + return notifier_.WriteOrBufferData(frame.stream_id, data.length(), + NO_FIN); + })); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); + ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress); + + // Verify that this packet contains a STREAM_FRAME and a + // PATH_RESPONSE_FRAME. + EXPECT_EQ(1u, writer_->stream_frames().size()); + EXPECT_EQ(1u, writer_->path_response_frames().size()); + // The final check is to ensure that the random data in the response + // matches the random data from the challenge. + EXPECT_EQ(0, memcmp(path_frame_buffer.data(), + &(writer_->path_response_frames().front().data_buffer), + sizeof(path_frame_buffer))); + EXPECT_EQ(1u, writer_->padding_frames().size()); + EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address()); +} + +TEST_P(QuicConnectionTest, ReceiveStreamFrameFollowingPathChallenge) { + if (!VersionHasIetfQuicFrames(connection_.version().transport_version) || + !connection_.send_path_response()) { + return; + } + PathProbeTestInit(Perspective::IS_SERVER); + + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + + QuicFrames frames; + QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7}; + frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer))); + // PATH_RESPONSE should be flushed out before the rest packet is parsed. + frames.push_back(QuicFrame(frame1_)); + const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(), + /*port=*/23456); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(Invoke([=]() { + // Verify that this packet contains a PATH_RESPONSE_FRAME. + EXPECT_EQ(0u, writer_->stream_frames().size()); + EXPECT_EQ(1u, writer_->path_response_frames().size()); + // The final check is to ensure that the random data in the response + // matches the random data from the challenge. + EXPECT_EQ(0, + memcmp(path_frame_buffer.data(), + &(writer_->path_response_frames().front().data_buffer), + sizeof(path_frame_buffer))); + EXPECT_EQ(1u, writer_->padding_frames().size()); + EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address()); + })) + .WillOnce(Invoke([=]() { + // Verify that this packet contains a STREAM_FRAME. + EXPECT_EQ(1u, writer_->stream_frames().size()); + EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address()); + })); + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)); + EXPECT_CALL(visitor_, OnStreamFrame(_)) + .WillOnce(Invoke([=](const QuicStreamFrame& frame) { + // Send some data on the stream. The STREAM_FRAME should be built into + // one packet together with the latter PATH_RESPONSE. + std::string data{"response body"}; + struct iovec iov; + MakeIOVector(data, &iov); + connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u, + data.length()); + return notifier_.WriteOrBufferData(frame.stream_id, data.length(), + NO_FIN); + })); + + ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress); +} + +// Tests that a PATH_CHALLENGE is received in between other frames in an out of +// order packet. +TEST_P(QuicConnectionTest, PathChallengeWithDataInOutOfOrderPacket) { + if (!VersionHasIetfQuicFrames(connection_.version().transport_version) || + !connection_.send_path_response()) { + return; + } + PathProbeTestInit(Perspective::IS_SERVER); + + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + + QuicFrames frames; + frames.push_back(QuicFrame(frame1_)); + QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7}; + frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer))); + frames.push_back(QuicFrame(frame2_)); + const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(), + /*port=*/23456); + + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0u); + EXPECT_CALL(visitor_, OnStreamFrame(_)) + .Times(2) + .WillRepeatedly(Invoke([=](const QuicStreamFrame& frame) { + // Send some data on the stream. The STREAM_FRAME should be built into + // one packet together with the latter PATH_RESPONSE. + std::string data{"response body"}; + struct iovec iov; + MakeIOVector(data, &iov); + connection_.producer()->SaveStreamData(frame.stream_id, &iov, 1, 0u, + data.length()); + return notifier_.WriteOrBufferData(frame.stream_id, data.length(), + NO_FIN); + })); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) + .WillOnce(Invoke([=]() { + // Verify that this packet contains a STREAM_FRAME and is sent to the + // original peer address. + EXPECT_EQ(1u, writer_->stream_frames().size()); + // No connection migration should happen because the packet is received + // out of order. + EXPECT_EQ(kPeerAddress, writer_->last_write_peer_address()); + })) + .WillOnce(Invoke([=]() { + EXPECT_EQ(1u, writer_->path_response_frames().size()); + // The final check is to ensure that the random data in the response + // matches the random data from the challenge. + EXPECT_EQ(0, + memcmp(path_frame_buffer.data(), + &(writer_->path_response_frames().front().data_buffer), + sizeof(path_frame_buffer))); + EXPECT_EQ(1u, writer_->padding_frames().size()); + // PATH_RESPONSE should be sent in another packet to a different peer + // address. + EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address()); + })) + .WillOnce(Invoke([=]() { + // Verify that this packet contains a STREAM_FRAME and is sent to the + // original peer address. + EXPECT_EQ(1u, writer_->stream_frames().size()); + // No connection migration should happen because the packet is received + // out of order. + EXPECT_EQ(kPeerAddress, writer_->last_write_peer_address()); + })); + // Lower the packet number so that receiving this packet shouldn't trigger + // peer migration. + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1); + ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress); +} + +// Tests that a PATH_CHALLENGE is cached if its PATH_RESPONSE can't be sent. +TEST_P(QuicConnectionTest, FailToWritePathResponse) { + if (!VersionHasIetfQuicFrames(connection_.version().transport_version) || + !connection_.send_path_response()) { + return; + } + PathProbeTestInit(Perspective::IS_SERVER); + + // Clear direct_peer_address. + QuicConnectionPeer::SetDirectPeerAddress(&connection_, QuicSocketAddress()); + // Clear effective_peer_address, it is the same as direct_peer_address for + // this test. + QuicConnectionPeer::SetEffectivePeerAddress(&connection_, + QuicSocketAddress()); + EXPECT_FALSE(connection_.effective_peer_address().IsInitialized()); + + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } else { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + } + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 2); + ProcessFramePacketWithAddresses(MakeCryptoFrame(), kSelfAddress, + kPeerAddress); + EXPECT_EQ(kPeerAddress, connection_.peer_address()); + EXPECT_EQ(kPeerAddress, connection_.effective_peer_address()); + + QuicFrames frames; + QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7}; + frames.push_back(QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer))); + const QuicSocketAddress kNewPeerAddress(QuicIpAddress::Loopback6(), + /*port=*/23456); + + EXPECT_CALL(visitor_, OnConnectionMigration(PORT_CHANGE)).Times(0u); + // Lower the packet number so that receiving this packet shouldn't trigger + // peer migration. + QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 1); + EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1)); + writer_->SetWriteBlocked(); + ProcessFramesPacketWithAddresses(frames, kSelfAddress, kNewPeerAddress); + + EXPECT_EQ( + 1u, + QuicConnectionPeer::pending_path_challenge_payloads(&connection_).size()); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1)); + writer_->SetWritable(); + connection_.OnCanWrite(); + EXPECT_EQ(1u, writer_->path_response_frames().size()); + // The final check is to ensure that the random data in the response + // matches the random data from the challenge. + EXPECT_EQ(0, memcmp(path_frame_buffer.data(), + &(writer_->path_response_frames().front().data_buffer), + sizeof(path_frame_buffer))); + EXPECT_EQ(1u, writer_->padding_frames().size()); + // PATH_RESPONSE should be sent in another packet to a different peer + // address. + EXPECT_EQ(kNewPeerAddress, writer_->last_write_peer_address()); + EXPECT_TRUE(QuicConnectionPeer::pending_path_challenge_payloads(&connection_) + .empty()); +} + +// Regression test for b/168101557. +TEST_P(QuicConnectionTest, HandshakeDataDoesNotGetPtoed) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + set_perspective(Perspective::IS_SERVER); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + use_tagging_decrypter(); + ProcessCryptoPacketAtLevel(1, ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.HasPendingAcks()); + + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + // Send INITIAL 1. + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_INITIAL); + + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + SetDecrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<StrictTaggingDecrypter>(0x02)); + // Send HANDSHAKE packets. + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + connection_.SendCryptoDataWithString("foo", 0, ENCRYPTION_HANDSHAKE); + + connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingEncrypter>(0x03)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + // Send half RTT packet. + connection_.SendStreamDataWithString(2, "foo", 0, NO_FIN); + + // Receives HANDSHAKE 1. + peer_framer_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + ProcessCryptoPacketAtLevel(1, ENCRYPTION_HANDSHAKE); + // Discard INITIAL key. + connection_.RemoveEncrypter(ENCRYPTION_INITIAL); + connection_.NeuterUnencryptedPackets(); + // Verify there is pending ACK. + ASSERT_TRUE(connection_.HasPendingAcks()); + // Set the send alarm. + connection_.GetSendAlarm()->Set(clock_.ApproximateNow()); + + // Fire ACK alarm. + if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } + connection_.GetAckAlarm()->Fire(); + if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) { + // Verify 1-RTT packet is coalesced with handshake packet. + EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet()); + } else { + // Verify handshake crypto frame is not bundled. + EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); + EXPECT_FALSE(writer_->ack_frames().empty()); + EXPECT_TRUE(writer_->crypto_frames().empty()); + } + connection_.GetSendAlarm()->Fire(); + + ASSERT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); + if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) { + if (!GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1); + } + } else { + EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(0); + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { + SendPing(); + })); + } + connection_.GetRetransmissionAlarm()->Fire(); + if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count)) { + // Verify a handshake packet gets PTOed and 1-RTT packet gets coalesced. + EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet()); + } else { + // Verify an 1-RTT PING gets sent because there is nothing to PTO, bummer, + // since this 1-RTT PING cannot be processed by peer and there is a + // deadlock. + EXPECT_EQ(0x03030303u, writer_->final_bytes_of_last_packet()); + EXPECT_FALSE(writer_->ping_frames().empty()); + } +} + +// Regression test for b/168294218. +TEST_P(QuicConnectionTest, CoalescerHandlesInitialKeyDiscard) { + if (!connection_.version().CanSendCoalescedPackets() || + !GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + return; + } + SetQuicReloadableFlag(quic_discard_initial_packet_with_key_dropped, true); + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() { + connection_.RemoveEncrypter(ENCRYPTION_INITIAL); + connection_.NeuterUnencryptedPackets(); + })); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + + EXPECT_EQ(0u, connection_.GetStats().packets_discarded); + { + QuicConnection::ScopedPacketFlusher flusher(&connection_); + use_tagging_decrypter(); + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + connection_.SendCryptoDataWithString(std::string(1300, 'a'), 0); + // Verify this packet is on hold. + EXPECT_EQ(0u, writer_->packets_write_attempts()); + } + EXPECT_TRUE(connection_.connected()); +} + +// Regresstion test for b/168294218 +TEST_P(QuicConnectionTest, ZeroRttRejectionAndMissingInitialKeys) { + if (!connection_.SupportsMultiplePacketNumberSpaces() || + !GetQuicReloadableFlag(quic_fix_missing_initial_keys2)) { + return; + } + // Not defer send in response to packet. + connection_.set_defer_send_in_response_to_packets(false); + EXPECT_CALL(visitor_, OnHandshakePacketSent()).WillOnce(Invoke([this]() { + connection_.RemoveEncrypter(ENCRYPTION_INITIAL); + connection_.NeuterUnencryptedPackets(); + })); + EXPECT_CALL(visitor_, OnCryptoFrame(_)) + .WillRepeatedly(Invoke([=](const QuicCryptoFrame& frame) { + if (frame.level == ENCRYPTION_HANDSHAKE) { + // 0-RTT gets rejected. + connection_.MarkZeroRttPacketsForRetransmission(0); + // Send Crypto data. + connection_.SetEncrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingEncrypter>(0x03)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); + connection_.SendCryptoStreamData(); + connection_.SetEncrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingEncrypter>(0x04)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + // Retransmit rejected 0-RTT packets. + connection_.OnCanWrite(); + // Advance INITIAL ack delay to trigger initial ACK to be sent AFTER + // the retransmission of rejected 0-RTT packets while the HANDSHAKE + // packet is still in the coalescer, such that the INITIAL key gets + // dropped between SendAllPendingAcks and actually send the ack frame, + // bummer. + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); + } + })); + use_tagging_decrypter(); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SendCryptoStreamData(); + // Send 0-RTT packet. + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + connection_.SendStreamDataWithString(2, "foo", 0, NO_FIN); + + QuicAckFrame frame1 = InitAckFrame(1); + // Received ACK for packet 1. + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)); + ProcessFramePacketAtLevel(1, QuicFrame(&frame1), ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); + + // Fire retransmission alarm. + EXPECT_CALL(visitor_, SendPing()).WillOnce(Invoke([this]() { SendPing(); })); + connection_.GetRetransmissionAlarm()->Fire(); + + QuicFrames frames1; + frames1.push_back(QuicFrame(&crypto_frame_)); + QuicFrames frames2; + QuicCryptoFrame crypto_frame(ENCRYPTION_HANDSHAKE, 0, + quiche::QuicheStringPiece(data1)); + frames2.push_back(QuicFrame(&crypto_frame)); + ProcessCoalescedPacket( + {{2, frames1, ENCRYPTION_INITIAL}, {3, frames2, ENCRYPTION_HANDSHAKE}}); +} + +TEST_P(QuicConnectionTest, OnZeroRttPacketAcked) { + if (!connection_.version().UsesTls()) { + return; + } + MockQuicConnectionDebugVisitor debug_visitor; + connection_.set_debug_visitor(&debug_visitor); + use_tagging_decrypter(); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x01)); + connection_.SendCryptoStreamData(); + // Send 0-RTT packet. + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<TaggingEncrypter>(0x02)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + connection_.SendStreamDataWithString(2, "foo", 0, NO_FIN); + connection_.SendStreamDataWithString(4, "bar", 0, NO_FIN); + // Received ACK for packet 1, HANDSHAKE packet and 1-RTT ACK. + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)) + .Times(AnyNumber()); + QuicFrames frames1; + QuicAckFrame ack_frame1 = InitAckFrame(1); + frames1.push_back(QuicFrame(&ack_frame1)); + + QuicFrames frames2; + QuicCryptoFrame crypto_frame(ENCRYPTION_HANDSHAKE, 0, + quiche::QuicheStringPiece(data1)); + frames2.push_back(QuicFrame(&crypto_frame)); + EXPECT_CALL(debug_visitor, OnZeroRttPacketAcked()).Times(0); + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(1); + ProcessCoalescedPacket( + {{1, frames1, ENCRYPTION_INITIAL}, {2, frames2, ENCRYPTION_HANDSHAKE}}); + + QuicFrames frames3; + QuicAckFrame ack_frame2 = + InitAckFrame({{QuicPacketNumber(2), QuicPacketNumber(3)}}); + frames3.push_back(QuicFrame(&ack_frame2)); + EXPECT_CALL(debug_visitor, OnZeroRttPacketAcked()).Times(1); + ProcessCoalescedPacket({{3, frames3, ENCRYPTION_FORWARD_SECURE}}); + + QuicFrames frames4; + QuicAckFrame ack_frame3 = + InitAckFrame({{QuicPacketNumber(3), QuicPacketNumber(4)}}); + frames4.push_back(QuicFrame(&ack_frame3)); + EXPECT_CALL(debug_visitor, OnZeroRttPacketAcked()).Times(0); + ProcessCoalescedPacket({{4, frames4, ENCRYPTION_FORWARD_SECURE}}); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc index ba000156b79..28b3446fb02 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.cc @@ -6,6 +6,8 @@ #include <string> +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_frame.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" @@ -103,8 +105,9 @@ void QuicControlFrameManager::WriteOrBufferMaxStreams(QuicStreamCount count, QuicMaxStreamsFrame(++last_control_frame_id_, count, unidirectional))); } -void QuicControlFrameManager::WriteOrBufferStopSending(uint16_t code, - QuicStreamId stream_id) { +void QuicControlFrameManager::WriteOrBufferStopSending( + QuicRstStreamErrorCode code, + QuicStreamId stream_id) { QUIC_DVLOG(1) << "Writing STOP_SENDING_FRAME"; WriteOrBufferQuicFrame(QuicFrame( new QuicStopSendingFrame(++last_control_frame_id_, stream_id, code))); @@ -116,6 +119,16 @@ void QuicControlFrameManager::WriteOrBufferHandshakeDone() { QuicFrame(QuicHandshakeDoneFrame(++last_control_frame_id_))); } +void QuicControlFrameManager::WriteOrBufferAckFrequency( + uint64_t packet_tolerance, + QuicTime::Delta max_ack_delay) { + QUIC_DVLOG(1) << "Writing ACK_FREQUENCY frame"; + QuicControlFrameId control_frame_id = ++last_control_frame_id_; + WriteOrBufferQuicFrame(QuicFrame(new QuicAckFrequencyFrame( + control_frame_id, + /*sequence_number=*/control_frame_id, packet_tolerance, max_ack_delay))); +} + void QuicControlFrameManager::WritePing() { QUIC_DVLOG(1) << "Writing PING_FRAME"; if (HasBufferedFrames()) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h index 76157549562..d79b679c984 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager.h @@ -77,12 +77,18 @@ class QUIC_EXPORT_PRIVATE QuicControlFrameManager { // Tries to send an IETF-QUIC STOP_SENDING frame. The frame is buffered if it // can not be sent immediately. - void WriteOrBufferStopSending(uint16_t code, QuicStreamId stream_id); + void WriteOrBufferStopSending(QuicRstStreamErrorCode code, + QuicStreamId stream_id); // Tries to send an HANDSHAKE_DONE frame. The frame is buffered if it can not // be sent immediately. void WriteOrBufferHandshakeDone(); + // Tries to send an AckFrequencyFrame. The frame is buffered if it cannot be + // sent immediately. + void WriteOrBufferAckFrequency(uint64_t packet_tolerance, + QuicTime::Delta max_ack_delay); + // Sends a PING_FRAME. Do not send PING if there is buffered frames. void WritePing(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc index f8e9932f4e5..68176997944 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_control_frame_manager_test.cc @@ -6,6 +6,7 @@ #include <utility> +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" @@ -31,7 +32,8 @@ class QuicControlFrameManagerPeer { namespace { const QuicStreamId kTestStreamId = 5; -const QuicStreamId kTestStopSendingCode = 321; +const QuicRstStreamErrorCode kTestStopSendingCode = + QUIC_STREAM_ENCODER_STREAM_ERROR; class QuicControlFrameManagerTest : public QuicTest { public: @@ -230,6 +232,29 @@ TEST_F(QuicControlFrameManagerTest, DonotSendPingWithBufferedFrames) { EXPECT_FALSE(manager_->WillingToWrite()); } +TEST_F(QuicControlFrameManagerTest, SendAndAckAckFrequencyFrame) { + Initialize(); + InSequence s; + // Send Non-AckFrequency frame 1-5. + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(5) + .WillRepeatedly(Invoke(&ClearControlFrame)); + EXPECT_CALL(*connection_, SendControlFrame(_)).WillOnce(Return(false)); + manager_->OnCanWrite(); + + // Send AckFrequencyFrame as frame 6. + QuicAckFrequencyFrame ack_frequency = {6, 6, 10, + QuicTime::Delta::FromMilliseconds(24)}; + manager_->WriteOrBufferAckFrequency(10, + QuicTime::Delta::FromMilliseconds(24)); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&ClearControlFrame)); + manager_->OnCanWrite(); + + // Ack AckFrequencyFrame. + EXPECT_TRUE(manager_->OnControlFrameAcked(QuicFrame(&ack_frequency))); +} + TEST_F(QuicControlFrameManagerTest, DonotRetransmitOldWindowUpdates) { Initialize(); // Send two more window updates of the same stream. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc index 72769372318..b60b02643b6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.cc @@ -128,6 +128,10 @@ bool QuicCryptoClientHandshaker::EarlyDataAccepted() const { return num_client_hellos_ == 1; } +ssl_early_data_reason_t QuicCryptoClientHandshaker::EarlyDataReason() const { + return early_data_reason_; +} + bool QuicCryptoClientHandshaker::ReceivedInchoateReject() const { QUIC_BUG_IF(!one_rtt_keys_available_); return num_client_hellos_ >= 3; @@ -290,9 +294,16 @@ void QuicCryptoClientHandshaker::DoSendCHLO( // inchoate or subsequent hello. session()->config()->ToHandshakeMessage(&out, session()->transport_version()); - if (!cached->IsComplete(session()->connection()->clock()->WallNow()) || - session()->config()->HasClientRequestedIndependentOption( - kQNZR, session()->perspective())) { + bool fill_inchoate_client_hello = false; + if (!cached->IsComplete(session()->connection()->clock()->WallNow())) { + early_data_reason_ = ssl_early_data_no_session_offered; + fill_inchoate_client_hello = true; + } else if (session()->config()->HasClientRequestedIndependentOption( + kQNZR, session()->perspective())) { + early_data_reason_ = ssl_early_data_disabled; + fill_inchoate_client_hello = true; + } + if (fill_inchoate_client_hello) { crypto_config_->FillInchoateClientHello( server_id_, session()->supported_versions().front(), cached, session()->connection()->random_generator(), @@ -356,6 +367,9 @@ void QuicCryptoClientHandshaker::DoSendCHLO( /*latch_once_used=*/true); encryption_established_ = true; delegate_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + if (early_data_reason_ == ssl_early_data_unknown && num_client_hellos_ > 1) { + early_data_reason_ = ssl_early_data_peer_declined; + } } void QuicCryptoClientHandshaker::DoReceiveREJ( @@ -531,6 +545,9 @@ void QuicCryptoClientHandshaker::DoReceiveSHLO( "unencrypted SHLO message"); return; } + if (num_client_hellos_ == 1) { + early_data_reason_ = ssl_early_data_accepted; + } std::string error_details; QuicErrorCode error = crypto_config_->ProcessServerHello( diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h index 90f011dd053..605318edc06 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_handshaker.h @@ -40,6 +40,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker int num_sent_client_hellos() const override; bool IsResumption() const override; bool EarlyDataAccepted() const override; + ssl_early_data_reason_t EarlyDataReason() const override; bool ReceivedInchoateReject() const override; int num_scup_messages_received() const override; std::string chlo_hash() const override; @@ -153,6 +154,8 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientHandshaker // connection has sent. int num_client_hellos_; + ssl_early_data_reason_t early_data_reason_ = ssl_early_data_unknown; + QuicCryptoClientConfig* const crypto_config_; // SHA-256 hash of the most recently sent CHLO. diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc index 62a261d1fc1..67a9a113510 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.cc @@ -71,6 +71,10 @@ bool QuicCryptoClientStream::EarlyDataAccepted() const { return handshaker_->EarlyDataAccepted(); } +ssl_early_data_reason_t QuicCryptoClientStream::EarlyDataReason() const { + return handshaker_->EarlyDataReason(); +} + bool QuicCryptoClientStream::ReceivedInchoateReject() const { return handshaker_->ReceivedInchoateReject(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h index be99fb2b949..1d9b04b35fc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream.h @@ -116,6 +116,10 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream // Returns true if early data (0-RTT) was accepted in the connection. virtual bool EarlyDataAccepted() const = 0; + // Returns the ssl_early_data_reason_t describing why 0-RTT was accepted or + // rejected. + virtual ssl_early_data_reason_t EarlyDataReason() const = 0; + // Returns true if the client received an inchoate REJ during the handshake, // extending the handshake by one round trip. This only applies for QUIC // crypto handshakes. The equivalent feature in IETF QUIC is a Retry packet, @@ -203,6 +207,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoClientStream int num_sent_client_hellos() const override; bool IsResumption() const override; bool EarlyDataAccepted() const override; + ssl_early_data_reason_t EarlyDataReason() const override; bool ReceivedInchoateReject() const override; int num_scup_messages_received() const override; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc index 7f6d7770eb6..52791b3d8e1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_client_stream_test.cc @@ -107,6 +107,7 @@ TEST_F(QuicCryptoClientStreamTest, ConnectedAfterSHLO) { EXPECT_TRUE(stream()->encryption_established()); EXPECT_TRUE(stream()->one_rtt_keys_available()); EXPECT_FALSE(stream()->IsResumption()); + EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_no_session_offered); } TEST_F(QuicCryptoClientStreamTest, MessageAfterHandshake) { @@ -179,6 +180,7 @@ TEST_F(QuicCryptoClientStreamTest, ClientTurnedOffZeroRtt) { // Check that a client hello was sent. ASSERT_EQ(1u, connection_->encrypted_packets_.size()); EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); + EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_disabled); } TEST_F(QuicCryptoClientStreamTest, ClockSkew) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc index 665cae10efb..5fc683944ab 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.cc @@ -360,6 +360,16 @@ bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID( return true; } +ssl_early_data_reason_t QuicCryptoServerStream::EarlyDataReason() const { + if (IsZeroRtt()) { + return ssl_early_data_accepted; + } + if (zero_rtt_attempted_) { + return ssl_early_data_session_not_resumed; + } + return ssl_early_data_no_session_offered; +} + bool QuicCryptoServerStream::encryption_established() const { return encryption_established_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h index 5a4b9b1428d..29d680ec98d 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h @@ -51,6 +51,7 @@ class QUIC_EXPORT_PRIVATE QuicCryptoServerStream const ProofSource::Details* ProofSourceDetails() const override; // From QuicCryptoStream + ssl_early_data_reason_t EarlyDataReason() const override; bool encryption_established() const override; bool one_rtt_keys_available() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h index 54d1b2525c2..d73d97080a8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream.h @@ -9,6 +9,7 @@ #include <cstddef> #include <string> +#include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" @@ -72,6 +73,13 @@ class QUIC_EXPORT_PRIVATE QuicCryptoStream : public QuicStream { virtual void WriteCryptoData(EncryptionLevel level, quiche::QuicheStringPiece data); + // Returns the ssl_early_data_reason_t describing why 0-RTT was accepted or + // rejected. Note that the value returned by this function may vary during the + // handshake. Once |one_rtt_keys_available| returns true, the value returned + // by this function will not change for the rest of the lifetime of the + // QuicCryptoStream. + virtual ssl_early_data_reason_t EarlyDataReason() const = 0; + // Returns true once an encrypter has been set for the connection. virtual bool encryption_established() const = 0; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc index f763d2d4782..f7e24830943 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_crypto_stream_test.cc @@ -46,6 +46,9 @@ class MockQuicCryptoStream : public QuicCryptoStream, std::vector<CryptoHandshakeMessage>* messages() { return &messages_; } + ssl_early_data_reason_t EarlyDataReason() const override { + return ssl_early_data_unknown; + } bool encryption_established() const override { return false; } bool one_rtt_keys_available() const override { return false; } @@ -218,15 +221,18 @@ TEST_F(QuicCryptoStreamTest, RetransmitCryptoDataInCryptoFrames) { &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_INITIAL, data); // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. - connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); std::unique_ptr<NullEncrypter> encrypter = std::make_unique<NullEncrypter>(Perspective::IS_CLIENT); connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter)); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level()); EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data); + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); @@ -274,15 +280,18 @@ TEST_F(QuicCryptoStreamTest, RetransmitEncryptionHandshakeLevelCryptoFrames) { &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_INITIAL, data); // Send [1000, 2000) in ENCRYPTION_HANDSHAKE. - connection_->SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); std::unique_ptr<NullEncrypter> encrypter = std::make_unique<NullEncrypter>(Perspective::IS_CLIENT); connection_->SetEncrypter(ENCRYPTION_HANDSHAKE, std::move(encrypter)); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_HANDSHAKE); EXPECT_EQ(ENCRYPTION_HANDSHAKE, connection_->encryption_level()); EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_HANDSHAKE, 1000, 0)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_HANDSHAKE, data); + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); @@ -350,6 +359,9 @@ TEST_F(QuicCryptoStreamTest, NeuterUnencryptedCryptoData) { &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_INITIAL, data); // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. + connection_->SetEncrypter( + ENCRYPTION_ZERO_RTT, + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); std::unique_ptr<NullEncrypter> encrypter = std::make_unique<NullEncrypter>(Perspective::IS_CLIENT); @@ -464,15 +476,18 @@ TEST_F(QuicCryptoStreamTest, RetransmitStreamDataWithCryptoFrames) { &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_INITIAL, data); // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. - connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); std::unique_ptr<NullEncrypter> encrypter = std::make_unique<NullEncrypter>(Perspective::IS_CLIENT); connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter)); + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level()); EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0)) .WillOnce(Invoke(connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data); + connection_->SetEncrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); @@ -588,6 +603,9 @@ TEST_F(QuicCryptoStreamTest, WriteBufferedCryptoFrames) { // Send [1350, 2700) in ENCRYPTION_ZERO_RTT and verify no write is attempted // because there is buffered data. EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0); + connection_->SetEncrypter( + ENCRYPTION_ZERO_RTT, + std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data); EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level()); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc index 7275adfe506..972a9ac0f86 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher.cc @@ -194,14 +194,10 @@ class ChloAlpnExtractor : public ChloExtractor::Delegate { if (chlo.GetStringPiece(kALPN, &alpn_value)) { alpn_ = std::string(alpn_value); } - if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation, - 1, 3); - if (version == LegacyVersionForEncapsulation().transport_version) { - quiche::QuicheStringPiece qlve_value; - if (chlo.GetStringPiece(kQLVE, &qlve_value)) { - legacy_version_encapsulation_inner_packet_ = std::string(qlve_value); - } + if (version == LegacyVersionForEncapsulation().transport_version) { + quiche::QuicheStringPiece qlve_value; + if (chlo.GetStringPiece(kQLVE, &qlve_value)) { + legacy_version_encapsulation_inner_packet_ = std::string(qlve_value); } } } @@ -209,7 +205,6 @@ class ChloAlpnExtractor : public ChloExtractor::Delegate { std::string&& ConsumeAlpn() { return std::move(alpn_); } std::string&& ConsumeLegacyVersionEncapsulationInnerPacket() { - DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)); return std::move(legacy_version_encapsulation_inner_packet_); } @@ -222,7 +217,6 @@ bool MaybeHandleLegacyVersionEncapsulation( QuicDispatcher* dispatcher, ChloAlpnExtractor* alpn_extractor, const ReceivedPacketInfo& packet_info) { - DCHECK(GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)); std::string legacy_version_encapsulation_inner_packet = alpn_extractor->ConsumeLegacyVersionEncapsulationInnerPacket(); if (legacy_version_encapsulation_inner_packet.empty()) { @@ -489,23 +483,19 @@ bool QuicDispatcher::MaybeDispatchPacket( auto it = session_map_.find(server_connection_id); if (it != session_map_.end()) { DCHECK(!buffered_packets_.HasBufferedPackets(server_connection_id)); - if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_dispatcher_legacy_version_encapsulation, - 2, 3); - if (packet_info.version_flag && - packet_info.version != it->second->version() && - packet_info.version == LegacyVersionForEncapsulation()) { - // This packet is using the Legacy Version Encapsulation version but the - // corresponding session isn't, attempt extraction of inner packet. - ChloAlpnExtractor alpn_extractor; - if (ChloExtractor::Extract(packet_info.packet, packet_info.version, - config_->create_session_tag_indicators(), - &alpn_extractor, - server_connection_id.length())) { - if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, - packet_info)) { - return true; - } + if (packet_info.version_flag && + packet_info.version != it->second->version() && + packet_info.version == LegacyVersionForEncapsulation()) { + // This packet is using the Legacy Version Encapsulation version but the + // corresponding session isn't, attempt extraction of inner packet. + ChloAlpnExtractor alpn_extractor; + if (ChloExtractor::Extract(packet_info.packet, packet_info.version, + config_->create_session_tag_indicators(), + &alpn_extractor, + server_connection_id.length())) { + if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, + packet_info)) { + return true; } } } @@ -676,14 +666,11 @@ void QuicDispatcher::ProcessHeader(ReceivedPacketInfo* packet_info) { break; } - if (GetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation)) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_dispatcher_legacy_version_encapsulation, 3, 3); - if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, - *packet_info)) { - break; - } + if (MaybeHandleLegacyVersionEncapsulation(this, &alpn_extractor, + *packet_info)) { + break; } + ProcessChlo({alpn_extractor.ConsumeAlpn()}, packet_info); } break; case kFateTimeWait: diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc index 1fa601f71c8..e90489a9f93 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_dispatcher_test.cc @@ -587,7 +587,6 @@ TEST_P(QuicDispatcherTestAllVersions, LegacyVersionEncapsulation) { // is not currently supported in QuicDispatcher. return; } - SetQuicReloadableFlag(quic_dispatcher_legacy_version_encapsulation, true); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId server_connection_id = TestConnectionId(); QuicConfig client_config = DefaultQuicConfig(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc index cf153e3eea7..8a075984be1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.cc @@ -7,6 +7,7 @@ #include "third_party/boringssl/src/include/openssl/ssl.h" #include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_client_stats.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" @@ -207,6 +208,7 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_HTTP_ZERO_RTT_REJECTION_SETTINGS_MISMATCH); RETURN_STRING_LITERAL(QUIC_HTTP_GOAWAY_INVALID_STREAM_ID); RETURN_STRING_LITERAL(QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS); + RETURN_STRING_LITERAL(QUIC_HTTP_RECEIVE_SPDY_SETTING); RETURN_STRING_LITERAL(QUIC_HPACK_INDEX_VARINT_ERROR); RETURN_STRING_LITERAL(QUIC_HPACK_NAME_LENGTH_VARINT_ERROR); RETURN_STRING_LITERAL(QUIC_HPACK_VALUE_LENGTH_VARINT_ERROR); @@ -229,6 +231,7 @@ const char* QuicErrorCodeToString(QuicErrorCode error) { RETURN_STRING_LITERAL(QUIC_ZERO_RTT_REJECTION_LIMIT_REDUCED); RETURN_STRING_LITERAL(QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED); RETURN_STRING_LITERAL(QUIC_SILENT_IDLE_TIMEOUT); + RETURN_STRING_LITERAL(QUIC_MISSING_WRITE_KEYS); RETURN_STRING_LITERAL(QUIC_LAST_ERROR); // Intentionally have no default case, so we'll break the build @@ -585,6 +588,8 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode( return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)}; case QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS: return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR)}; + case QUIC_HTTP_RECEIVE_SPDY_SETTING: + return {false, static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR)}; case QUIC_HPACK_INDEX_VARINT_ERROR: return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; case QUIC_HPACK_NAME_LENGTH_VARINT_ERROR: @@ -623,6 +628,8 @@ QuicErrorCodeToIetfMapping QuicErrorCodeToTransportErrorCode( return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; case QUIC_ZERO_RTT_RESUMPTION_LIMIT_REDUCED: return {true, static_cast<uint64_t>(PROTOCOL_VIOLATION)}; + case QUIC_MISSING_WRITE_KEYS: + return {true, static_cast<uint64_t>(INTERNAL_ERROR)}; case QUIC_LAST_ERROR: return {false, static_cast<uint64_t>(QUIC_LAST_ERROR)}; } @@ -763,6 +770,13 @@ QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode( return QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE; } +void RecordFailToSerializePacketLocation( + QuicFailToSerializePacketLocation location) { + QUIC_CLIENT_HISTOGRAM_ENUM("QuicSession.FailToSerializePacketLocation", + location, kMaxFailLocationValue, + "The reason why a packet fails to serialize"); +} + #undef RETURN_STRING_LITERAL // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h index b57eaa76080..180dff7baf1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes.h @@ -442,6 +442,9 @@ enum QuicErrorCode { QUIC_HTTP_GOAWAY_INVALID_STREAM_ID = 166, // Received GOAWAY frame with ID that is greater than previously received ID. QUIC_HTTP_GOAWAY_ID_LARGER_THAN_PREVIOUS = 167, + // HTTP/3 session received SETTINGS frame which contains HTTP/2 specific + // settings. + QUIC_HTTP_RECEIVE_SPDY_SETTING = 169, // HPACK header block decoding errors. // Index varint beyond implementation limit. @@ -492,8 +495,11 @@ enum QuicErrorCode { // The connection silently timed out due to no network activity. QUIC_SILENT_IDLE_TIMEOUT = 168, + // Try to write data without the right write keys. + QUIC_MISSING_WRITE_KEYS = 170, + // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 169, + QUIC_LAST_ERROR = 171, }; // QuicErrorCodes is encoded as four octets on-the-wire when doing Google QUIC, // or a varint62 when doing IETF QUIC. Ensure that its value does not exceed @@ -580,13 +586,13 @@ enum class QuicHttpQpackErrorCode { // Convert a QuicRstStreamErrorCode to an application error code to be used in // an IETF QUIC RESET_STREAM frame -uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode( +QUIC_EXPORT_PRIVATE uint64_t RstStreamErrorCodeToIetfResetStreamErrorCode( QuicRstStreamErrorCode rst_stream_error_code); // Convert the application error code of an IETF QUIC RESET_STREAM frame // to QuicRstStreamErrorCode. -QuicRstStreamErrorCode IetfResetStreamErrorCodeToRstStreamErrorCode( - uint64_t ietf_error_code); +QUIC_EXPORT_PRIVATE QuicRstStreamErrorCode +IetfResetStreamErrorCodeToRstStreamErrorCode(uint64_t ietf_error_code); QUIC_EXPORT_PRIVATE inline std::string HistogramEnumString( QuicErrorCode enum_value) { @@ -598,6 +604,36 @@ QUIC_EXPORT_PRIVATE inline std::string HistogramEnumDescription( return "cause"; } +enum QuicFailToSerializePacketLocation { + kQuicFailToAppendPacketHeaderFastPath = 0, + kQuicFailToAppendTypeFastPath = 1, + kQuicFailToAppendStreamFrameFastPath = 2, + kQuicFailToAddPaddingFastPath = 3, + kQuicFailToWriteIetfLongHeaderLengthFastPath = 4, + kQuicFailToEncryptPacketFastPath = 5, + kQuicSerializePacketNonEmptyBuffer = 6, + kQuicMissingInitialKey = 7, + kQuicMissingHandshakeKey = 8, + kQuicMissingZeroRttKey = 9, + kQuicMissingOneRttKey = 10, + kQuicFailToBuildPacketWithPaddingInitial = 11, + kQuicFailToBuildPacketInitial = 12, + kQuicFailToBuildPacketWithPaddingHandshake = 13, + kQuicFailToBuildPacketHandshake = 14, + kQuicFailToBuildPacketWithPaddingZeroRtt = 15, + kQuicFailToBuildPacketZeroRtt = 16, + kQuicFailToBuildPacketWithPaddingOneRtt = 17, + kQuicFailToBuildPacketOneRtt = 18, + kQuicFailToEncryptInitial = 19, + kQuicFailToEncryptHandshake = 20, + kQuicFailToEncryptZeroRtt = 21, + kQuicFailToEncryptOneRtt = 22, + kMaxFailLocationValue = kQuicFailToEncryptOneRtt +}; + +QUIC_EXPORT_PRIVATE void RecordFailToSerializePacketLocation( + QuicFailToSerializePacketLocation location); + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_ERROR_CODES_H_ diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc index e57a3e57cd0..0f567df48c2 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_error_codes_test.cc @@ -13,12 +13,7 @@ namespace quic { namespace test { namespace { -class QuicErrorCodesTest : public QuicTest {}; - -TEST_F(QuicErrorCodesTest, QuicRstStreamErrorCodeToString) { - EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD", - QuicRstStreamErrorCodeToString(QUIC_BAD_APPLICATION_PAYLOAD)); -} +using QuicErrorCodesTest = QuicTest; TEST_F(QuicErrorCodesTest, QuicErrorCodeToString) { EXPECT_STREQ("QUIC_NO_ERROR", QuicErrorCodeToString(QUIC_NO_ERROR)); @@ -94,6 +89,45 @@ TEST_F(QuicErrorCodesTest, QuicErrorCodeToTransportErrorCode) { } } +using QuicRstErrorCodesTest = QuicTest; + +TEST_F(QuicRstErrorCodesTest, QuicRstStreamErrorCodeToString) { + EXPECT_STREQ("QUIC_BAD_APPLICATION_PAYLOAD", + QuicRstStreamErrorCodeToString(QUIC_BAD_APPLICATION_PAYLOAD)); +} + +// When an IETF application protocol error code (sent on the wire in +// RESET_STREAM and STOP_SENDING frames) is translated into a +// QuicRstStreamErrorCode and back, it must yield the original value. +TEST_F(QuicRstErrorCodesTest, + IetfResetStreamErrorCodeToRstStreamErrorCodeAndBack) { + for (uint64_t wire_code : + {static_cast<uint64_t>(QuicHttp3ErrorCode::HTTP3_NO_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::GENERAL_PROTOCOL_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::INTERNAL_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::STREAM_CREATION_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::CLOSED_CRITICAL_STREAM), + static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_UNEXPECTED), + static_cast<uint64_t>(QuicHttp3ErrorCode::FRAME_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::EXCESSIVE_LOAD), + static_cast<uint64_t>(QuicHttp3ErrorCode::ID_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::SETTINGS_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::MISSING_SETTINGS), + static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_REJECTED), + static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_CANCELLED), + static_cast<uint64_t>(QuicHttp3ErrorCode::REQUEST_INCOMPLETE), + static_cast<uint64_t>(QuicHttp3ErrorCode::CONNECT_ERROR), + static_cast<uint64_t>(QuicHttp3ErrorCode::VERSION_FALLBACK), + static_cast<uint64_t>(QuicHttpQpackErrorCode::DECOMPRESSION_FAILED), + static_cast<uint64_t>(QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR), + static_cast<uint64_t>(QuicHttpQpackErrorCode::DECODER_STREAM_ERROR)}) { + QuicRstStreamErrorCode rst_stream_error_code = + IetfResetStreamErrorCodeToRstStreamErrorCode(wire_code); + EXPECT_EQ(wire_code, RstStreamErrorCodeToIetfResetStreamErrorCode( + rst_stream_error_code)); + } +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc index c9eabcb7ff3..e57277c672a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.cc @@ -621,7 +621,7 @@ size_t QuicFramer::GetBlockedFrameSize(QuicTransportVersion version, // static size_t QuicFramer::GetStopSendingFrameSize(const QuicStopSendingFrame& frame) { return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.stream_id) + - QuicDataWriter::GetVarInt62Len(frame.application_error_code); + QuicDataWriter::GetVarInt62Len(frame.ietf_error_code); } // static @@ -2034,6 +2034,23 @@ bool QuicFramer::HasDecrypterOfEncryptionLevel(EncryptionLevel level) const { return decrypter_[level] != nullptr; } +bool QuicFramer::HasAnEncrypterForSpace(PacketNumberSpace space) const { + switch (space) { + case INITIAL_DATA: + return HasEncrypterOfEncryptionLevel(ENCRYPTION_INITIAL); + case HANDSHAKE_DATA: + return HasEncrypterOfEncryptionLevel(ENCRYPTION_HANDSHAKE); + case APPLICATION_DATA: + return HasEncrypterOfEncryptionLevel(ENCRYPTION_ZERO_RTT) || + HasEncrypterOfEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + case NUM_PACKET_NUMBER_SPACES: + break; + } + QUIC_BUG << ENDPOINT + << "Try to send data of space: " << PacketNumberSpaceToString(space); + return false; +} + bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, QuicDataWriter* writer, size_t* length_field_offset) { @@ -2948,12 +2965,6 @@ bool QuicFramer::ProcessFrameData(QuicDataReader* reader, } case STOP_WAITING_FRAME: { - if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) && - version_.HasIetfInvariantHeader()) { - QUIC_RELOADABLE_FLAG_COUNT(quic_do_not_accept_stop_waiting); - set_detailed_error("STOP WAITING not supported in version 44+."); - return RaiseError(QUIC_INVALID_STOP_WAITING_DATA); - } QuicStopWaitingFrame stop_waiting_frame; if (!ProcessStopWaitingFrame(reader, header, &stop_waiting_frame)) { return RaiseError(QUIC_INVALID_STOP_WAITING_DATA); @@ -4047,7 +4058,8 @@ bool QuicFramer::ProcessConnectionCloseFrame(QuicDataReader* reader, return false; } - if (error_code >= QUIC_LAST_ERROR) { + if (!GetQuicReloadableFlag(quic_do_not_clip_received_error_code) && + error_code >= QUIC_LAST_ERROR) { // Ignore invalid QUIC error code if any. error_code = QUIC_LAST_ERROR; } @@ -4075,7 +4087,8 @@ bool QuicFramer::ProcessGoAwayFrame(QuicDataReader* reader, return false; } - if (error_code >= QUIC_LAST_ERROR) { + if (!GetQuicReloadableFlag(quic_do_not_clip_received_error_code) && + error_code >= QUIC_LAST_ERROR) { // Ignore invalid QUIC error code if any. error_code = QUIC_LAST_ERROR; } @@ -5907,19 +5920,28 @@ bool QuicFramer::ProcessStopSendingFrame( return false; } - uint64_t error_code; - if (!reader->ReadVarInt62(&error_code)) { + if (!reader->ReadVarInt62(&stop_sending_frame->ietf_error_code)) { set_detailed_error("Unable to read stop sending application error code."); return false; } + + if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_stop_sending_uses_ietf_error_code, 2, 2); + stop_sending_frame->error_code = + IetfResetStreamErrorCodeToRstStreamErrorCode( + stop_sending_frame->ietf_error_code); + return true; + } + // TODO(fkastenholz): when error codes go to uint64_t, remove this. - if (error_code > 0xffff) { - stop_sending_frame->application_error_code = 0xffff; - QUIC_DLOG(ERROR) << "Stop sending error code (" << error_code - << ") > 0xffff"; + if (stop_sending_frame->ietf_error_code > 0xffff) { + stop_sending_frame->error_code = + static_cast<QuicRstStreamErrorCode>(0xffff); + QUIC_DLOG(ERROR) << "Stop sending error code (" + << stop_sending_frame->ietf_error_code << ") > 0xffff"; } else { - stop_sending_frame->application_error_code = - static_cast<uint16_t>(error_code); + stop_sending_frame->error_code = static_cast<QuicRstStreamErrorCode>( + stop_sending_frame->ietf_error_code); } return true; } @@ -5932,7 +5954,7 @@ bool QuicFramer::AppendStopSendingFrame( return false; } if (!writer->WriteVarInt62( - static_cast<uint64_t>(stop_sending_frame.application_error_code))) { + static_cast<uint64_t>(stop_sending_frame.ietf_error_code))) { set_detailed_error("Can not write application error code"); return false; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h index 8e63fc25722..4fcd67110f6 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer.h @@ -581,6 +581,9 @@ class QUIC_EXPORT_PRIVATE QuicFramer { // Returns true if decrypter of |level| is available. bool HasDecrypterOfEncryptionLevel(EncryptionLevel level) const; + // Returns true if an encrypter of |space| is available. + bool HasAnEncrypterForSpace(PacketNumberSpace space) const; + void set_validate_flags(bool value) { validate_flags_ = value; } Perspective perspective() const { return perspective_; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc index c6109979c15..4da3e03fb99 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_framer_test.cc @@ -4157,17 +4157,8 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); - if (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) && - framer_.version().HasIetfInvariantHeader()) { - EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); - EXPECT_THAT(framer_.error(), IsError(QUIC_INVALID_STOP_WAITING_DATA)); - EXPECT_EQ("STOP WAITING not supported in version 44+.", - framer_.detailed_error()); - return; - } EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); - EXPECT_THAT(framer_.error(), IsQuicNoError()); ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( @@ -4184,9 +4175,8 @@ TEST_P(QuicFramerTest, NewStopWaitingFrame) { TEST_P(QuicFramerTest, InvalidNewStopWaitingFrame) { // The Stop Waiting frame is not in IETF QUIC - if (VersionHasIetfQuicFrames(version_.transport_version) || - (GetQuicReloadableFlag(quic_do_not_accept_stop_waiting) && - framer_.version().HasIetfInvariantHeader())) { + if (VersionHasIetfQuicFrames(version_.transport_version) && + framer_.version().HasIetfInvariantHeader()) { return; } SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); @@ -4408,8 +4398,9 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { {"Unable to read connection close error details.", { // error details length - kVarInt62OneByte + 0x0d, - // error details + kVarInt62OneByte + 0x11, + // error details with QuicErrorCode serialized + '1', '1', '5', ':', 'b', 'e', 'c', 'a', 'u', 's', 'e', ' ', 'I', ' ', 'c', 'a', @@ -4439,8 +4430,7 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { if (VersionHasIetfQuicFrames(framer_.transport_version())) { EXPECT_EQ(0x1234u, visitor_.connection_close_frame_.transport_close_frame_type); - EXPECT_THAT(visitor_.connection_close_frame_.quic_error_code, - IsError(QUIC_IETF_GQUIC_ERROR_MISSING)); + EXPECT_EQ(115u, visitor_.connection_close_frame_.quic_error_code); } else { // For Google QUIC frame, |quic_error_code| and |wire_error_code| has the // same value. @@ -4453,6 +4443,137 @@ TEST_P(QuicFramerTest, ConnectionCloseFrame) { CheckFramingBoundaries(fragments, QUIC_INVALID_CONNECTION_CLOSE_DATA); } +TEST_P(QuicFramerTest, ConnectionCloseFrameWithUnknownErrorCode) { + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); + // clang-format off + PacketFragments packet = { + // public flags (8 byte connection_id) + {"", + {0x28}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + // frame type (connection close frame) + {"", + {0x02}}, + // error code larger than QUIC_LAST_ERROR + {"Unable to read connection close error code.", + {0x00, 0x00, 0xC0, 0xDE}}, + {"Unable to read connection close error details.", + { + // error details length + 0x0, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n'} + } + }; + + PacketFragments packet46 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + // frame type (connection close frame) + {"", + {0x02}}, + // error code larger than QUIC_LAST_ERROR + {"Unable to read connection close error code.", + {0x00, 0x00, 0xC0, 0xDE}}, + {"Unable to read connection close error details.", + { + // error details length + 0x0, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n'} + } + }; + + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + // frame type (IETF Transport CONNECTION_CLOSE frame) + {"", + {0x1c}}, + // error code + {"Unable to read connection close error code.", + {kVarInt62FourBytes + 0x00, 0x00, 0xC0, 0xDE}}, + {"Unable to read connection close frame type.", + {kVarInt62TwoBytes + 0x12, 0x34 }}, + {"Unable to read connection close error details.", + { + // error details length + kVarInt62OneByte + 0x11, + // error details with QuicErrorCode larger than QUIC_LAST_ERROR + '8', '4', '9', ':', + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n'} + } + }; + // clang-format on + + PacketFragments& fragments = + VersionHasIetfQuicFrames(framer_.transport_version()) + ? packet99 + : (framer_.version().HasIetfInvariantHeader() ? packet46 : packet); + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(fragments)); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_THAT(framer_.error(), IsQuicNoError()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + EXPECT_EQ(0u, visitor_.stream_frames_.size()); + EXPECT_EQ("because I can", visitor_.connection_close_frame_.error_details); + if (VersionHasIetfQuicFrames(framer_.transport_version())) { + EXPECT_EQ(0x1234u, + visitor_.connection_close_frame_.transport_close_frame_type); + EXPECT_EQ(0xC0DEu, visitor_.connection_close_frame_.wire_error_code); + EXPECT_EQ(849u, visitor_.connection_close_frame_.quic_error_code); + } else { + // For Google QUIC frame, |quic_error_code| and |wire_error_code| has the + // same value. + if (GetQuicReloadableFlag(quic_do_not_clip_received_error_code)) { + EXPECT_EQ(0xC0DEu, visitor_.connection_close_frame_.wire_error_code); + EXPECT_EQ(0xC0DEu, visitor_.connection_close_frame_.quic_error_code); + } else { + EXPECT_EQ(QUIC_LAST_ERROR, + visitor_.connection_close_frame_.wire_error_code); + EXPECT_EQ(QUIC_LAST_ERROR, + visitor_.connection_close_frame_.quic_error_code); + } + } + + ASSERT_EQ(0u, visitor_.ack_frames_.size()); + + CheckFramingBoundaries(fragments, QUIC_INVALID_CONNECTION_CLOSE_DATA); +} + // As above, but checks that for Google-QUIC, if there happens // to be an ErrorCode string at the start of the details, it is // NOT extracted/parsed/folded/spindled/and/mutilated. @@ -4800,6 +4921,101 @@ TEST_P(QuicFramerTest, GoAwayFrame) { CheckFramingBoundaries(fragments, QUIC_INVALID_GOAWAY_DATA); } +TEST_P(QuicFramerTest, GoAwayFrameWithUnknownErrorCode) { + if (VersionHasIetfQuicFrames(framer_.transport_version())) { + // This frame is not in IETF QUIC. + return; + } + SetDecrypterLevel(ENCRYPTION_FORWARD_SECURE); + // clang-format off + PacketFragments packet = { + // public flags (8 byte connection_id) + {"", + {0x28}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + // frame type (go away frame) + {"", + {0x03}}, + // error code larger than QUIC_LAST_ERROR + {"Unable to read go away error code.", + {0x00, 0x00, 0xC0, 0xDE}}, + // stream id + {"Unable to read last good stream id.", + {0x01, 0x02, 0x03, 0x04}}, + // stream id + {"Unable to read goaway reason.", + { + // error details length + 0x0, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n'} + } + }; + + PacketFragments packet46 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x56, 0x78}}, + // frame type (go away frame) + {"", + {0x03}}, + // error code larger than QUIC_LAST_ERROR + {"Unable to read go away error code.", + {0x00, 0x00, 0xC0, 0xDE}}, + // stream id + {"Unable to read last good stream id.", + {0x01, 0x02, 0x03, 0x04}}, + // stream id + {"Unable to read goaway reason.", + { + // error details length + 0x0, 0x0d, + // error details + 'b', 'e', 'c', 'a', + 'u', 's', 'e', ' ', + 'I', ' ', 'c', 'a', + 'n'} + } + }; + // clang-format on + + PacketFragments& fragments = + framer_.version().HasIetfInvariantHeader() ? packet46 : packet; + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(fragments)); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_THAT(framer_.error(), IsQuicNoError()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + EXPECT_EQ(kStreamId, visitor_.goaway_frame_.last_good_stream_id); + if (GetQuicReloadableFlag(quic_do_not_clip_received_error_code)) { + EXPECT_EQ(0xC0DE, visitor_.goaway_frame_.error_code); + } else { + EXPECT_EQ(QUIC_LAST_ERROR, visitor_.goaway_frame_.error_code); + } + EXPECT_EQ("because I can", visitor_.goaway_frame_.reason_phrase); + + CheckFramingBoundaries(fragments, QUIC_INVALID_GOAWAY_DATA); +} + TEST_P(QuicFramerTest, WindowUpdateFrame) { if (VersionHasIetfQuicFrames(framer_.transport_version())) { // This frame is not in IETF QUIC, see MaxDataFrame and MaxStreamDataFrame @@ -10977,7 +11193,14 @@ TEST_P(QuicFramerTest, IetfStopSendingFrame) { PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); EXPECT_EQ(kStreamId, visitor_.stop_sending_frame_.stream_id); - EXPECT_EQ(0x7654, visitor_.stop_sending_frame_.application_error_code); + if (GetQuicReloadableFlag(quic_stop_sending_uses_ietf_error_code)) { + EXPECT_EQ(QUIC_STREAM_UNKNOWN_APPLICATION_ERROR_CODE, + visitor_.stop_sending_frame_.error_code); + } else { + EXPECT_EQ(0x7654, visitor_.stop_sending_frame_.error_code); + } + EXPECT_EQ(static_cast<uint64_t>(0x7654), + visitor_.stop_sending_frame_.ietf_error_code); CheckFramingBoundaries(packet99, QUIC_INVALID_STOP_SENDING_FRAME_DATA); } @@ -10996,7 +11219,9 @@ TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) { QuicStopSendingFrame frame; frame.stream_id = kStreamId; - frame.application_error_code = 0xffff; + frame.error_code = QUIC_STREAM_ENCODER_STREAM_ERROR; + frame.ietf_error_code = + static_cast<uint64_t>(QuicHttpQpackErrorCode::ENCODER_STREAM_ERROR); QuicFrames frames = {QuicFrame(&frame)}; // clang-format off @@ -11013,7 +11238,7 @@ TEST_P(QuicFramerTest, BuildIetfStopSendingPacket) { // Stream ID kVarInt62FourBytes + 0x01, 0x02, 0x03, 0x04, // Application error code - kVarInt62FourBytes + 0x00, 0x00, 0xff, 0xff + kVarInt62TwoBytes + 0x02, 0x01, }; // clang-format on @@ -11260,7 +11485,7 @@ TEST_P(QuicFramerTest, GetRetransmittableControlFrameSize) { QuicFramer::GetRetransmittableControlFrameSize( framer_.transport_version(), QuicFrame(&path_challenge_frame))); - QuicStopSendingFrame stop_sending_frame(10, 3, 20); + QuicStopSendingFrame stop_sending_frame(10, 3, QUIC_STREAM_CANCELLED); EXPECT_EQ(QuicFramer::GetStopSendingFrameSize(stop_sending_frame), QuicFramer::GetRetransmittableControlFrameSize( framer_.transport_version(), QuicFrame(&stop_sending_frame))); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h b/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h index 2a3a758b385..0ac98278019 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_interval_deque.h @@ -186,6 +186,7 @@ class QUIC_NO_EXPORT QuicIntervalDeque { return copy; } reference operator*() { return deque_->container_[index_]; } + reference operator*() const { return deque_->container_[index_]; } pointer operator->() { return &deque_->container_[index_]; } bool operator==(const Iterator& rhs) const { return index_ == rhs.index_ && deque_ == rhs.deque_; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc index 02e33088890..79deba84848 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.cc @@ -34,33 +34,18 @@ QuicNetworkBlackholeDetector::QuicNetworkBlackholeDetector( alarm_factory->CreateAlarm(arena->New<AlarmDelegate>(this), arena)) {} void QuicNetworkBlackholeDetector::OnAlarm() { - if (!revert_mtu_after_two_ptos_) { - if (path_degrading_deadline_.IsInitialized()) { - path_degrading_deadline_ = QuicTime::Zero(); - delegate_->OnPathDegradingDetected(); - // Switch to blackhole detection mode. - alarm_->Update(blackhole_deadline_, kAlarmGranularity); - return; - } - if (blackhole_deadline_.IsInitialized()) { - blackhole_deadline_ = QuicTime::Zero(); - delegate_->OnBlackholeDetected(); - } - return; - } - QuicTime next_deadline = GetEarliestDeadline(); if (!next_deadline.IsInitialized()) { QUIC_BUG << "BlackholeDetector alarm fired unexpectedly"; return; } - QUIC_DLOG(INFO) << "BlackholeDetector alarm firing. next_deadline:" - << next_deadline - << ", path_degrading_deadline_:" << path_degrading_deadline_ - << ", path_mtu_reduction_deadline_:" - << path_mtu_reduction_deadline_ - << ", blackhole_deadline_:" << blackhole_deadline_; + QUIC_DVLOG(1) << "BlackholeDetector alarm firing. next_deadline:" + << next_deadline + << ", path_degrading_deadline_:" << path_degrading_deadline_ + << ", path_mtu_reduction_deadline_:" + << path_mtu_reduction_deadline_ + << ", blackhole_deadline_:" << blackhole_deadline_; if (path_degrading_deadline_ == next_deadline) { path_degrading_deadline_ = QuicTime::Zero(); delegate_->OnPathDegradingDetected(); @@ -94,31 +79,14 @@ void QuicNetworkBlackholeDetector::RestartDetection( blackhole_deadline_ = blackhole_deadline; path_mtu_reduction_deadline_ = path_mtu_reduction_deadline; - if (!revert_mtu_after_two_ptos_) { - QUIC_BUG_IF(path_degrading_deadline_.IsInitialized() && - blackhole_deadline_.IsInitialized() && - path_degrading_deadline_ > blackhole_deadline_) - << "Path degrading timeout is later than blackhole detection timeout"; - } else { - QUIC_BUG_IF(blackhole_deadline_.IsInitialized() && - blackhole_deadline_ != GetLastDeadline()) - << "Blackhole detection deadline should be the last deadline."; - } + QUIC_BUG_IF(blackhole_deadline_.IsInitialized() && + blackhole_deadline_ != GetLastDeadline()) + << "Blackhole detection deadline should be the last deadline."; - if (!revert_mtu_after_two_ptos_) { - alarm_->Update(path_degrading_deadline_, kAlarmGranularity); - if (alarm_->IsSet()) { - return; - } - alarm_->Update(blackhole_deadline_, kAlarmGranularity); - } else { - UpdateAlarm(); - } + UpdateAlarm(); } QuicTime QuicNetworkBlackholeDetector::GetEarliestDeadline() const { - DCHECK(revert_mtu_after_two_ptos_); - QuicTime result = QuicTime::Zero(); for (QuicTime t : {path_degrading_deadline_, blackhole_deadline_, path_mtu_reduction_deadline_}) { @@ -135,21 +103,18 @@ QuicTime QuicNetworkBlackholeDetector::GetEarliestDeadline() const { } QuicTime QuicNetworkBlackholeDetector::GetLastDeadline() const { - DCHECK(revert_mtu_after_two_ptos_); return std::max({path_degrading_deadline_, blackhole_deadline_, path_mtu_reduction_deadline_}); } void QuicNetworkBlackholeDetector::UpdateAlarm() const { - DCHECK(revert_mtu_after_two_ptos_); - QuicTime next_deadline = GetEarliestDeadline(); - QUIC_DLOG(INFO) << "Updating alarm. next_deadline:" << next_deadline - << ", path_degrading_deadline_:" << path_degrading_deadline_ - << ", path_mtu_reduction_deadline_:" - << path_mtu_reduction_deadline_ - << ", blackhole_deadline_:" << blackhole_deadline_; + QUIC_DVLOG(1) << "Updating alarm. next_deadline:" << next_deadline + << ", path_degrading_deadline_:" << path_degrading_deadline_ + << ", path_mtu_reduction_deadline_:" + << path_mtu_reduction_deadline_ + << ", blackhole_deadline_:" << blackhole_deadline_; alarm_->Update(next_deadline, kAlarmGranularity); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h index 77c5c59dd7e..6952c85d22b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector.h @@ -60,8 +60,6 @@ class QUIC_EXPORT_PRIVATE QuicNetworkBlackholeDetector { // Returns true if |alarm_| is set. bool IsDetectionInProgress() const; - bool revert_mtu_after_two_ptos() const { return revert_mtu_after_two_ptos_; } - private: friend class test::QuicConnectionPeer; friend class test::QuicNetworkBlackholeDetectorPeer; @@ -74,9 +72,6 @@ class QUIC_EXPORT_PRIVATE QuicNetworkBlackholeDetector { Delegate* delegate_; // Not owned. - const bool revert_mtu_after_two_ptos_ = - GetQuicReloadableFlag(quic_revert_mtu_after_two_ptos); - // Time that Delegate::OnPathDegrading will be called. 0 means no path // degrading detection is in progress. QuicTime path_degrading_deadline_ = QuicTime::Zero(); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc index 3f6f7470854..d628d777396 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_network_blackhole_detector_test.cc @@ -77,20 +77,6 @@ TEST_F(QuicNetworkBlackholeDetectorTest, StartAndFire) { EXPECT_CALL(delegate_, OnPathDegradingDetected()); alarm_->Fire(); - if (!detector_.revert_mtu_after_two_ptos()) { - // Verify blackhole detection is still in progress. - EXPECT_TRUE(detector_.IsDetectionInProgress()); - EXPECT_EQ(clock_.Now() + blackhole_delay_ - path_degrading_delay_, - alarm_->deadline()); - - // Fire blackhole detection alarm. - clock_.AdvanceTime(blackhole_delay_ - path_degrading_delay_); - EXPECT_CALL(delegate_, OnBlackholeDetected()); - alarm_->Fire(); - EXPECT_FALSE(detector_.IsDetectionInProgress()); - return; - } - // Verify path mtu reduction detection is still in progress. EXPECT_TRUE(detector_.IsDetectionInProgress()); EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_, @@ -135,17 +121,10 @@ TEST_F(QuicNetworkBlackholeDetectorTest, PathDegradingFiresAndRestart) { EXPECT_CALL(delegate_, OnPathDegradingDetected()); alarm_->Fire(); - if (!detector_.revert_mtu_after_two_ptos()) { - // Verify blackhole detection is still in progress. - EXPECT_TRUE(detector_.IsDetectionInProgress()); - EXPECT_EQ(clock_.Now() + blackhole_delay_ - path_degrading_delay_, - alarm_->deadline()); - } else { - // Verify path mtu reduction detection is still in progress. - EXPECT_TRUE(detector_.IsDetectionInProgress()); - EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_, - alarm_->deadline()); - } + // Verify path mtu reduction detection is still in progress. + EXPECT_TRUE(detector_.IsDetectionInProgress()); + EXPECT_EQ(clock_.Now() + path_mtu_reduction_delay_ - path_degrading_delay_, + alarm_->deadline()); // After 100ms, restart detections on forward progress. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc index 5140df8f2c8..30b911fa839 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.cc @@ -18,6 +18,7 @@ #include "net/third_party/quiche/src/quic/core/quic_connection_id.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" @@ -133,6 +134,9 @@ QuicPacketCreator::QuicPacketCreator(QuicConnectionId server_connection_id, fully_pad_crypto_handshake_packets_(true), latched_hard_max_packet_length_(0), max_datagram_frame_size_(0) { + if (close_connection_on_serialization_failure_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_close_connection_on_serialization_failure); + } SetMaxPacketLength(kDefaultMaxPacketSize); if (!framer_->version().UsesTls()) { // QUIC+TLS negotiates the maximum datagram frame size via the @@ -203,9 +207,7 @@ void QuicPacketCreator::SetSoftMaxPacketLength(QuicByteCount length) { // Please note: this would not guarantee to fit next packet if the size of // packet header increases (e.g., encryption level changes). QUIC_DLOG(INFO) << length << " is too small to fit packet header"; - if (coalesced_packet_of_higher_space_) { - RemoveSoftMaxPacketLength(); - } + RemoveSoftMaxPacketLength(); return; } QUIC_DVLOG(1) << "Setting soft max packet length to: " << length; @@ -413,13 +415,16 @@ void QuicPacketCreator::CreateStreamFrame(QuicStreamId id, QuicStreamOffset offset, bool fin, QuicFrame* frame) { - DCHECK_GT( - max_packet_length_, - StreamFramePacketOverhead( - framer_->transport_version(), GetDestinationConnectionIdLength(), - GetSourceConnectionIdLength(), kIncludeVersion, - IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER, - GetRetryTokenLengthLength(), GetLengthLength(), offset)); + // Make sure max_packet_length_ is greater than the largest possible overhead + // or max_packet_length_ is set to the soft limit. + DCHECK(max_packet_length_ > + StreamFramePacketOverhead( + framer_->transport_version(), + GetDestinationConnectionIdLength(), + GetSourceConnectionIdLength(), kIncludeVersion, + IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER, + GetRetryTokenLengthLength(), GetLengthLength(), offset) || + latched_hard_max_packet_length_ > 0); QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset, data_size)) << "No room for Stream frame, BytesFree: " << BytesFree() @@ -444,15 +449,10 @@ bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level, size_t write_length, QuicStreamOffset offset, QuicFrame* frame) { - size_t min_frame_size = + const size_t min_frame_size = QuicFramer::GetMinCryptoFrameSize(write_length, offset); - size_t min_plaintext_bytes = min_frame_size; - if (!fix_extra_padding_bytes_ && queued_frames_.empty()) { - min_plaintext_bytes = - std::max(min_frame_size, MinPlaintextPacketSize(framer_->version())); - } - if (BytesFree() <= min_plaintext_bytes && - (!RemoveSoftMaxPacketLength() || BytesFree() <= min_plaintext_bytes)) { + if (BytesFree() <= min_frame_size && + (!RemoveSoftMaxPacketLength() || BytesFree() <= min_frame_size)) { return false; } size_t max_write_length = BytesFree() - min_frame_size; @@ -475,12 +475,18 @@ void QuicPacketCreator::FlushCurrentPacket() { } DCHECK_EQ(nullptr, packet_.encrypted_buffer); - SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize); + const bool success = + SerializePacket(std::move(external_buffer), kMaxOutgoingPacketSize); + if (close_connection_on_serialization_failure_ && !success) { + return; + } OnSerializedPacket(); } void QuicPacketCreator::OnSerializedPacket() { - if (packet_.encrypted_buffer == nullptr) { + if (close_connection_on_serialization_failure_) { + QUIC_BUG_IF(packet_.encrypted_buffer == nullptr); + } else if (packet_.encrypted_buffer == nullptr) { const std::string error_details = "Failed to SerializePacket."; QUIC_BUG << error_details; delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, @@ -501,6 +507,8 @@ void QuicPacketCreator::ClearPacket() { packet_.transmission_type = NOT_RETRANSMISSION; packet_.encrypted_buffer = nullptr; packet_.encrypted_length = 0; + packet_.has_ack_frequency = false; + packet_.has_message = false; packet_.fate = SEND_TO_WRITER; QUIC_BUG_IF(packet_.release_encrypted_buffer != nullptr) << "packet_.release_encrypted_buffer should be empty"; @@ -548,8 +556,11 @@ size_t QuicPacketCreator::ReserializeInitialPacketInCoalescedPacket( return 0; } } - SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len); - // TODO(b/166255274): report unrecoverable error on serialization failures. + const bool success = + SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len); + if (close_connection_on_serialization_failure_ && !success) { + return 0; + } const size_t encrypted_length = packet_.encrypted_length; // Clear frames in packet_. No need to DeleteFrames since frames are owned by // initial_packet. @@ -567,19 +578,17 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( bool fin, TransmissionType transmission_type, size_t* num_bytes_consumed) { + // TODO(b/167222597): consider using ScopedSerializationFailureHandler. DCHECK(queued_frames_.empty()); DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); // Write out the packet header QuicPacketHeader header; FillPacketHeader(&header); - if (determine_serialized_packet_fate_early_) { - packet_.fate = delegate_->GetSerializedPacketFate( - /*is_mtu_discovery=*/false, packet_.encryption_level); - QUIC_DVLOG(1) << ENDPOINT << "fate of packet " << packet_.packet_number - << ": " << SerializedPacketFateToString(packet_.fate) - << " of " - << EncryptionLevelToString(packet_.encryption_level); - } + packet_.fate = delegate_->GetSerializedPacketFate( + /*is_mtu_discovery=*/false, packet_.encryption_level); + QUIC_DVLOG(1) << ENDPOINT << "fate of packet " << packet_.packet_number + << ": " << SerializedPacketFateToString(packet_.fate) << " of " + << EncryptionLevelToString(packet_.encryption_level); QUIC_CACHELINE_ALIGNED char stack_buffer[kMaxOutgoingPacketSize]; QuicOwnedPacketBuffer packet_buffer(delegate_->GetPacketBuffer()); @@ -595,6 +604,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( size_t length_field_offset = 0; if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) { QUIC_BUG << "AppendPacketHeader failed"; + RecordFailToSerializePacketLocation(kQuicFailToAppendPacketHeaderFastPath); return; } @@ -636,10 +646,12 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( bool omit_frame_length = !needs_padding; if (!framer_->AppendTypeByte(QuicFrame(frame), omit_frame_length, &writer)) { QUIC_BUG << "AppendTypeByte failed"; + RecordFailToSerializePacketLocation(kQuicFailToAppendTypeFastPath); return; } if (!framer_->AppendStreamFrame(frame, omit_frame_length, &writer)) { QUIC_BUG << "AppendStreamFrame failed"; + RecordFailToSerializePacketLocation(kQuicFailToAppendStreamFrameFastPath); return; } if (needs_padding && @@ -647,11 +659,14 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( !writer.WritePaddingBytes(MinPlaintextPacketSize(framer_->version()) - plaintext_bytes_written)) { QUIC_BUG << "Unable to add padding bytes"; + RecordFailToSerializePacketLocation(kQuicFailToAddPaddingFastPath); return; } if (!framer_->WriteIetfLongHeaderLength(header, &writer, length_field_offset, packet_.encryption_level)) { + RecordFailToSerializePacketLocation( + kQuicFailToWriteIetfLongHeaderLengthFastPath); return; } @@ -666,6 +681,7 @@ void QuicPacketCreator::CreateAndSerializeStreamFrame( writer.length(), kMaxOutgoingPacketSize, encrypted_buffer); if (encrypted_length == 0) { QUIC_BUG << "Failed to encrypt packet number " << header.packet_number; + RecordFailToSerializePacketLocation(kQuicFailToEncryptPacketFastPath); return; } // TODO(ianswett): Optimize the storage so RetransmitableFrames can be @@ -726,21 +742,14 @@ size_t QuicPacketCreator::ExpansionOnNewFrameWithLastFrame( return kQuicStreamPayloadLengthSize; } -size_t QuicPacketCreator::BytesFree() { +size_t QuicPacketCreator::BytesFree() const { DCHECK_GE(max_plaintext_size_, PacketSize()); return max_plaintext_size_ - std::min(max_plaintext_size_, PacketSize() + ExpansionOnNewFrame()); } -size_t QuicPacketCreator::PacketSize() { - if (update_packet_size_) { - return queued_frames_.empty() ? PacketHeaderSize() : packet_size_; - } - if (!queued_frames_.empty()) { - return packet_size_; - } - packet_size_ = PacketHeaderSize(); - return packet_size_; +size_t QuicPacketCreator::PacketSize() const { + return queued_frames_.empty() ? PacketHeaderSize() : packet_size_; } bool QuicPacketCreator::AddPaddedSavedFrame( @@ -753,11 +762,23 @@ bool QuicPacketCreator::AddPaddedSavedFrame( return false; } -void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, +bool QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, size_t encrypted_buffer_len) { - const bool use_queued_frames_cleaner = GetQuicReloadableFlag( - quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded); - ScopedQueuedFramesCleaner cleaner(use_queued_frames_cleaner ? this : nullptr); + if (close_connection_on_serialization_failure_ && + packet_.encrypted_buffer != nullptr) { + RecordFailToSerializePacketLocation(kQuicSerializePacketNonEmptyBuffer); + const std::string error_details = + "Packet's encrypted buffer is not empty before serialization"; + QUIC_BUG << error_details; + delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, + error_details); + return false; + } + const bool use_handler = + GetQuicReloadableFlag( + quic_neuter_initial_packet_in_coalescer_with_initial_key_discarded) || + close_connection_on_serialization_failure_; + ScopedSerializationFailureHandler handler(use_handler ? this : nullptr); DCHECK_LT(0u, encrypted_buffer_len); QUIC_BUG_IF(queued_frames_.empty() && pending_padding_bytes_ == 0) @@ -765,8 +786,7 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, QuicPacketHeader header; // FillPacketHeader increments packet_number_. FillPacketHeader(&header); - if (determine_serialized_packet_fate_early_ && delegate_ != nullptr) { - QUIC_RELOADABLE_FLAG_COUNT(quic_determine_serialized_packet_fate_early); + if (delegate_ != nullptr) { packet_.fate = delegate_->GetSerializedPacketFate( /*is_mtu_discovery=*/QuicUtils::ContainsFrameType(queued_frames_, MTU_DISCOVERY_FRAME), @@ -784,11 +804,29 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, << packet_.encryption_level; if (!framer_->HasEncrypterOfEncryptionLevel(packet_.encryption_level)) { + // TODO(fayang): Use QUIC_MISSING_WRITE_KEYS for serialization failures due + // to missing keys. QUIC_BUG << ENDPOINT << "Attempting to serialize " << header << QuicFramesToString(queued_frames_) << " at missing encryption_level " << packet_.encryption_level << " using " << framer_->version(); - return; + switch (packet_.encryption_level) { + case ENCRYPTION_INITIAL: + RecordFailToSerializePacketLocation(kQuicMissingInitialKey); + break; + case ENCRYPTION_HANDSHAKE: + RecordFailToSerializePacketLocation(kQuicMissingHandshakeKey); + break; + case ENCRYPTION_ZERO_RTT: + RecordFailToSerializePacketLocation(kQuicMissingZeroRttKey); + break; + case ENCRYPTION_FORWARD_SECURE: + RecordFailToSerializePacketLocation(kQuicMissingOneRttKey); + break; + default: + break; + } + return false; } DCHECK_GE(max_plaintext_size_, packet_size_); @@ -806,7 +844,43 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, << latched_hard_max_packet_length_ << ", max_packet_length_: " << max_packet_length_ << ", header: " << header; - return; + switch (packet_.encryption_level) { + case ENCRYPTION_INITIAL: + if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) { + RecordFailToSerializePacketLocation( + kQuicFailToBuildPacketWithPaddingInitial); + } else { + RecordFailToSerializePacketLocation(kQuicFailToBuildPacketInitial); + } + break; + case ENCRYPTION_HANDSHAKE: + if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) { + RecordFailToSerializePacketLocation( + kQuicFailToBuildPacketWithPaddingHandshake); + } else { + RecordFailToSerializePacketLocation(kQuicFailToBuildPacketHandshake); + } + break; + case ENCRYPTION_ZERO_RTT: + if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) { + RecordFailToSerializePacketLocation( + kQuicFailToBuildPacketWithPaddingZeroRtt); + } else { + RecordFailToSerializePacketLocation(kQuicFailToBuildPacketZeroRtt); + } + break; + case ENCRYPTION_FORWARD_SECURE: + if (QuicUtils::ContainsFrameType(queued_frames_, PADDING_FRAME)) { + RecordFailToSerializePacketLocation( + kQuicFailToBuildPacketWithPaddingOneRtt); + } else { + RecordFailToSerializePacketLocation(kQuicFailToBuildPacketOneRtt); + } + break; + default: + break; + } + return false; } // ACK Frames will be truncated due to length only if they're the only frame @@ -827,11 +901,27 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, encrypted_buffer_len, encrypted_buffer.buffer); if (encrypted_length == 0) { QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number; - return; + switch (packet_.encryption_level) { + case ENCRYPTION_INITIAL: + RecordFailToSerializePacketLocation(kQuicFailToEncryptInitial); + break; + case ENCRYPTION_HANDSHAKE: + RecordFailToSerializePacketLocation(kQuicFailToEncryptHandshake); + break; + case ENCRYPTION_ZERO_RTT: + RecordFailToSerializePacketLocation(kQuicFailToEncryptZeroRtt); + break; + case ENCRYPTION_FORWARD_SECURE: + RecordFailToSerializePacketLocation(kQuicFailToEncryptOneRtt); + break; + default: + break; + } + return false; } packet_size_ = 0; - if (!use_queued_frames_cleaner) { + if (!use_handler) { queued_frames_.clear(); } packet_.encrypted_buffer = encrypted_buffer.buffer; @@ -839,6 +929,7 @@ void QuicPacketCreator::SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, encrypted_buffer.buffer = nullptr; packet_.release_encrypted_buffer = std::move(encrypted_buffer).release_buffer; + return true; } std::unique_ptr<QuicEncryptedPacket> @@ -1331,12 +1422,9 @@ QuicConsumedData QuicPacketCreator::ConsumeDataFastPath( bool fin, size_t total_bytes_consumed) { DCHECK(!QuicUtils::IsCryptoStreamId(transport_version(), id)); - if (GetQuicReloadableFlag(quic_check_encryption_level_in_fast_path)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_check_encryption_level_in_fast_path); - if (AttemptingToSendUnencryptedStreamData()) { - return QuicConsumedData(total_bytes_consumed, - fin && (total_bytes_consumed == write_length)); - } + if (AttemptingToSendUnencryptedStreamData()) { + return QuicConsumedData(total_bytes_consumed, + fin && (total_bytes_consumed == write_length)); } while (total_bytes_consumed < write_length && @@ -1586,9 +1674,6 @@ size_t QuicPacketCreator::GetSerializedFrameLength(const QuicFrame& frame) { size_t serialized_frame_length = framer_->GetSerializedFrameLength( frame, BytesFree(), queued_frames_.empty(), /* last_frame_in_packet= */ true, GetPacketNumberLength()); - if (!fix_extra_padding_bytes_) { - return serialized_frame_length; - } if (!framer_->version().HasHeaderProtection() || serialized_frame_length == 0) { return serialized_frame_length; @@ -1600,7 +1685,6 @@ size_t QuicPacketCreator::GetSerializedFrameLength(const QuicFrame& frame) { // No extra bytes is needed. return serialized_frame_length; } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_extra_padding_bytes, 1, 3); if (BytesFree() < serialized_frame_length) { QUIC_BUG << ENDPOINT << "Frame does not fit: " << frame; return 0; @@ -1639,6 +1723,13 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, } } + // If this is an ACK frame, validate that it is non-empty and that + // largest_acked matches the max packet number. + DCHECK(frame.type != ACK_FRAME || + (!frame.ack_frame->packets.Empty() && + frame.ack_frame->packets.Max() == frame.ack_frame->largest_acked)) + << "Invalid ACK frame: " << frame; + size_t frame_len = GetSerializedFrameLength(frame); if (frame_len == 0 && RemoveSoftMaxPacketLength()) { // Remove soft max_packet_length and retry. @@ -1650,8 +1741,7 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, FlushCurrentPacket(); return false; } - if (update_packet_size_ && queued_frames_.empty()) { - QUIC_RELOADABLE_FLAG_COUNT(quic_update_packet_size); + if (queued_frames_.empty()) { packet_size_ = PacketHeaderSize(); } DCHECK_LT(0u, packet_size_); @@ -1680,9 +1770,12 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, if (frame.type == ACK_FRAME) { packet_.has_ack = true; packet_.largest_acked = LargestAcked(*frame.ack_frame); - } - if (frame.type == STOP_WAITING_FRAME) { + } else if (frame.type == STOP_WAITING_FRAME) { packet_.has_stop_waiting = true; + } else if (frame.type == ACK_FREQUENCY_FRAME) { + packet_.has_ack_frequency = true; + } else if (frame.type == MESSAGE_FRAME) { + packet_.has_message = true; } if (debug_delegate_ != nullptr) { debug_delegate_->OnFrameAddedToPacket(frame); @@ -1697,7 +1790,6 @@ bool QuicPacketCreator::AddFrame(const QuicFrame& frame, } void QuicPacketCreator::MaybeAddExtraPaddingForHeaderProtection() { - DCHECK(fix_extra_padding_bytes_); if (!framer_->version().HasHeaderProtection() || needs_full_padding_) { return; } @@ -1709,7 +1801,6 @@ void QuicPacketCreator::MaybeAddExtraPaddingForHeaderProtection() { std::max(1 + ExpansionOnNewFrame(), MinPlaintextPacketSize(framer_->version()) - frame_bytes) - ExpansionOnNewFrame(); - QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_extra_padding_bytes, 2, 3); // Update pending_padding_bytes_. pending_padding_bytes_ = std::max(pending_padding_bytes_, min_header_protection_padding); @@ -1772,59 +1863,16 @@ void QuicPacketCreator::MaybeAddPadding() { needs_full_padding_ = true; } - if (determine_serialized_packet_fate_early_) { - if (packet_.fate == COALESCE || - packet_.fate == LEGACY_VERSION_ENCAPSULATE) { - // Do not add full padding if the packet is going to be coalesced or - // encapsulated. - needs_full_padding_ = false; - } - } else { - // Packet coalescer pads INITIAL packets, so the creator should not. - if (framer_->version().CanSendCoalescedPackets() && - (packet_.encryption_level == ENCRYPTION_INITIAL || - packet_.encryption_level == ENCRYPTION_HANDSHAKE)) { - // TODO(fayang): MTU discovery packets should not ever be sent as - // ENCRYPTION_INITIAL or ENCRYPTION_HANDSHAKE. - bool is_mtu_discovery = false; - for (const auto& frame : packet_.nonretransmittable_frames) { - if (frame.type == MTU_DISCOVERY_FRAME) { - is_mtu_discovery = true; - break; - } - } - if (!is_mtu_discovery) { - // Do not add full padding if connection tries to coalesce packet. - needs_full_padding_ = false; - } - } - - if (disable_padding_override_) { - needs_full_padding_ = false; - } + if (packet_.fate == COALESCE || packet_.fate == LEGACY_VERSION_ENCAPSULATE) { + // Do not add full padding if the packet is going to be coalesced or + // encapsulated. + needs_full_padding_ = false; } // Header protection requires a minimum plaintext packet size. - // TODO(fayang): remove extra_padding_bytes when deprecating - // quic_fix_extra_padding_bytes. - size_t extra_padding_bytes = 0; - if (fix_extra_padding_bytes_) { - MaybeAddExtraPaddingForHeaderProtection(); - } else { - if (framer_->version().HasHeaderProtection()) { - size_t frame_bytes = PacketSize() - PacketHeaderSize(); - - if (frame_bytes + pending_padding_bytes_ < - MinPlaintextPacketSize(framer_->version()) && - !needs_full_padding_) { - extra_padding_bytes = - MinPlaintextPacketSize(framer_->version()) - frame_bytes; - } - } - } + MaybeAddExtraPaddingForHeaderProtection(); - if (!needs_full_padding_ && pending_padding_bytes_ == 0 && - extra_padding_bytes == 0) { + if (!needs_full_padding_ && pending_padding_bytes_ == 0) { // Do not need padding. return; } @@ -1833,7 +1881,6 @@ void QuicPacketCreator::MaybeAddPadding() { if (!needs_full_padding_) { padding_bytes = std::min<int16_t>(pending_padding_bytes_, BytesFree()); pending_padding_bytes_ -= padding_bytes; - padding_bytes = std::max<int16_t>(padding_bytes, extra_padding_bytes); } bool success = AddFrame(QuicFrame(QuicPaddingFrame(padding_bytes)), @@ -2018,16 +2065,83 @@ bool QuicPacketCreator::HasSoftMaxPacketLength() const { return latched_hard_max_packet_length_ != 0; } -QuicPacketCreator::ScopedQueuedFramesCleaner::ScopedQueuedFramesCleaner( - QuicPacketCreator* creator) +void QuicPacketCreator::SetDefaultPeerAddress(QuicSocketAddress address) { + if (!packet_.peer_address.IsInitialized()) { + packet_.peer_address = address; + return; + } + if (packet_.peer_address != address) { + FlushCurrentPacket(); + packet_.peer_address = address; + } +} + +QuicPacketCreator::ScopedPeerAddressContext::ScopedPeerAddressContext( + QuicPacketCreator* creator, + QuicSocketAddress address) + : creator_(creator), old_peer_address_(creator_->packet_.peer_address) { + QUIC_BUG_IF(!creator_->packet_.peer_address.IsInitialized()) + << "Context is used before seralized packet's peer address is " + "initialized."; + creator_->SetDefaultPeerAddress(address); +} + +QuicPacketCreator::ScopedPeerAddressContext::~ScopedPeerAddressContext() { + creator_->SetDefaultPeerAddress(old_peer_address_); +} + +QuicPacketCreator::ScopedSerializationFailureHandler:: + ScopedSerializationFailureHandler(QuicPacketCreator* creator) : creator_(creator) {} -QuicPacketCreator::ScopedQueuedFramesCleaner::~ScopedQueuedFramesCleaner() { +QuicPacketCreator::ScopedSerializationFailureHandler:: + ~ScopedSerializationFailureHandler() { if (creator_ == nullptr) { return; } + // Always clear queued_frames_. creator_->queued_frames_.clear(); + + if (creator_->close_connection_on_serialization_failure_ && + creator_->packet_.encrypted_buffer == nullptr) { + const std::string error_details = "Failed to SerializePacket."; + QUIC_BUG << error_details; + creator_->delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, + error_details); + } } +void QuicPacketCreator::set_encryption_level(EncryptionLevel level) { + DCHECK(level == packet_.encryption_level || !HasPendingFrames()) + << "Cannot update encryption level from " << packet_.encryption_level + << " to " << level << " when we already have pending frames: " + << QuicFramesToString(queued_frames_); + packet_.encryption_level = level; +} + +bool QuicPacketCreator::AddPathResponseFrame( + const QuicPathFrameBuffer& data_buffer) { + auto path_response = + new QuicPathResponseFrame(kInvalidControlFrameId, data_buffer); + QuicFrame frame(path_response); + if (HasPendingFrames()) { + if (AddPaddedSavedFrame(frame, NOT_RETRANSMISSION)) { + // Frame is queued. + return true; + } + } + // Frame was not queued but queued frames were flushed. + DCHECK(!HasPendingFrames()); + if (!delegate_->ShouldGeneratePacket(NO_RETRANSMITTABLE_DATA, + NOT_HANDSHAKE)) { + QUIC_DVLOG(1) << ENDPOINT << "Can't send PATH_RESPONSE now"; + QUIC_RELOADABLE_FLAG_COUNT_N(quic_send_path_response, 5, 5); + delete path_response; + return false; + } + bool success = AddPaddedSavedFrame(frame, NOT_RETRANSMISSION); + QUIC_BUG_IF(!success); + return true; +} #undef ENDPOINT // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h index aefa975efb2..b025d06f66f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator.h @@ -27,6 +27,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" namespace quic { @@ -82,6 +83,20 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { virtual void OnStreamFrameCoalesced(const QuicStreamFrame& /*frame*/) {} }; + // Set the peer address which the serialized packet will be sent to during the + // scope of this object. Upon exiting the scope, the original peer address is + // restored. + class QUIC_EXPORT_PRIVATE ScopedPeerAddressContext { + public: + ScopedPeerAddressContext(QuicPacketCreator* creator, + QuicSocketAddress address); + ~ScopedPeerAddressContext(); + + private: + QuicPacketCreator* creator_; + QuicSocketAddress old_peer_address_; + }; + QuicPacketCreator(QuicConnectionId server_connection_id, QuicFramer* framer, DelegateInterface* delegate); @@ -149,14 +164,14 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Returns true if current open packet can accommodate more stream frames of // stream |id| at |offset| and data length |data_size|, false otherwise. - // TODO(fayang): mark this const when deprecating quic_update_packet_size. + // TODO(fayang): mark this const by moving RemoveSoftMaxPacketLength out. bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset, size_t data_size); // Returns true if current open packet can accommodate a message frame of // |length|. - // TODO(fayang): mark this const when deprecating quic_update_packet_size. + // TODO(fayang): mark this const by moving RemoveSoftMaxPacketLength out. bool HasRoomForMessageFrame(QuicByteCount length); // Serializes all added frames into a single packet and invokes the delegate_ @@ -188,8 +203,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // frames in the packet. Since stream frames are slightly smaller when they // are the last frame in a packet, this method will return a different // value than max_packet_size - PacketSize(), in this case. - // TODO(fayang): mark this const when deprecating quic_update_packet_size. - size_t BytesFree(); + size_t BytesFree() const; // Returns the number of bytes that the packet will expand by if a new frame // is added to the packet. If the last frame was a stream frame, it will @@ -206,8 +220,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // if serialized with the current frames. Adding a frame to the packet // may change the serialized length of existing frames, as per the comment // in BytesFree. - // TODO(fayang): mark this const when deprecating quic_update_packet_size. - size_t PacketSize(); + size_t PacketSize() const; // Tries to add |frame| to the packet creator's list of frames to be // serialized. If the frame does not fit into the current packet, flushes the @@ -242,6 +255,9 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { const QuicCircularDeque<QuicPathFrameBuffer>& payloads, const bool is_padded); + // Add PATH_RESPONSE to current packet, flush before or afterwards if needed. + bool AddPathResponseFrame(const QuicPathFrameBuffer& data_buffer); + // Returns a dummy packet that is valid but contains no useful information. static SerializedPacket NoPacket(); @@ -268,9 +284,7 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { void SetClientConnectionId(QuicConnectionId client_connection_id); // Sets the encryption level that will be applied to new packets. - void set_encryption_level(EncryptionLevel level) { - packet_.encryption_level = level; - } + void set_encryption_level(EncryptionLevel level); EncryptionLevel encryption_level() { return packet_.encryption_level; } // packet number of the last created packet, or 0 if no packets have been @@ -451,26 +465,19 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Returns true if max_packet_length_ is currently a soft value. bool HasSoftMaxPacketLength() const; - void set_disable_padding_override(bool should_disable_padding) { - disable_padding_override_ = should_disable_padding; - } - - bool determine_serialized_packet_fate_early() const { - return determine_serialized_packet_fate_early_; - } - - bool coalesced_packet_of_higher_space() const { - return coalesced_packet_of_higher_space_; - } + // Use this address to sent to the peer from now on. If this address is + // different from the current one, flush all the queue frames first. + void SetDefaultPeerAddress(QuicSocketAddress address); private: friend class test::QuicPacketCreatorPeer; - // Used to clear queued_frames_ of creator upon exiting the scope. - class QUIC_EXPORT_PRIVATE ScopedQueuedFramesCleaner { + // Used to 1) clear queued_frames_, 2) report unrecoverable error (if + // serialization fails) upon exiting the scope. + class QUIC_EXPORT_PRIVATE ScopedSerializationFailureHandler { public: - explicit ScopedQueuedFramesCleaner(QuicPacketCreator* creator); - ~ScopedQueuedFramesCleaner(); + explicit ScopedSerializationFailureHandler(QuicPacketCreator* creator); + ~ScopedSerializationFailureHandler(); private: QuicPacketCreator* creator_; // Unowned. @@ -501,10 +508,11 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // Serializes all frames which have been added and adds any which should be // retransmitted to packet_.retransmittable_frames. All frames must fit into - // a single packet. - // Fails if |encrypted_buffer_len| isn't long enough for the encrypted packet. - void SerializePacket(QuicOwnedPacketBuffer encrypted_buffer, - size_t encrypted_buffer_len); + // a single packet. Returns true on success, otherwise, returns false. + // Fails if |encrypted_buffer| is not large enough for the encrypted packet. + QUIC_MUST_USE_RESULT bool SerializePacket( + QuicOwnedPacketBuffer encrypted_buffer, + size_t encrypted_buffer_len); // Called after a new SerialiedPacket is created to call the delegate's // OnSerializedPacket and reset state. @@ -655,22 +663,8 @@ class QUIC_EXPORT_PRIVATE QuicPacketCreator { // negotiates this during the handshake. QuicByteCount max_datagram_frame_size_; - // When true, this will override the padding generation code to disable it. - // TODO(fayang): remove this when deprecating - // quic_determine_serialized_packet_fate_early. - bool disable_padding_override_ = false; - - const bool update_packet_size_ = - GetQuicReloadableFlag(quic_update_packet_size); - - const bool fix_extra_padding_bytes_ = - GetQuicReloadableFlag(quic_fix_extra_padding_bytes); - - const bool determine_serialized_packet_fate_early_ = - GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early); - - const bool coalesced_packet_of_higher_space_ = - GetQuicReloadableFlag(quic_coalesced_packet_of_higher_space2); + const bool close_connection_on_serialization_failure_ = + GetQuicReloadableFlag(quic_close_connection_on_serialization_failure); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc index 60703fb4b65..4afbf06158a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packet_creator_test.cc @@ -164,10 +164,8 @@ class QuicPacketCreatorTest : public QuicTestWithParam<TestParams> { creator_(connection_id_, &client_framer_, &delegate_, &producer_) { EXPECT_CALL(delegate_, GetPacketBuffer()) .WillRepeatedly(Return(QuicPacketBuffer())); - if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early)) { - EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _)) - .WillRepeatedly(Return(SEND_TO_WRITER)); - } + EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _)) + .WillRepeatedly(Return(SEND_TO_WRITER)); creator_.SetEncrypter(ENCRYPTION_INITIAL, std::make_unique<NullEncrypter>( Perspective::IS_CLIENT)); creator_.SetEncrypter(ENCRYPTION_HANDSHAKE, std::make_unique<NullEncrypter>( @@ -510,8 +508,7 @@ TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) { EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillRepeatedly( Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early) && - client_framer_.version().CanSendCoalescedPackets()) { + if (client_framer_.version().CanSendCoalescedPackets()) { EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _)) .WillRepeatedly(Return(COALESCE)); } @@ -2453,10 +2450,8 @@ class QuicPacketCreatorMultiplePacketsTest : public QuicTest { ack_frame_(InitAckFrame(1)) { EXPECT_CALL(delegate_, GetPacketBuffer()) .WillRepeatedly(Return(QuicPacketBuffer())); - if (GetQuicReloadableFlag(quic_determine_serialized_packet_fate_early)) { - EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _)) - .WillRepeatedly(Return(SEND_TO_WRITER)); - } + EXPECT_CALL(delegate_, GetSerializedPacketFate(_, _)) + .WillRepeatedly(Return(SEND_TO_WRITER)); creator_.SetEncrypter( ENCRYPTION_FORWARD_SECURE, std::make_unique<NullEncrypter>(Perspective::IS_CLIENT)); @@ -2595,9 +2590,6 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, AddControlFrame_NotWritable) { TEST_F(QuicPacketCreatorMultiplePacketsTest, WrongEncryptionLevelForStreamDataFastPath) { - if (!GetQuicReloadableFlag(quic_check_encryption_level_in_fast_path)) { - return; - } creator_.set_encryption_level(ENCRYPTION_HANDSHAKE); delegate_.SetCanWriteAnything(); // Create a 10000 byte IOVector. @@ -3825,12 +3817,136 @@ TEST_F(QuicPacketCreatorMultiplePacketsTest, ExtraPaddingNeeded) { creator_.Flush(); ASSERT_FALSE(packets_[0].nonretransmittable_frames.empty()); QuicFrame padding = packets_[0].nonretransmittable_frames[0]; - if (GetQuicReloadableFlag(quic_fix_extra_padding_bytes)) { - // Verify stream frame expansion is excluded. - padding.padding_frame.num_padding_bytes = 3; - } else { - padding.padding_frame.num_padding_bytes = 4; - } + // Verify stream frame expansion is excluded. + padding.padding_frame.num_padding_bytes = 3; +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + PeerAddressContextWithSameAddress) { + QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345); + creator_.SetDefaultPeerAddress(peer_addr); + // Send some stream data. + MakeIOVector("foo", &iov_); + EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _)) + .WillRepeatedly(Return(true)); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + { + // Set a different address via context which should trigger flush. + QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr); + EXPECT_TRUE(creator_.HasPendingFrames()); + // Queue another STREAM_FRAME. + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + } + // After exiting the scope, the last queued frame should be flushed. + EXPECT_TRUE(creator_.HasPendingFrames()); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce(Invoke([=](SerializedPacket packet) { + EXPECT_EQ(peer_addr, packet.peer_address); + ASSERT_EQ(2u, packet.retransmittable_frames.size()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.back().type); + })); + creator_.FlushCurrentPacket(); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + PeerAddressContextWithDifferentAddress) { + QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345); + creator_.SetDefaultPeerAddress(peer_addr); + // Send some stream data. + MakeIOVector("foo", &iov_); + EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _)) + .WillRepeatedly(Return(true)); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + + QuicSocketAddress peer_addr1(QuicIpAddress::Any4(), 12346); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce(Invoke([=](SerializedPacket packet) { + EXPECT_EQ(peer_addr, packet.peer_address); + ASSERT_EQ(1u, packet.retransmittable_frames.size()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + })) + .WillOnce(Invoke([=](SerializedPacket packet) { + EXPECT_EQ(peer_addr1, packet.peer_address); + ASSERT_EQ(1u, packet.retransmittable_frames.size()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + })); + EXPECT_TRUE(creator_.HasPendingFrames()); + { + // Set a different address via context which should trigger flush. + QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr1); + EXPECT_FALSE(creator_.HasPendingFrames()); + // Queue another STREAM_FRAME. + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + } + // After exiting the scope, the last queued frame should be flushed. + EXPECT_FALSE(creator_.HasPendingFrames()); +} + +TEST_F(QuicPacketCreatorMultiplePacketsTest, + NestedPeerAddressContextWithDifferentAddress) { + QuicSocketAddress peer_addr(QuicIpAddress::Any4(), 12345); + creator_.SetDefaultPeerAddress(peer_addr); + QuicPacketCreator::ScopedPeerAddressContext context(&creator_, peer_addr); + + // Send some stream data. + MakeIOVector("foo", &iov_); + EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _)) + .WillRepeatedly(Return(true)); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId(creator_.transport_version(), + Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + + QuicSocketAddress peer_addr1(QuicIpAddress::Any4(), 12346); + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce(Invoke([=](SerializedPacket packet) { + EXPECT_EQ(peer_addr, packet.peer_address); + ASSERT_EQ(1u, packet.retransmittable_frames.size()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + + // Set up another context with a different address. + QuicPacketCreator::ScopedPeerAddressContext context(&creator_, + peer_addr1); + MakeIOVector("foo", &iov_); + EXPECT_CALL(delegate_, ShouldGeneratePacket(_, _)) + .WillRepeatedly(Return(true)); + QuicConsumedData consumed = creator_.ConsumeData( + QuicUtils::GetFirstBidirectionalStreamId( + creator_.transport_version(), Perspective::IS_CLIENT), + &iov_, 1u, iov_.iov_len, 0, NO_FIN); + EXPECT_EQ(3u, consumed.bytes_consumed); + EXPECT_TRUE(creator_.HasPendingFrames()); + // This should trigger another OnSerializedPacket() with the 2nd + // address. + creator_.FlushCurrentPacket(); + })) + .WillOnce(Invoke([=](SerializedPacket packet) { + EXPECT_EQ(peer_addr1, packet.peer_address); + ASSERT_EQ(1u, packet.retransmittable_frames.size()); + EXPECT_EQ(STREAM_FRAME, packet.retransmittable_frames.front().type); + })); + creator_.FlushCurrentPacket(); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc index 6ffa39a07d1..f54cf00d081 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.cc @@ -463,6 +463,8 @@ SerializedPacket::SerializedPacket(QuicPacketNumber packet_number, has_stop_waiting(has_stop_waiting), transmission_type(NOT_RETRANSMISSION), has_ack_frame_copy(false), + has_ack_frequency(false), + has_message(false), fate(SEND_TO_WRITER) {} SerializedPacket::SerializedPacket(SerializedPacket&& other) @@ -475,7 +477,10 @@ SerializedPacket::SerializedPacket(SerializedPacket&& other) transmission_type(other.transmission_type), largest_acked(other.largest_acked), has_ack_frame_copy(other.has_ack_frame_copy), - fate(other.fate) { + has_ack_frequency(other.has_ack_frequency), + has_message(other.has_message), + fate(other.fate), + peer_address(other.peer_address) { if (this != &other) { if (release_encrypted_buffer && encrypted_buffer != nullptr) { release_encrypted_buffer(encrypted_buffer); @@ -518,7 +523,10 @@ SerializedPacket* CopySerializedPacket(const SerializedPacket& serialized, copy->encryption_level = serialized.encryption_level; copy->transmission_type = serialized.transmission_type; copy->largest_acked = serialized.largest_acked; + copy->has_ack_frequency = serialized.has_ack_frequency; + copy->has_message = serialized.has_message; copy->fate = serialized.fate; + copy->peer_address = serialized.peer_address; if (copy_buffer) { copy->encrypted_buffer = CopyBuffer(serialized); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h index 450b842fcb8..e9c811c6737 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_packets.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_packets.h @@ -403,7 +403,10 @@ struct QUIC_EXPORT_PRIVATE SerializedPacket { // Indicates whether this packet has a copy of ack frame in // nonretransmittable_frames. bool has_ack_frame_copy; + bool has_ack_frequency; + bool has_message; SerializedPacketFate fate; + QuicSocketAddress peer_address; }; // Make a copy of |serialized| (including the underlying frames). |copy_buffer| diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc index 9cc6c295eda..9a84d975fd5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.cc @@ -41,58 +41,30 @@ QuicReceivedPacketManager::QuicReceivedPacketManager(QuicConnectionStats* stats) time_largest_observed_(QuicTime::Zero()), save_timestamps_(false), stats_(stats), - ack_mode_(ACK_DECIMATION), num_retransmittable_packets_received_since_last_ack_sent_(0), min_received_before_ack_decimation_(kMinReceivedBeforeAckDecimation), ack_frequency_(kDefaultRetransmittablePacketsBeforeAck), ack_decimation_delay_(kAckDecimationDelay), unlimited_ack_decimation_(false), - fast_ack_after_quiescence_(false), one_immediate_ack_(false), + ignore_order_(false), local_max_ack_delay_( QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)), ack_timeout_(QuicTime::Zero()), time_of_previous_received_packet_(QuicTime::Zero()), - was_last_packet_missing_(false) {} + was_last_packet_missing_(false), + last_ack_frequency_frame_sequence_number_(-1) {} QuicReceivedPacketManager::~QuicReceivedPacketManager() {} void QuicReceivedPacketManager::SetFromConfig(const QuicConfig& config, Perspective perspective) { - if (remove_unused_ack_options_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_remove_unused_ack_options); - } - if (!remove_unused_ack_options_) { - if (config.HasClientSentConnectionOption(kACD0, perspective)) { - ack_mode_ = TCP_ACKING; - } - if (config.HasClientSentConnectionOption(kACKD, perspective)) { - ack_mode_ = ACK_DECIMATION; - } - if (config.HasClientSentConnectionOption(kAKD2, perspective)) { - ack_mode_ = ACK_DECIMATION_WITH_REORDERING; - } - } if (config.HasClientSentConnectionOption(kAKD3, perspective)) { - if (!remove_unused_ack_options_) { - ack_mode_ = ACK_DECIMATION; - } ack_decimation_delay_ = kShortAckDecimationDelay; } - if (!remove_unused_ack_options_) { - if (config.HasClientSentConnectionOption(kAKD4, perspective)) { - ack_mode_ = ACK_DECIMATION_WITH_REORDERING; - ack_decimation_delay_ = kShortAckDecimationDelay; - } - } if (config.HasClientSentConnectionOption(kAKDU, perspective)) { unlimited_ack_decimation_ = true; } - if (!remove_unused_ack_options_) { - if (config.HasClientSentConnectionOption(kACKQ, perspective)) { - fast_ack_after_quiescence_ = true; - } - } if (config.HasClientSentConnectionOption(k1ACK, perspective)) { one_immediate_ack_ = true; } @@ -189,7 +161,13 @@ const QuicFrame QuicReceivedPacketManager::GetUpdatedAckFrame( } } +#if QUIC_FRAME_DEBUG + QuicFrame frame = QuicFrame(&ack_frame_); + frame.delete_forbidden = true; + return frame; +#else // QUIC_FRAME_DEBUG return QuicFrame(&ack_frame_); +#endif // QUIC_FRAME_DEBUG } void QuicReceivedPacketManager::DontWaitForPacketsBefore( @@ -218,9 +196,9 @@ void QuicReceivedPacketManager::DontWaitForPacketsBefore( QuicTime::Delta QuicReceivedPacketManager::GetMaxAckDelay( QuicPacketNumber last_received_packet_number, const RttStats& rtt_stats) const { - DCHECK(simplify_received_packet_manager_ack_); - if (last_received_packet_number < - PeerFirstSendingPacketNumber() + min_received_before_ack_decimation_) { + if (AckFrequencyFrameReceived() || + last_received_packet_number < PeerFirstSendingPacketNumber() + + min_received_before_ack_decimation_) { return local_max_ack_delay_; } @@ -237,7 +215,11 @@ QuicTime::Delta QuicReceivedPacketManager::GetMaxAckDelay( void QuicReceivedPacketManager::MaybeUpdateAckFrequency( QuicPacketNumber last_received_packet_number) { - DCHECK(simplify_received_packet_manager_ack_); + if (AckFrequencyFrameReceived()) { + // Skip Ack Decimation below after receiving an AckFrequencyFrame from the + // other end point. + return; + } if (last_received_packet_number < PeerFirstSendingPacketNumber() + min_received_before_ack_decimation_) { return; @@ -250,7 +232,6 @@ void QuicReceivedPacketManager::MaybeUpdateAckFrequency( void QuicReceivedPacketManager::MaybeUpdateAckTimeout( bool should_last_packet_instigate_acks, QuicPacketNumber last_received_packet_number, - QuicTime time_of_last_received_packet, QuicTime now, const RttStats* rtt_stats) { if (!ack_frame_updated_) { @@ -258,7 +239,8 @@ void QuicReceivedPacketManager::MaybeUpdateAckTimeout( return; } - if (was_last_packet_missing_ && last_sent_largest_acked_.IsInitialized() && + if (!ignore_order_ && was_last_packet_missing_ && + last_sent_largest_acked_.IsInitialized() && last_received_packet_number < last_sent_largest_acked_) { // Only ack immediately if an ACK frame was sent with a larger largest acked // than the newly received packet number. @@ -272,85 +254,20 @@ void QuicReceivedPacketManager::MaybeUpdateAckTimeout( ++num_retransmittable_packets_received_since_last_ack_sent_; - if (simplify_received_packet_manager_ack_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_simplify_received_packet_manager_ack); - MaybeUpdateAckFrequency(last_received_packet_number); - if (num_retransmittable_packets_received_since_last_ack_sent_ >= - ack_frequency_) { - ack_timeout_ = now; - return; - } - - if (HasNewMissingPackets()) { - ack_timeout_ = now; - return; - } - - MaybeUpdateAckTimeoutTo( - now + GetMaxAckDelay(last_received_packet_number, *rtt_stats)); + MaybeUpdateAckFrequency(last_received_packet_number); + if (num_retransmittable_packets_received_since_last_ack_sent_ >= + ack_frequency_) { + ack_timeout_ = now; return; } - if (ack_mode_ != TCP_ACKING && - last_received_packet_number >= PeerFirstSendingPacketNumber() + - min_received_before_ack_decimation_) { - // Ack up to 10 packets at once unless ack decimation is unlimited. - if (!unlimited_ack_decimation_ && - num_retransmittable_packets_received_since_last_ack_sent_ >= - kMaxRetransmittablePacketsBeforeAck) { - ack_timeout_ = now; - return; - } - // Wait for the minimum of the ack decimation delay or the delayed ack time - // before sending an ack. - QuicTime::Delta ack_delay = std::min( - local_max_ack_delay_, rtt_stats->min_rtt() * ack_decimation_delay_); - if (GetQuicReloadableFlag(quic_ack_delay_alarm_granularity)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_ack_delay_alarm_granularity); - ack_delay = std::max(ack_delay, kAlarmGranularity); - } - if (fast_ack_after_quiescence_ && now - time_of_previous_received_packet_ > - rtt_stats->SmoothedOrInitialRtt()) { - // Ack the first packet out of queiscence faster, because QUIC does - // not pace the first few packets and commonly these may be handshake - // or TLP packets, which we'd like to acknowledge quickly. - ack_delay = kAlarmGranularity; - } - MaybeUpdateAckTimeoutTo(now + ack_delay); - } else { - // Ack with a timer or every 2 packets by default. - if (num_retransmittable_packets_received_since_last_ack_sent_ >= - ack_frequency_) { - ack_timeout_ = now; - } else if (fast_ack_after_quiescence_ && - (now - time_of_previous_received_packet_) > - rtt_stats->SmoothedOrInitialRtt()) { - // Ack the first packet out of queiscence faster, because QUIC does - // not pace the first few packets and commonly these may be handshake - // or TLP packets, which we'd like to acknowledge quickly. - MaybeUpdateAckTimeoutTo(now + kAlarmGranularity); - } else { - MaybeUpdateAckTimeoutTo(now + local_max_ack_delay_); - } - } - - // If there are new missing packets to report, send an ack immediately. - if (HasNewMissingPackets()) { - // TODO(haoyuewang) Remove ACK_DECIMATION_WITH_REORDERING after - // quic_remove_unused_ack_options is deprecated. - if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) { - DCHECK(!remove_unused_ack_options_); - // Wait the minimum of an eighth min_rtt and the existing ack time. - QuicTime ack_time = now + kShortAckDecimationDelay * rtt_stats->min_rtt(); - MaybeUpdateAckTimeoutTo(ack_time); - } else { - ack_timeout_ = now; - } + if (!ignore_order_ && HasNewMissingPackets()) { + ack_timeout_ = now; + return; } - if (fast_ack_after_quiescence_) { - time_of_previous_received_packet_ = time_of_last_received_packet; - } + MaybeUpdateAckTimeoutTo( + now + GetMaxAckDelay(last_received_packet_number, *rtt_stats)); } void QuicReceivedPacketManager::ResetAckStates() { @@ -406,4 +323,17 @@ bool QuicReceivedPacketManager::IsAckFrameEmpty() const { return ack_frame_.packets.Empty(); } +void QuicReceivedPacketManager::OnAckFrequencyFrame( + const QuicAckFrequencyFrame& frame) { + int64_t new_sequence_number = frame.sequence_number; + if (new_sequence_number <= last_ack_frequency_frame_sequence_number_) { + // Ignore old ACK_FREQUENCY frames. + return; + } + last_ack_frequency_frame_sequence_number_ = new_sequence_number; + ack_frequency_ = frame.packet_tolerance; + local_max_ack_delay_ = frame.max_ack_delay; + ignore_order_ = frame.ignore_order; +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h index 5f5525a3ab9..78ed4111585 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager.h @@ -5,6 +5,8 @@ #ifndef QUICHE_QUIC_CORE_QUIC_RECEIVED_PACKET_MANAGER_H_ #define QUICHE_QUIC_CORE_QUIC_RECEIVED_PACKET_MANAGER_H_ +#include <cstddef> +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_framer.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" @@ -62,7 +64,6 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager { // Otherwise, ACK needs to be sent by the specified time. void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks, QuicPacketNumber last_received_packet_number, - QuicTime time_of_last_received_packet, QuicTime now, const RttStats* rtt_stats); @@ -124,6 +125,8 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager { QuicTime ack_timeout() const { return ack_timeout_; } + void OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame); + private: friend class test::QuicConnectionPeer; friend class test::QuicReceivedPacketManagerPeer; @@ -138,6 +141,10 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager { QuicTime::Delta GetMaxAckDelay(QuicPacketNumber last_received_packet_number, const RttStats& rtt_stats) const; + bool AckFrequencyFrameReceived() const { + return last_ack_frequency_frame_sequence_number_ >= 0; + } + // Least packet number of the the packet sent by the peer for which it // hasn't received an ack. QuicPacketNumber peer_least_packet_awaiting_ack_; @@ -165,7 +172,6 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager { QuicConnectionStats* stats_; - AckMode ack_mode_; // How many retransmittable packets have arrived without sending an ack. QuicPacketCount num_retransmittable_packets_received_since_last_ack_sent_; // Ack decimation will start happening after this many packets are received. @@ -177,13 +183,10 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager { // When true, removes ack decimation's max number of packets(10) before // sending an ack. bool unlimited_ack_decimation_; - // When true, use a 1ms delayed ack timer if it's been an SRTT since a packet - // was received. - // TODO(haoyuewang) Remove fast_ack_after_quiescence_ when - // quic_remove_unused_ack_options flag is deprecated. - bool fast_ack_after_quiescence_; // When true, only send 1 immediate ACK when reordering is detected. bool one_immediate_ack_; + // When true, do not ack immediately upon observation of packet reordering. + bool ignore_order_; // The local node's maximum ack delay time. This is the maximum amount of // time to wait before sending an acknowledgement. @@ -197,17 +200,12 @@ class QUIC_EXPORT_PRIVATE QuicReceivedPacketManager { // Whether the most recent packet was missing before it was received. bool was_last_packet_missing_; - // TODO(haoyuewang) Remove TCP_ACKING when - // fast_ack_after_quiescence_ when this flag is deprecated. - const bool remove_unused_ack_options_ = - GetQuicReloadableFlag(quic_remove_unused_ack_options); - - const bool simplify_received_packet_manager_ack_ = - remove_unused_ack_options_ && - GetQuicReloadableFlag(quic_simplify_received_packet_manager_ack); - // Last sent largest acked, which gets updated when ACK was successfully sent. QuicPacketNumber last_sent_largest_acked_; + + // The sequence number of the last received AckFrequencyFrame. Negative if + // none received. + int64_t last_ack_frequency_frame_sequence_number_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc index ca56662904f..c8d16388470 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_received_packet_manager_test.cc @@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h" #include <algorithm> +#include <cstddef> #include <ostream> #include <vector> @@ -22,15 +23,6 @@ namespace test { class QuicReceivedPacketManagerPeer { public: - static void SetAckMode(QuicReceivedPacketManager* manager, AckMode ack_mode) { - manager->ack_mode_ = ack_mode; - } - - static void SetFastAckAfterQuiescence(QuicReceivedPacketManager* manager, - bool fast_ack_after_quiescence) { - manager->fast_ack_after_quiescence_ = fast_ack_after_quiescence; - } - static void SetOneImmediateAck(QuicReceivedPacketManager* manager, bool one_immediate_ack) { manager->one_immediate_ack_ = one_immediate_ack; @@ -97,7 +89,7 @@ class QuicReceivedPacketManagerTest : public QuicTestWithParam<TestParams> { received_manager_.MaybeUpdateAckTimeout( should_last_packet_instigate_acks, QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(), - clock_.ApproximateNow(), &rtt_stats_); + &rtt_stats_); } void CheckAckTimeout(QuicTime time) { @@ -368,8 +360,6 @@ TEST_P(QuicReceivedPacketManagerTest, AckSentEveryNthPacket) { TEST_P(QuicReceivedPacketManagerTest, AckDecimationReducesAcks) { EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, - ACK_DECIMATION_WITH_REORDERING); // Start ack decimation from 10th packet. received_manager_.set_min_received_before_ack_decimation(10); @@ -401,45 +391,8 @@ TEST_P(QuicReceivedPacketManagerTest, AckDecimationReducesAcks) { CheckAckTimeout(clock_.ApproximateNow()); } -TEST_P(QuicReceivedPacketManagerTest, SendDelayedAfterQuiescence) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetFastAckAfterQuiescence(&received_manager_, - true); - // The beginning of the connection counts as quiescence. - QuicTime ack_time = - clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - - RecordPacketReceipt(1, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 1); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - CheckAckTimeout(clock_.ApproximateNow()); - - // Process another packet immediately after sending the ack and expect the - // ack timeout to be set delayed ack time in the future. - ack_time = clock_.ApproximateNow() + kDelayedAckTime; - RecordPacketReceipt(2, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 2); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(kDelayedAckTime); - CheckAckTimeout(clock_.ApproximateNow()); - - // Wait 1 second and enesure the ack timeout is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(3, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 3); - CheckAckTimeout(ack_time); -} - TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimation) { EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION); // The ack time should be based on min_rtt * 1/4, since it's less than the // default delayed ack time. QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; @@ -474,7 +427,6 @@ TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationMin1ms) { return; } EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION); // Seed the min_rtt with a kAlarmGranularity signal. rtt_stats_.UpdateRtt(kAlarmGranularity, QuicTime::Delta::Zero(), clock_.ApproximateNow()); @@ -507,76 +459,6 @@ TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationMin1ms) { } TEST_P(QuicReceivedPacketManagerTest, - SendDelayedAckAckDecimationAfterQuiescence) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION); - QuicReceivedPacketManagerPeer::SetFastAckAfterQuiescence(&received_manager_, - true); - // The beginning of the connection counts as quiescence. - QuicTime ack_time = - clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(1, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 1); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - CheckAckTimeout(clock_.ApproximateNow()); - - // Process another packet immedately after sending the ack and expect the - // ack timeout to be set delayed ack time in the future. - ack_time = clock_.ApproximateNow() + kDelayedAckTime; - RecordPacketReceipt(2, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 2); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(kDelayedAckTime); - CheckAckTimeout(clock_.ApproximateNow()); - - // Wait 1 second and enesure the ack timeout is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(3, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 3); - CheckAckTimeout(ack_time); - // Process enough packets to get into ack decimation behavior. - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 4; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } - EXPECT_FALSE(HasPendingAck()); - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (uint64_t i = 1; i < 10; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); - } - CheckAckTimeout(clock_.ApproximateNow()); - - // Wait 1 second and enesure the ack timeout is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); - CheckAckTimeout(ack_time); -} - -TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationUnlimitedAggregation) { EXPECT_FALSE(HasPendingAck()); QuicConfig config; @@ -619,7 +501,6 @@ TEST_P(QuicReceivedPacketManagerTest, TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) { EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, ACK_DECIMATION); QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_, 0.125); @@ -652,190 +533,123 @@ TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) { CheckAckTimeout(clock_.ApproximateNow()); } -TEST_P(QuicReceivedPacketManagerTest, SendDelayedAckDecimationWithReordering) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } +TEST_F(QuicReceivedPacketManagerTest, + UpdateMaxAckDelayAndAckFrequencyFromAckFrequencyFrame) { EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, - ACK_DECIMATION_WITH_REORDERING); - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; - // Process all the packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + QuicAckFrequencyFrame frame; + frame.max_ack_delay = QuicTime::Delta::FromMilliseconds(10); + frame.packet_tolerance = 5; + received_manager_.OnAckFrequencyFrame(frame); + + for (int i = 1; i <= 50; ++i) { RecordPacketReceipt(i, clock_.ApproximateNow()); MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. + if (i % frame.packet_tolerance == 0) { CheckAckTimeout(clock_.ApproximateNow()); } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } - - // Receive one packet out of order and then the rest in order. - // The loop leaves a one packet gap between acks sent to simulate some loss. - for (int j = 0; j < 3; ++j) { - // Process packet 10 first and ensure the timeout is one eighth min_rtt. - RecordPacketReceipt(kFirstDecimatedPacket + 9 + (j * 11), - clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9 + (j * 11)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (int i = 0; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i + (j * 11), - clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, - kFirstDecimatedPacket + i + (j * 11)); + CheckAckTimeout(clock_.ApproximateNow() + frame.max_ack_delay); } - CheckAckTimeout(clock_.ApproximateNow()); } } -TEST_P(QuicReceivedPacketManagerTest, - SendDelayedAckDecimationWithLargeReordering) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } +TEST_F(QuicReceivedPacketManagerTest, + DisableOutOfOrderAckByIgnoreOrderFromAckFrequencyFrame) { EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, - ACK_DECIMATION_WITH_REORDERING); - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; - // Process all the packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } + QuicAckFrequencyFrame frame; + frame.max_ack_delay = kDelayedAckTime; + frame.packet_tolerance = 2; + frame.ignore_order = true; + received_manager_.OnAckFrequencyFrame(frame); - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); + RecordPacketReceipt(4, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 4); + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + RecordPacketReceipt(5, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 5); + // Immediate ack is sent as this is the 2nd packet of every two packets. + CheckAckTimeout(clock_.ApproximateNow()); - RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); - ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; - CheckAckTimeout(ack_time); + RecordPacketReceipt(3, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 3); + // Don't ack as ignore_order is set by AckFrequencyFrame. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - // The 10th received packet causes an ack to be sent. - for (int i = 1; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); - } + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + // Immediate ack is sent as this is the 2nd packet of every two packets. CheckAckTimeout(clock_.ApproximateNow()); - // The next packet received in order will cause an immediate ack, because it - // fills a hole. - RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); - CheckAckTimeout(clock_.ApproximateNow()); + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + // Don't ack as ignore_order is set by AckFrequencyFrame. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); } -TEST_P(QuicReceivedPacketManagerTest, - SendDelayedAckDecimationWithReorderingEighthRtt) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } +TEST_F(QuicReceivedPacketManagerTest, + DisableMissingPaketsAckByIgnoreOrderFromAckFrequencyFrame) { EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, - ACK_DECIMATION_WITH_REORDERING); - QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_, - 0.125); - // The ack time should be based on min_rtt/8, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + QuicConfig config; + config.SetConnectionOptionsToSend({kAFFE}); + received_manager_.SetFromConfig(config, Perspective::IS_CLIENT); - // Process all the packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } + QuicAckFrequencyFrame frame; + frame.max_ack_delay = kDelayedAckTime; + frame.packet_tolerance = 2; + frame.ignore_order = true; + received_manager_.OnAckFrequencyFrame(frame); - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); + RecordPacketReceipt(1, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 1); + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); + RecordPacketReceipt(2, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 2); + // Immediate ack is sent as this is the 2nd packet of every two packets. + CheckAckTimeout(clock_.ApproximateNow()); - // Process packet 10 first and ensure the timeout is one eighth min_rtt. - RecordPacketReceipt(kFirstDecimatedPacket + 9, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9); - CheckAckTimeout(ack_time); + RecordPacketReceipt(4, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 4); + // Don't ack even if packet 3 is newly missing as ignore_order is set by + // AckFrequencyFrame. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - // The 10th received packet causes an ack to be sent. - for (int i = 1; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck + i, kFirstDecimatedPacket); - } + RecordPacketReceipt(5, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 5); + // Immediate ack is sent as this is the 2nd packet of every two packets. CheckAckTimeout(clock_.ApproximateNow()); + + RecordPacketReceipt(7, clock_.ApproximateNow()); + MaybeUpdateAckTimeout(kInstigateAck, 7); + // Don't ack even if packet 6 is newly missing as ignore_order is set by + // AckFrequencyFrame. + CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); } -TEST_P(QuicReceivedPacketManagerTest, - SendDelayedAckDecimationWithLargeReorderingEighthRtt) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } +TEST_F(QuicReceivedPacketManagerTest, + AckDecimationDisabledWhenAckFrequencyFrameIsReceived) { EXPECT_FALSE(HasPendingAck()); - QuicReceivedPacketManagerPeer::SetAckMode(&received_manager_, - ACK_DECIMATION_WITH_REORDERING); - QuicReceivedPacketManagerPeer::SetAckDecimationDelay(&received_manager_, - 0.125); - // The ack time should be based on min_rtt/8, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; + QuicAckFrequencyFrame frame; + frame.max_ack_delay = kDelayedAckTime; + frame.packet_tolerance = 3; + frame.ignore_order = true; + received_manager_.OnAckFrequencyFrame(frame); + // Process all the packets in order so there aren't missing packets. uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { + uint64_t FiftyPacketsAfterAckDecimation = kFirstDecimatedPacket + 50; + for (uint64_t i = 1; i < FiftyPacketsAfterAckDecimation; ++i) { RecordPacketReceipt(i, clock_.ApproximateNow()); MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. + if (i % 3 == 0) { + // Ack every 3 packets as decimation is disabled. CheckAckTimeout(clock_.ApproximateNow()); } else { + // Ack at default delay as decimation is disabled. CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); } } - - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); - - RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (int i = 1; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); - } - CheckAckTimeout(clock_.ApproximateNow()); - - // The next packet received in order will cause an immediate ack, because it - // fills a hole. - RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); - CheckAckTimeout(clock_.ApproximateNow()); } } // namespace diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc index 4746eaecc52..4dc25828378 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.cc @@ -105,6 +105,7 @@ QuicSentPacketManager::QuicSentPacketManager( pto_rttvar_multiplier_(4), num_tlp_timeout_ptos_(0), handshake_packet_acked_(false), + zero_rtt_packet_acked_(false), one_rtt_packet_acked_(false), one_rtt_packet_sent_(false), first_pto_srtt_multiplier_(0), @@ -559,6 +560,11 @@ QuicTime QuicSentPacketManager::GetEarliestPacketSentTimeForPto( bool QuicSentPacketManager::ShouldArmPtoForApplicationData() const { DCHECK(supports_multiple_packet_number_spaces()); + if (GetQuicReloadableFlag(quic_fix_arm_pto_for_application_data)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_arm_pto_for_application_data); + // Do not arm PTO for application data until handshake gets confirmed. + return handshake_finished_; + } // Application data must be ignored before handshake completes (1-RTT key // is available). Not arming PTO for application data to prioritize the // completion of handshake. On the server side, handshake_finished_ @@ -640,6 +646,13 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number, QuicTime ack_receive_time, QuicTime::Delta ack_delay_time, QuicTime receive_timestamp) { + if (info->has_ack_frequency) { + for (const auto& frame : info->retransmittable_frames) { + if (frame.type == ACK_FREQUENCY_FRAME) { + OnAckFrequencyFrameAcked(*frame.ack_frequency_frame); + } + } + } // Try to aggregate acked stream frames if acked packet is not a // retransmission. if (info->transmission_type == NOT_RETRANSMISSION) { @@ -688,36 +701,58 @@ void QuicSentPacketManager::MarkPacketHandled(QuicPacketNumber packet_number, } bool QuicSentPacketManager::OnPacketSent( - SerializedPacket* serialized_packet, + SerializedPacket* mutable_packet, QuicTime sent_time, TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data) { - QuicPacketNumber packet_number = serialized_packet->packet_number; + HasRetransmittableData has_retransmittable_data, + bool measure_rtt) { + const SerializedPacket& packet = *mutable_packet; + QuicPacketNumber packet_number = packet.packet_number; DCHECK_LE(FirstSendingPacketNumber(), packet_number); DCHECK(!unacked_packets_.IsUnacked(packet_number)); - QUIC_BUG_IF(serialized_packet->encrypted_length == 0) - << "Cannot send empty packets."; + QUIC_BUG_IF(packet.encrypted_length == 0) << "Cannot send empty packets."; if (pending_timer_transmission_count_ > 0) { --pending_timer_transmission_count_; } bool in_flight = has_retransmittable_data == HAS_RETRANSMITTABLE_DATA; if (using_pacing_) { - pacing_sender_.OnPacketSent( - sent_time, unacked_packets_.bytes_in_flight(), packet_number, - serialized_packet->encrypted_length, has_retransmittable_data); + pacing_sender_.OnPacketSent(sent_time, unacked_packets_.bytes_in_flight(), + packet_number, packet.encrypted_length, + has_retransmittable_data); } else { - send_algorithm_->OnPacketSent( - sent_time, unacked_packets_.bytes_in_flight(), packet_number, - serialized_packet->encrypted_length, has_retransmittable_data); + send_algorithm_->OnPacketSent(sent_time, unacked_packets_.bytes_in_flight(), + packet_number, packet.encrypted_length, + has_retransmittable_data); } - if (serialized_packet->encryption_level == ENCRYPTION_FORWARD_SECURE) { + if (packet.encryption_level == ENCRYPTION_FORWARD_SECURE) { one_rtt_packet_sent_ = true; } - unacked_packets_.AddSentPacket(serialized_packet, transmission_type, - sent_time, in_flight); + if (GetQuicReloadableFlag(quic_deallocate_message_right_after_sent)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_deallocate_message_right_after_sent); + // Deallocate message data in QuicMessageFrame immediately after packet + // sent. + if (packet.has_message) { + for (auto& frame : mutable_packet->retransmittable_frames) { + if (frame.type == MESSAGE_FRAME) { + frame.message_frame->message_data.clear(); + frame.message_frame->message_length = 0; + } + } + } + } + + if (packet.has_ack_frequency) { + for (const auto& frame : packet.retransmittable_frames) { + if (frame.type == ACK_FREQUENCY_FRAME) { + OnAckFrequencyFrameSent(*frame.ack_frequency_frame); + } + } + } + unacked_packets_.AddSentPacket(mutable_packet, transmission_type, sent_time, + in_flight, measure_rtt); // Reset the retransmission timer anytime a pending packet is sent. return in_flight; } @@ -767,6 +802,8 @@ QuicSentPacketManager::OnRetransmissionTimeout() { pending_timer_transmission_count_ = max_probe_packets_per_pto_; return PTO_MODE; } + QUIC_BUG << "Unknown retransmission mode " << GetRetransmissionMode(); + return GetRetransmissionMode(); } void QuicSentPacketManager::RetransmitCryptoPackets() { @@ -921,6 +958,10 @@ void QuicSentPacketManager::EnableIetfPtoAndLossDetection() { max_probe_packets_per_pto_ = 1; skip_packet_number_for_pto_ = true; first_pto_srtt_multiplier_ = 1.5; + if (GetQuicReloadableFlag(quic_default_to_2_rttvar)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_default_to_2_rttvar); + pto_rttvar_multiplier_ = 2; + } } void QuicSentPacketManager::StartExponentialBackoffAfterNthPto( @@ -942,6 +983,11 @@ void QuicSentPacketManager::RetransmitDataOfSpaceIfAny( unacked_packets_.HasRetransmittableFrames(*it) && unacked_packets_.GetPacketNumberSpace(it->encryption_level) == space) { DCHECK(it->in_flight); + if (GetQuicReloadableFlag(quic_fix_pto_pending_timer_count) && + pending_timer_transmission_count_ == 0) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_pto_pending_timer_count); + pending_timer_transmission_count_ = 1; + } MarkForRetransmission(packet_number, PTO_RETRANSMISSION); return; } @@ -1250,10 +1296,8 @@ const QuicTime::Delta QuicSentPacketManager::GetProbeTimeoutDelay( QuicTime::Delta::FromMilliseconds(kMinHandshakeTimeoutMs)) * (1 << consecutive_pto_count_); } - if (GetQuicReloadableFlag(quic_use_half_rtt_as_first_pto) && - enable_half_rtt_tail_loss_probe_ && consecutive_pto_count_ == 0 && + if (enable_half_rtt_tail_loss_probe_ && consecutive_pto_count_ == 0 && handshake_finished_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_use_half_rtt_as_first_pto); return std::max(min_tlp_timeout_, rtt_stats_.smoothed_rtt() * 0.5); } const QuicTime::Delta rtt_var = use_standard_deviation_for_pto_ @@ -1432,8 +1476,9 @@ AckResult QuicSentPacketManager::OnAckFrameEnd( last_ack_frame_.packets.Add(acked_packet.packet_number); if (info->encryption_level == ENCRYPTION_HANDSHAKE) { handshake_packet_acked_ = true; - } - if (info->encryption_level == ENCRYPTION_FORWARD_SECURE) { + } else if (info->encryption_level == ENCRYPTION_ZERO_RTT) { + zero_rtt_packet_acked_ = true; + } else if (info->encryption_level == ENCRYPTION_FORWARD_SECURE) { one_rtt_packet_acked_ = true; } largest_packet_peer_knows_is_acked_.UpdateMax(info->largest_acked); @@ -1488,8 +1533,13 @@ NextReleaseTimeResult QuicSentPacketManager::GetNextReleaseTime() const { void QuicSentPacketManager::SetInitialRtt(QuicTime::Delta rtt) { const QuicTime::Delta min_rtt = QuicTime::Delta::FromMicroseconds(kMinInitialRoundTripTimeUs); - const QuicTime::Delta max_rtt = + QuicTime::Delta max_rtt = QuicTime::Delta::FromMicroseconds(kMaxInitialRoundTripTimeUs); + if (GetQuicReloadableFlag(quic_cap_large_client_initial_rtt)) { + // TODO(fayang): change the value of kMaxInitialRoundTripTimeUs when + // deprecating quic_cap_large_client_initial_rtt. + max_rtt = QuicTime::Delta::FromSeconds(1); + } rtt_stats_.set_initial_rtt(std::max(min_rtt, std::min(max_rtt, rtt))); } @@ -1507,10 +1557,6 @@ QuicPacketNumber QuicSentPacketManager::GetLargestAckedPacket( QuicPacketNumber QuicSentPacketManager::GetLeastPacketAwaitedByPeer( EncryptionLevel encryption_level) const { - if (!fix_packet_number_length_) { - return GetLeastUnacked(); - } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_fix_packet_number_length, 1, 2); QuicPacketNumber largest_acked; if (supports_multiple_packet_number_spaces()) { largest_acked = GetLargestAckedPacket(encryption_level); @@ -1591,5 +1637,37 @@ QuicTime::Delta QuicSentPacketManager::GetPtoDelay() const { : GetRetransmissionDelay(); } +void QuicSentPacketManager::OnAckFrequencyFrameSent( + const QuicAckFrequencyFrame& ack_frequency_frame) { + in_use_sent_ack_delays_.emplace_back(ack_frequency_frame.max_ack_delay, + ack_frequency_frame.sequence_number); + if (ack_frequency_frame.max_ack_delay > peer_max_ack_delay_) { + peer_max_ack_delay_ = ack_frequency_frame.max_ack_delay; + } +} + +void QuicSentPacketManager::OnAckFrequencyFrameAcked( + const QuicAckFrequencyFrame& ack_frequency_frame) { + int stale_entry_count = 0; + for (auto it = in_use_sent_ack_delays_.cbegin(); + it != in_use_sent_ack_delays_.cend(); ++it) { + if (it->second < ack_frequency_frame.sequence_number) { + ++stale_entry_count; + } else { + break; + } + } + if (stale_entry_count > 0) { + in_use_sent_ack_delays_.pop_front_n(stale_entry_count); + } + if (in_use_sent_ack_delays_.empty()) { + QUIC_BUG << "in_use_sent_ack_delays_ is empty."; + return; + } + peer_max_ack_delay_ = std::max_element(in_use_sent_ack_delays_.cbegin(), + in_use_sent_ack_delays_.cend()) + ->first; +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h index 9e5bd969047..6e36da9f6b5 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h @@ -6,6 +6,7 @@ #define QUICHE_QUIC_CORE_QUIC_SENT_PACKET_MANAGER_H_ #include <cstddef> +#include <cstdint> #include <map> #include <memory> #include <set> @@ -18,6 +19,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" #include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h" #include "net/third_party/quiche/src/quic/core/proto/cached_network_parameters_proto.h" +#include "net/third_party/quiche/src/quic/core/quic_circular_deque.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_sustained_bandwidth_recorder.h" #include "net/third_party/quiche/src/quic/core/quic_transmission_info.h" @@ -186,12 +188,14 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { } // Called when we have sent bytes to the peer. This informs the manager both - // the number of bytes sent and if they were retransmitted. Returns true if - // the sender should reset the retransmission timer. - bool OnPacketSent(SerializedPacket* serialized_packet, + // the number of bytes sent and if they were retransmitted and if this packet + // is used for rtt measuring. Returns true if the sender should reset the + // retransmission timer. + bool OnPacketSent(SerializedPacket* mutable_packet, QuicTime sent_time, TransmissionType transmission_type, - HasRetransmittableData has_retransmittable_data); + HasRetransmittableData has_retransmittable_data, + bool measure_rtt); // Called when the retransmission timer expires and returns the retransmission // mode. @@ -432,11 +436,15 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { return skip_packet_number_for_pto_; } + bool zero_rtt_packet_acked() const { return zero_rtt_packet_acked_; } + bool one_rtt_packet_acked() const { return one_rtt_packet_acked_; } void OnUserAgentIdKnown() { loss_algorithm_->OnUserAgentIdKnown(); } - bool fix_packet_number_length() const { return fix_packet_number_length_; } + bool give_sent_packet_to_debug_visitor_after_sent() const { + return give_sent_packet_to_debug_visitor_after_sent_; + } private: friend class test::QuicConnectionPeer; @@ -550,6 +558,14 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // retransmission timer is not armed if there is no packets in flight. bool PeerCompletedAddressValidation() const; + // Called when an AckFrequencyFrame is sent. + void OnAckFrequencyFrameSent( + const QuicAckFrequencyFrame& ack_frequency_frame); + + // Called when an AckFrequencyFrame is acked. + void OnAckFrequencyFrameAcked( + const QuicAckFrequencyFrame& ack_frequency_frame); + // Newly serialized retransmittable packets are added to this map, which // contains owning pointers to any contained frames. If a packet is // retransmitted, this map will contain entries for both the old and the new @@ -629,11 +645,17 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { QuicPacketNumber largest_packets_peer_knows_is_acked_[NUM_PACKET_NUMBER_SPACES]; - // The maximum ACK delay time that the peer uses. Initialized to be the + // The maximum ACK delay time that the peer might uses. Initialized to be the // same as local_max_ack_delay_, may be changed via transport parameter - // negotiation. + // negotiation or subsequently by AckFrequencyFrame. QuicTime::Delta peer_max_ack_delay_; + // The history of outstanding max_ack_delays sent to peer. Outstanding means + // a max_ack_delay is sent as part of the last acked AckFrequencyFrame or + // an unacked AckFrequencyFrame after that. + QuicCircularDeque<std::pair<QuicTime::Delta, /*sequence_number=*/uint64_t>> + in_use_sent_ack_delays_; + // Latest received ack frame. QuicAckFrame last_ack_frame_; @@ -677,6 +699,9 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // True if any ENCRYPTION_HANDSHAKE packet gets acknowledged. bool handshake_packet_acked_; + // True if any 0-RTT packet gets acknowledged. + bool zero_rtt_packet_acked_; + // True if any 1-RTT packet gets acknowledged. bool one_rtt_packet_acked_; @@ -695,8 +720,8 @@ class QUIC_EXPORT_PRIVATE QuicSentPacketManager { // available. float pto_multiplier_without_rtt_samples_; - const bool fix_packet_number_length_ = - GetQuicReloadableFlag(quic_fix_packet_number_length); + const bool give_sent_packet_to_debug_visitor_after_sent_ = + GetQuicReloadableFlag(quic_give_sent_packet_to_debug_visitor_after_sent); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc index 57abfab5fda..c186f65099b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_sent_packet_manager_test.cc @@ -7,6 +7,8 @@ #include <memory> #include <utility> +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_time.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" @@ -69,7 +71,7 @@ class QuicSentPacketManagerTest : public QuicTest { QuicFrame(QuicStreamFrame(1, false, 0, quiche::QuicheStringPiece()))); packet.has_crypto_handshake = IS_HANDSHAKE; manager_.OnPacketSent(&packet, clock_.Now(), HANDSHAKE_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); } void RetransmitDataPacket(uint64_t packet_number, @@ -81,8 +83,8 @@ class QuicSentPacketManagerTest : public QuicTest { kDefaultLength, HAS_RETRANSMITTABLE_DATA)); SerializedPacket packet(CreatePacket(packet_number, true)); packet.encryption_level = level; - manager_.OnPacketSent(&packet, clock_.Now(), type, - HAS_RETRANSMITTABLE_DATA); + manager_.OnPacketSent(&packet, clock_.Now(), type, HAS_RETRANSMITTABLE_DATA, + true); } void RetransmitDataPacket(uint64_t packet_number, TransmissionType type) { @@ -238,7 +240,7 @@ class QuicSentPacketManagerTest : public QuicTest { kDefaultLength, HAS_RETRANSMITTABLE_DATA)); SerializedPacket packet(CreatePacket(new_packet_number, true)); manager_.OnPacketSent(&packet, clock_.Now(), transmission_type, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); } SerializedPacket CreateDataPacket(uint64_t packet_number) { @@ -276,7 +278,7 @@ class QuicSentPacketManagerTest : public QuicTest { SerializedPacket packet(CreateDataPacket(packet_number)); packet.encryption_level = encryption_level; manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); } void SendPingPacket(uint64_t packet_number, @@ -287,7 +289,7 @@ class QuicSentPacketManagerTest : public QuicTest { SerializedPacket packet(CreatePingPacket(packet_number)); packet.encryption_level = encryption_level; manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); } void SendCryptoPacket(uint64_t packet_number) { @@ -300,7 +302,7 @@ class QuicSentPacketManagerTest : public QuicTest { QuicFrame(QuicStreamFrame(1, false, 0, quiche::QuicheStringPiece()))); packet.has_crypto_handshake = IS_HANDSHAKE; manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); EXPECT_CALL(notifier_, HasUnackedCryptoData()).WillRepeatedly(Return(true)); } @@ -319,7 +321,7 @@ class QuicSentPacketManagerTest : public QuicTest { packet.largest_acked = QuicPacketNumber(largest_acked); packet.encryption_level = level; manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, - NO_RETRANSMITTABLE_DATA); + NO_RETRANSMITTABLE_DATA, true); } void EnablePto(QuicTag tag) { @@ -333,6 +335,18 @@ class QuicSentPacketManagerTest : public QuicTest { EXPECT_TRUE(manager_.pto_enabled()); } + int GetPtoRttvarMultiplier() { + if (GetQuicReloadableFlag(quic_default_on_pto)) { + return 2; + } + if (GetQuicReloadableFlag(quic_default_to_2_rttvar) && + manager_.handshake_mode_disabled()) { + return 2; + } + return 4; + } + + SimpleBufferAllocator allocator_; QuicSentPacketManager manager_; MockClock clock_; QuicConnectionStats stats_; @@ -2195,7 +2209,7 @@ TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) { TEST_F(QuicSentPacketManagerTest, ResumeConnectionState) { // The sent packet manager should use the RTT from CachedNetworkParameters if // it is provided. - const QuicTime::Delta kRtt = QuicTime::Delta::FromMilliseconds(1234); + const QuicTime::Delta kRtt = QuicTime::Delta::FromMilliseconds(123); CachedNetworkParameters cached_network_params; cached_network_params.set_min_rtt_ms(kRtt.ToMilliseconds()); @@ -2272,7 +2286,7 @@ TEST_F(QuicSentPacketManagerTest, PathMtuIncreased) { SerializedPacket packet(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength + 100, false, false); manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); // Ack the large packet and expect the path MTU to increase. ExpectAck(1); @@ -2640,10 +2654,8 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); QuicTime packet1_sent_time = clock_.Now(); EXPECT_EQ(clock_.Now() + expected_pto_delay, @@ -2693,7 +2705,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeout) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), + std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -2719,10 +2731,8 @@ TEST_F(QuicSentPacketManagerTest, SendOneProbePacket) { QuicTime::Delta::Zero(), QuicTime::Zero()); QuicTime::Delta srtt = rtt_stats->smoothed_rtt(); // Verify PTO period is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); QuicTime deadline = clock_.Now() + expected_pto_delay; if (GetQuicReloadableFlag(quic_default_on_pto)) { @@ -2825,10 +2835,8 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set and ack delay is included. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(clock_.Now() + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -2875,7 +2883,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), + std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -2909,7 +2917,7 @@ TEST_F(QuicSentPacketManagerTest, PtoTimeoutIncludesMaxAckDelay) { expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), + std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); for (size_t i = 101; i < 110; i++) { @@ -2949,10 +2957,8 @@ TEST_F(QuicSentPacketManagerTest, StartExponentialBackoffSince2ndPto) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3160,10 +3166,8 @@ TEST_F(QuicSentPacketManagerTest, Aggressive1Pto) { // Verify PTO period gets set correctly. QuicTime sent_time = clock_.Now(); - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(sent_time + expected_pto_delay * 2, manager_.GetRetransmissionTime()); @@ -3224,10 +3228,8 @@ TEST_F(QuicSentPacketManagerTest, Aggressive2Ptos) { RetransmitDataPacket(5, type, ENCRYPTION_FORWARD_SECURE); }))); manager_.MaybeSendProbePackets(); - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); // Verify PTO period gets set correctly. @@ -3264,10 +3266,8 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) { // Send packet 1. SendDataPacket(1, ENCRYPTION_INITIAL); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::Zero(); EXPECT_EQ(clock_.Now() + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3327,18 +3327,32 @@ TEST_F(QuicSentPacketManagerTest, ClientMultiplePacketNumberSpacePtoTimeout) { // Send packet 7 in handshake. clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + const QuicTime packet7_sent_time = clock_.Now(); SendDataPacket(7, ENCRYPTION_HANDSHAKE); - // Verify PTO timeout is now based on packet 6. - expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + - QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); - EXPECT_EQ(packet6_sent_time + expected_pto_delay * 2, - manager_.GetRetransmissionTime()); + + if (GetQuicReloadableFlag(quic_fix_arm_pto_for_application_data)) { + expected_pto_delay = + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(); + // Verify PTO timeout is now based on packet 7. + EXPECT_EQ(packet7_sent_time + expected_pto_delay * 2, + manager_.GetRetransmissionTime()); + + } else { + expected_pto_delay = + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); + // Verify PTO timeout is now based on packet 6. + EXPECT_EQ(packet6_sent_time + expected_pto_delay * 2, + manager_.GetRetransmissionTime()); + } // Neuter handshake key. manager_.SetHandshakeConfirmed(); // Forward progress has been made, verify PTO counter gets reset. PTO timeout // is armed by left edge. + expected_pto_delay = + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(packet4_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); } @@ -3359,10 +3373,8 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) { SendDataPacket(1, ENCRYPTION_INITIAL); const QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::Zero(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3397,7 +3409,7 @@ TEST_F(QuicSentPacketManagerTest, ServerMultiplePacketNumberSpacePtoTimeout) { // Discard handshake keys. manager_.SetHandshakeConfirmed(); expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); // Verify PTO timeout is now based on packet 3 as handshake is // complete/confirmed. @@ -3429,10 +3441,8 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); const QuicTime packet1_sent_time = clock_.Now(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, @@ -3472,7 +3482,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), + std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -3505,10 +3515,8 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); const QuicTime packet1_sent_time = clock_.Now(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, @@ -3538,7 +3546,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { // Verify PTO period gets set to twice the expected value and based on // packet3 (right edge). expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); QuicTime packet3_sent_time = clock_.Now(); EXPECT_EQ(packet3_sent_time + expected_pto_delay * 2, @@ -3555,7 +3563,7 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutByLeftEdge2) { ENCRYPTION_FORWARD_SECURE)); expected_pto_delay = rtt_stats->SmoothedOrInitialRtt() + - std::max(pto_rttvar_multiplier * rtt_stats->mean_deviation(), + std::max(GetPtoRttvarMultiplier() * rtt_stats->mean_deviation(), QuicTime::Delta::FromMilliseconds(1)) + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); @@ -3595,10 +3603,9 @@ TEST_F(QuicSentPacketManagerTest, ComputingProbeTimeoutUsingStandardDeviation) { SendDataPacket(1, ENCRYPTION_FORWARD_SECURE); // Verify PTO is correctly set using standard deviation. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->GetStandardOrMeanDeviation() + + srtt + + GetPtoRttvarMultiplier() * rtt_stats->GetStandardOrMeanDeviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(clock_.Now() + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3632,10 +3639,8 @@ TEST_F(QuicSentPacketManagerTest, SendDataPacket(1, ENCRYPTION_INITIAL); const QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::Zero(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3672,7 +3677,7 @@ TEST_F(QuicSentPacketManagerTest, // Verify PTO timeout is now based on packet 3 as handshake is // complete/confirmed. expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(packet3_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3712,10 +3717,8 @@ TEST_F(QuicSentPacketManagerTest, SendDataPacket(1, ENCRYPTION_INITIAL); const QuicTime packet1_sent_time = clock_.Now(); // Verify PTO is correctly set. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::Zero(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3752,7 +3755,7 @@ TEST_F(QuicSentPacketManagerTest, // Verify PTO timeout is now based on packet 3 as handshake is // complete/confirmed. expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); EXPECT_EQ(packet3_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -3982,11 +3985,9 @@ TEST_F(QuicSentPacketManagerTest, ClearLastInflightPacketsSentTime) { manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), ENCRYPTION_INITIAL)); RttStats* rtt_stats = const_cast<RttStats*>(manager_.GetRttStats()); - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; const QuicTime::Delta pto_delay = rtt_stats->smoothed_rtt() + - pto_rttvar_multiplier * rtt_stats->mean_deviation() + + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::Zero(); // Verify PTO is armed based on handshake data. EXPECT_EQ(packet2_sent_time + pto_delay, manager_.GetRetransmissionTime()); @@ -4057,10 +4058,8 @@ TEST_F(QuicSentPacketManagerTest, MaybeRetransmitInitialData) { QuicTime packet2_sent_time = clock_.Now(); SendDataPacket(3, ENCRYPTION_HANDSHAKE); // Verify PTO is correctly set based on packet 1. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; QuicTime::Delta expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::Zero(); EXPECT_EQ(packet1_sent_time + expected_pto_delay, manager_.GetRetransmissionTime()); @@ -4141,7 +4140,6 @@ TEST_F(QuicSentPacketManagerTest, ClientOnlyTLPR) { } TEST_F(QuicSentPacketManagerTest, PtoWithTlpr) { - SetQuicReloadableFlag(quic_use_half_rtt_as_first_pto, true); QuicConfig config; QuicTagVector options; @@ -4180,16 +4178,247 @@ TEST_F(QuicSentPacketManagerTest, PtoWithTlpr) { manager_.MaybeSendProbePackets(); // Verify PTO period gets set correctly. - int pto_rttvar_multiplier = - GetQuicReloadableFlag(quic_default_on_pto) ? 2 : 4; expected_pto_delay = - srtt + pto_rttvar_multiplier * rtt_stats->mean_deviation() + + srtt + GetPtoRttvarMultiplier() * rtt_stats->mean_deviation() + QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs); QuicTime sent_time = clock_.Now(); EXPECT_EQ(sent_time + expected_pto_delay * 2, manager_.GetRetransmissionTime()); } +TEST_F(QuicSentPacketManagerTest, SendPathChallengeAndGetAck) { + QuicPacketNumber packet_number(1); + EXPECT_CALL(*send_algorithm_, + OnPacketSent(_, BytesInFlight(), packet_number, _, _)); + SerializedPacket packet(packet_number, PACKET_4BYTE_PACKET_NUMBER, nullptr, + kDefaultLength, false, false); + QuicPathFrameBuffer path_frame_buffer{0, 1, 2, 3, 4, 5, 6, 7}; + packet.nonretransmittable_frames.push_back( + QuicFrame(new QuicPathChallengeFrame(0, path_frame_buffer))); + packet.encryption_level = ENCRYPTION_FORWARD_SECURE; + manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, + NO_RETRANSMITTABLE_DATA, false); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); + EXPECT_CALL(*send_algorithm_, + OnCongestionEvent(/*rtt_updated=*/false, _, _, + Pointwise(PacketNumberEq(), {1}), IsEmpty())); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + + // Get ACK for the packet. + manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); + EXPECT_EQ(PACKETS_NEWLY_ACKED, + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE)); +} + +SerializedPacket MakePacketWithAckFrequencyFrame( + int packet_number, + int ack_frequency_sequence_number, + QuicTime::Delta max_ack_delay) { + auto* ack_frequency_frame = new QuicAckFrequencyFrame(); + ack_frequency_frame->max_ack_delay = max_ack_delay; + ack_frequency_frame->sequence_number = ack_frequency_sequence_number; + SerializedPacket packet(QuicPacketNumber(packet_number), + PACKET_4BYTE_PACKET_NUMBER, nullptr, kDefaultLength, + /*has_ack=*/false, + /*has_stop_waiting=*/false); + packet.retransmittable_frames.push_back(QuicFrame(ack_frequency_frame)); + packet.has_ack_frequency = true; + packet.encryption_level = ENCRYPTION_FORWARD_SECURE; + return packet; +} + +TEST_F(QuicSentPacketManagerTest, + PeerMaxAckDelayUpdatedFromAckFrequencyFrameOneAtATime) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)) + .Times(AnyNumber()); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()) + .Times(AnyNumber()); + + auto initial_peer_max_ack_delay = manager_.peer_max_ack_delay(); + auto one_ms = QuicTime::Delta::FromMilliseconds(1); + auto plus_1_ms_delay = initial_peer_max_ack_delay + one_ms; + auto minus_1_ms_delay = initial_peer_max_ack_delay - one_ms; + + // Send and Ack frame1. + SerializedPacket packet1 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/1, /*ack_frequency_sequence_number=*/1, + plus_1_ms_delay); + // Higher on the fly max_ack_delay changes peer_max_ack_delay. + manager_.OnPacketSent(&packet1, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + EXPECT_EQ(manager_.peer_max_ack_delay(), plus_1_ms_delay); + manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), plus_1_ms_delay); + + // Send and Ack frame2. + SerializedPacket packet2 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/2, /*ack_frequency_sequence_number=*/2, + minus_1_ms_delay); + // Lower on the fly max_ack_delay does not change peer_max_ack_delay. + manager_.OnPacketSent(&packet2, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + EXPECT_EQ(manager_.peer_max_ack_delay(), plus_1_ms_delay); + manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(2), QuicPacketNumber(3)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(2), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), minus_1_ms_delay); +} + +TEST_F(QuicSentPacketManagerTest, + PeerMaxAckDelayUpdatedFromInOrderAckFrequencyFrames) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)) + .Times(AnyNumber()); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()) + .Times(AnyNumber()); + + auto initial_peer_max_ack_delay = manager_.peer_max_ack_delay(); + auto one_ms = QuicTime::Delta::FromMilliseconds(1); + auto extra_1_ms = initial_peer_max_ack_delay + one_ms; + auto extra_2_ms = initial_peer_max_ack_delay + 2 * one_ms; + auto extra_3_ms = initial_peer_max_ack_delay + 3 * one_ms; + SerializedPacket packet1 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/1, /*ack_frequency_sequence_number=*/1, extra_1_ms); + SerializedPacket packet2 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/2, /*ack_frequency_sequence_number=*/2, extra_3_ms); + SerializedPacket packet3 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/3, /*ack_frequency_sequence_number=*/3, extra_2_ms); + + // Send frame1, farme2, frame3. + manager_.OnPacketSent(&packet1, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_1_ms); + manager_.OnPacketSent(&packet2, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms); + manager_.OnPacketSent(&packet3, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms); + + // Ack frame1, farme2, frame3. + manager_.OnAckFrameStart(QuicPacketNumber(1), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms); + manager_.OnAckFrameStart(QuicPacketNumber(2), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(3)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_3_ms); + manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms); +} + +TEST_F(QuicSentPacketManagerTest, + PeerMaxAckDelayUpdatedFromOutOfOrderAckedAckFrequencyFrames) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); + EXPECT_CALL(*send_algorithm_, OnCongestionEvent(_, _, _, _, _)) + .Times(AnyNumber()); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()) + .Times(AnyNumber()); + + auto initial_peer_max_ack_delay = manager_.peer_max_ack_delay(); + auto one_ms = QuicTime::Delta::FromMilliseconds(1); + auto extra_1_ms = initial_peer_max_ack_delay + one_ms; + auto extra_2_ms = initial_peer_max_ack_delay + 2 * one_ms; + auto extra_3_ms = initial_peer_max_ack_delay + 3 * one_ms; + auto extra_4_ms = initial_peer_max_ack_delay + 4 * one_ms; + SerializedPacket packet1 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/1, /*ack_frequency_sequence_number=*/1, extra_4_ms); + SerializedPacket packet2 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/2, /*ack_frequency_sequence_number=*/2, extra_3_ms); + SerializedPacket packet3 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/3, /*ack_frequency_sequence_number=*/3, extra_2_ms); + SerializedPacket packet4 = MakePacketWithAckFrequencyFrame( + /*packet_number=*/4, /*ack_frequency_sequence_number=*/4, extra_1_ms); + + // Send frame1, farme2, frame3, frame4. + manager_.OnPacketSent(&packet1, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + manager_.OnPacketSent(&packet2, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + manager_.OnPacketSent(&packet3, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + manager_.OnPacketSent(&packet4, clock_.Now(), NOT_RETRANSMISSION, + NO_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_4_ms); + + // Ack frame3. + manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms); + // Acking frame1 do not affect peer_max_ack_delay after frame3 is acked. + manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(3), QuicPacketNumber(4)); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms); + // Acking frame2 do not affect peer_max_ack_delay after frame3 is acked. + manager_.OnAckFrameStart(QuicPacketNumber(3), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(4)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_2_ms); + // Acking frame4 updates peer_max_ack_delay. + manager_.OnAckFrameStart(QuicPacketNumber(4), QuicTime::Delta::Infinite(), + clock_.Now()); + manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(5)); + manager_.OnAckFrameEnd(clock_.Now(), QuicPacketNumber(1), + ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(manager_.peer_max_ack_delay(), extra_1_ms); +} + +TEST_F(QuicSentPacketManagerTest, ClearDataInMessageFrameAfterPacketSent) { + SetQuicReloadableFlag(quic_deallocate_message_right_after_sent, true); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + + QuicMessageFrame* message_frame = nullptr; + { + QuicMemSlice slice(MakeUniqueBuffer(&allocator_, 1024), 1024); + message_frame = + new QuicMessageFrame(/*message_id=*/1, QuicMemSliceSpan(&slice)); + EXPECT_FALSE(message_frame->message_data.empty()); + EXPECT_EQ(message_frame->message_length, 1024); + + SerializedPacket packet(QuicPacketNumber(1), PACKET_4BYTE_PACKET_NUMBER, + /*encrypted_buffer=*/nullptr, kDefaultLength, + /*has_ack=*/false, + /*has_stop_waiting*/ false); + packet.encryption_level = ENCRYPTION_FORWARD_SECURE; + packet.retransmittable_frames.push_back(QuicFrame(message_frame)); + packet.has_message = true; + manager_.OnPacketSent(&packet, clock_.Now(), NOT_RETRANSMISSION, + HAS_RETRANSMITTABLE_DATA, /*measure_rtt=*/true); + } + + EXPECT_TRUE(message_frame->message_data.empty()); + EXPECT_EQ(message_frame->message_length, 0); +} + } // namespace } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc index 0f43d2fa3fa..4737902ef2c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.cc @@ -89,8 +89,8 @@ QuicSession::QuicSession( perspective() == Perspective::IS_SERVER, nullptr), currently_writing_stream_id_(0), - goaway_sent_(false), - goaway_received_(false), + transport_goaway_sent_(false), + transport_goaway_received_(false), control_frame_manager_(this), last_message_id_(0), datagram_queue_(this), @@ -100,13 +100,7 @@ QuicSession::QuicSession( is_configured_(false), enable_round_robin_scheduling_(false), was_zero_rtt_rejected_(false), - liveness_testing_in_progress_(false), - remove_streams_waiting_for_acks_( - GetQuicReloadableFlag(quic_remove_streams_waiting_for_acks)), - do_not_use_stream_map_(GetQuicReloadableFlag(quic_do_not_use_stream_map)), - remove_zombie_streams_( - GetQuicReloadableFlag(quic_remove_zombie_streams) && - do_not_use_stream_map_ && remove_streams_waiting_for_acks_) { + liveness_testing_in_progress_(false) { closed_streams_clean_up_alarm_ = QuicWrapUnique<QuicAlarm>(connection_->alarm_factory()->CreateAlarm( new ClosedStreamsCleanUpDelegate(this))); @@ -126,6 +120,12 @@ void QuicSession::Initialize() { connection_->SetSessionNotifier(this); connection_->SetDataProducer(this); connection_->SetFromConfig(config_); + if (perspective_ == Perspective::IS_CLIENT && + config_.HasClientRequestedIndependentOption(kAFFE, perspective_) && + version().HasIetfQuicFrames()) { + connection_->set_can_receive_ack_frequency_frame(); + config_.SetMinAckDelayMs(kDefaultMinAckDelayTimeMs); + } if (perspective() == Perspective::IS_CLIENT && version().UsesTls() && !version().HasHandshakeDone()) { config_.SetSupportHandshakeDone(); @@ -145,15 +145,7 @@ void QuicSession::Initialize() { GetMutableCryptoStream()->id()); } -QuicSession::~QuicSession() { - if (!remove_zombie_streams_) { - QUIC_LOG_IF(WARNING, !zombie_streams_.empty()) - << "Still have zombie streams"; - } else { - QUIC_LOG_IF(WARNING, num_zombie_streams_ > 0) - << "Still have zombie streams"; - } -} +QuicSession::~QuicSession() {} void QuicSession::PendingStreamOnStreamFrame(const QuicStreamFrame& frame) { DCHECK(VersionUsesHttp3(transport_version())); @@ -265,7 +257,7 @@ void QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { return; } - stream->OnStopSending(frame.application_error_code); + stream->OnStopSending(frame.error_code); } void QuicSession::OnPacketDecrypted(EncryptionLevel level) { @@ -348,7 +340,7 @@ void QuicSession::OnGoAway(const QuicGoAwayFrame& /*frame*/) { QUIC_BUG_IF(version().UsesHttp3()) << "gQUIC GOAWAY received on version " << version(); - goaway_received_ = true; + transport_goaway_received_ = true; } void QuicSession::OnMessageReceived(quiche::QuicheStringPiece message) { @@ -391,66 +383,17 @@ void QuicSession::OnConnectionClosed(const QuicConnectionCloseFrame& frame, GetMutableCryptoStream()->OnConnectionClosed(frame.quic_error_code, source); - if (!do_not_use_stream_map_) { - // Copy all non static streams in a new map for the ease of deleting. - std::vector<QuicStream*> non_static_streams; - for (const auto& it : stream_map_) { - if (!it.second->is_static()) { - non_static_streams.push_back(it.second.get()); - } - } - - for (QuicStream* stream : non_static_streams) { - QuicStreamId id = stream->id(); - stream->OnConnectionClosed(frame.quic_error_code, source); - QUIC_RELOADABLE_FLAG_COUNT( - quic_do_not_close_stream_again_on_connection_close); - if (stream_map_.find(id) != stream_map_.end()) { - QUIC_BUG << ENDPOINT << "Stream " << id - << " failed to close under OnConnectionClosed"; - if (!GetQuicReloadableFlag( - quic_do_not_close_stream_again_on_connection_close)) { - CloseStream(id); - } - } - } - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_do_not_use_stream_map, 1, 2); - PerformActionOnActiveStreams([this, frame, source](QuicStream* stream) { - QuicStreamId id = stream->id(); - stream->OnConnectionClosed(frame.quic_error_code, source); - QUIC_RELOADABLE_FLAG_COUNT( - quic_do_not_close_stream_again_on_connection_close); - auto it = stream_map_.find(id); - if (it != stream_map_.end()) { - if (!remove_zombie_streams_) { - QUIC_BUG << ENDPOINT << "Stream " << id - << " failed to close under OnConnectionClosed"; - } else { - QUIC_BUG_IF(!it->second->IsZombie()) - << ENDPOINT << "Non-zombie stream " << id - << " failed to close under OnConnectionClosed"; - } - if (!GetQuicReloadableFlag( - quic_do_not_close_stream_again_on_connection_close)) { - CloseStream(id); - } - } - return true; - }); - } - - if (!remove_zombie_streams_) { - // Cleanup zombie stream map on connection close. - while (!zombie_streams_.empty()) { - ZombieStreamMap::iterator it = zombie_streams_.begin(); - closed_streams_.push_back(std::move(it->second)); - zombie_streams_.erase(it); + PerformActionOnActiveStreams([this, frame, source](QuicStream* stream) { + QuicStreamId id = stream->id(); + stream->OnConnectionClosed(frame.quic_error_code, source); + auto it = stream_map_.find(id); + if (it != stream_map_.end()) { + QUIC_BUG_IF(!it->second->IsZombie()) + << ENDPOINT << "Non-zombie stream " << id + << " failed to close under OnConnectionClosed"; } - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 1, 4); - DCHECK(zombie_streams_.empty()); - } + return true; + }); closed_streams_clean_up_alarm_->Cancel(); @@ -479,7 +422,14 @@ void QuicSession::OnPacketReceived(const QuicSocketAddress& /*self_address*/, if (is_connectivity_probe && perspective() == Perspective::IS_SERVER) { // Server only sends back a connectivity probe after received a // connectivity probe from a new peer address. - connection_->SendConnectivityProbingResponsePacket(peer_address); + if (connection_->send_path_response()) { + // SendConnectivityProbingResponsePacket() will be deprecated. + // SendConnectivityProbingPacket() will be used to send both probing + // request and response as both of them are padded PING. + connection_->SendConnectivityProbingPacket(nullptr, peer_address); + } else { + connection_->SendConnectivityProbingResponsePacket(peer_address); + } } } @@ -704,6 +654,34 @@ bool QuicSession::WillingAndAbleToWrite() const { write_blocked_streams_.HasWriteBlockedDataStreams(); } +std::string QuicSession::GetStreamsInfoForLogging() const { + std::string info = quiche::QuicheStrCat( + "num_active_streams: ", GetNumActiveStreams(), + ", num_pending_streams: ", pending_streams_size(), + ", num_outgoing_draining_streams: ", num_outgoing_draining_streams(), + " "); + // Log info for up to 5 streams. + size_t i = 5; + for (const auto& it : stream_map_) { + if (it.second->is_static()) { + continue; + } + // Calculate the stream creation delay. + const QuicTime::Delta delay = + connection_->clock()->ApproximateNow() - it.second->creation_time(); + info = quiche::QuicheStrCat( + info, "{", it.second->id(), ":", delay.ToDebuggingValue(), ";", + it.second->stream_bytes_written(), ",", it.second->fin_sent(), ",", + it.second->HasBufferedData(), ",", it.second->fin_buffered(), ";", + it.second->stream_bytes_read(), ",", it.second->fin_received(), "}"); + --i; + if (i == 0) { + break; + } + } + return info; +} + bool QuicSession::HasPendingHandshake() const { if (QuicVersionUsesCryptoFrames(transport_version())) { return GetCryptoStream()->HasPendingCryptoRetransmission() || @@ -734,8 +712,15 @@ QuicConsumedData QuicSession::WritevData( !QuicUtils::IsCryptoStreamId(transport_version(), id)) { // Do not let streams write without encryption. The calling stream will end // up write blocked until OnCanWrite is next called. - QUIC_BUG << ENDPOINT << "Try to send data of stream " << id - << " before encryption is established."; + if (was_zero_rtt_rejected_ && !OneRttKeysAvailable()) { + DCHECK(version().UsesTls() && perspective() == Perspective::IS_CLIENT); + QUIC_BUG_IF(type == NOT_RETRANSMISSION) + << ENDPOINT << "Try to send new data on stream " << id + << "before 1-RTT keys are available while 0-RTT is rejected."; + } else { + QUIC_BUG << ENDPOINT << "Try to send data of stream " << id + << " before encryption is established."; + } return QuicConsumedData(0, false); } @@ -765,6 +750,17 @@ size_t QuicSession::SendCryptoData(EncryptionLevel level, QuicStreamOffset offset, TransmissionType type) { DCHECK(QuicVersionUsesCryptoFrames(transport_version())); + if (connection()->check_keys_before_writing() && + !connection()->framer().HasEncrypterOfEncryptionLevel(level)) { + const std::string error_details = quiche::QuicheStrCat( + "Try to send crypto data with missing keys of encryption level: ", + EncryptionLevelToString(level)); + QUIC_BUG << ENDPOINT << error_details; + connection()->CloseConnection( + QUIC_MISSING_WRITE_KEYS, error_details, + ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); + return 0; + } SetTransmissionType(type); const auto current_level = connection()->encryption_level(); connection_->SetDefaultEncryptionLevel(level); @@ -847,10 +843,10 @@ void QuicSession::SendGoAway(QuicErrorCode error_code, const std::string& reason) { // GOAWAY frame is not supported in v99. DCHECK(!VersionHasIetfQuicFrames(transport_version())); - if (goaway_sent_) { + if (transport_goaway_sent_) { return; } - goaway_sent_ = true; + transport_goaway_sent_ = true; control_frame_manager_.WriteOrBufferGoAway( error_code, stream_id_manager_.largest_peer_created_stream_id(), reason); } @@ -880,31 +876,6 @@ void QuicSession::SendMaxStreams(QuicStreamCount stream_count, control_frame_manager_.WriteOrBufferMaxStreams(stream_count, unidirectional); } -void QuicSession::CloseStream(QuicStreamId stream_id) { - QUIC_DVLOG(1) << ENDPOINT << "Closing stream " << stream_id; - - StreamMap::iterator it = stream_map_.find(stream_id); - if (it == stream_map_.end()) { - // When CloseStream has been called recursively (via - // QuicStream::OnClose), the stream will already have been deleted - // from stream_map_, so return immediately. - QUIC_DVLOG(1) << ENDPOINT << "Stream is already closed: " << stream_id; - return; - } - QuicStream* stream = it->second.get(); - if (stream->is_static()) { - QUIC_DVLOG(1) << ENDPOINT - << "Try to close a static stream, id: " << stream_id - << " Closing connection"; - connection()->CloseConnection( - QUIC_INVALID_STREAM_ID, "Try to close a static stream", - ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); - return; - } - stream->CloseReadSide(); - stream->CloseWriteSide(); -} - void QuicSession::InsertLocallyClosedStreamsHighestOffset( const QuicStreamId id, QuicStreamOffset offset) { @@ -923,26 +894,11 @@ void QuicSession::OnStreamClosed(QuicStreamId stream_id) { const bool stream_waiting_for_acks = stream->IsWaitingForAcks(); if (stream_waiting_for_acks) { - if (remove_zombie_streams_) { - // The stream needs to be kept alive because it's waiting for acks. - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 2, 4); - ++num_zombie_streams_; - } else { - zombie_streams_[stream_id] = std::move(it->second); - } + // The stream needs to be kept alive because it's waiting for acks. + ++num_zombie_streams_; } else { - // Clean up the stream since it is no longer waiting for acks. - if (remove_streams_waiting_for_acks_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 1, 4); - } else { - streams_waiting_for_acks_.erase(stream_id); - } closed_streams_.push_back(std::move(it->second)); - if (remove_zombie_streams_) { - // When zombie_streams_ is removed, stream is only erased from stream map - // if it's not zombie. - stream_map_.erase(it); - } + stream_map_.erase(it); // Do not retransmit data of a closed stream. streams_with_pending_retransmission_.erase(stream_id); if (!closed_streams_clean_up_alarm_->IsSet()) { @@ -960,18 +916,12 @@ void QuicSession::OnStreamClosed(QuicStreamId stream_id) { DCHECK(!stream->was_draining()); InsertLocallyClosedStreamsHighestOffset( stream_id, stream->highest_received_byte_offset()); - if (!remove_zombie_streams_) { - stream_map_.erase(it); - } return; } const bool stream_was_draining = stream->was_draining(); QUIC_DVLOG_IF(1, stream_was_draining) << ENDPOINT << "Stream " << stream_id << " was draining"; - if (!remove_zombie_streams_) { - stream_map_.erase(it); - } if (stream_was_draining) { QUIC_BUG_IF(num_draining_streams_ == 0); --num_draining_streams_; @@ -1580,7 +1530,7 @@ void QuicSession::SetDefaultEncryptionLevel(EncryptionLevel level) { if (perspective() == Perspective::IS_CLIENT) { // Retransmit old 0-RTT data (if any) with the new 0-RTT keys, since // they can't be decrypted by the server. - connection_->MarkZeroRttPacketsForRetransmission(); + connection_->MarkZeroRttPacketsForRetransmission(0); // Given any streams blocked by encryption a chance to write. OnCanWrite(); } @@ -1646,17 +1596,14 @@ void QuicSession::DiscardOldEncryptionKey(EncryptionLevel level) { } void QuicSession::NeuterHandshakeData() { - if (GetQuicReloadableFlag(quic_fix_neuter_handshake_data)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_neuter_handshake_data); - GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel( - ENCRYPTION_HANDSHAKE); - } + GetMutableCryptoStream()->NeuterStreamDataOfEncryptionLevel( + ENCRYPTION_HANDSHAKE); connection()->OnHandshakeComplete(); } -void QuicSession::OnZeroRttRejected() { +void QuicSession::OnZeroRttRejected(int reason) { was_zero_rtt_rejected_ = true; - connection_->MarkZeroRttPacketsForRetransmission(); + connection_->MarkZeroRttPacketsForRetransmission(reason); if (connection_->encryption_level() == ENCRYPTION_FORWARD_SECURE) { QUIC_BUG << "1-RTT keys already available when 0-RTT is rejected."; connection_->CloseConnection( @@ -1818,11 +1765,7 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) { StreamMap::iterator it = stream_map_.find(stream_id); if (it != stream_map_.end()) { - if (remove_zombie_streams_ && it->second->IsZombie()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 3, 4); - return nullptr; - } - return it->second.get(); + return it->second->IsZombie() ? nullptr : it->second.get(); } if (IsClosedStream(stream_id)) { @@ -1834,10 +1777,10 @@ QuicStream* QuicSession::GetOrCreateStream(const QuicStreamId stream_id) { return nullptr; } - // TODO(fkastenholz): If we are creating a new stream and we have - // sent a goaway, we should ignore the stream creation. Need to - // add code to A) test if goaway was sent ("if (goaway_sent_)") and - // B) reject stream creation ("return nullptr") + // TODO(fkastenholz): If we are creating a new stream and we have sent a + // goaway, we should ignore the stream creation. Need to add code to A) test + // if goaway was sent ("if (transport_goaway_sent_)") and B) reject stream + // creation ("return nullptr") if (!MaybeIncreaseLargestPeerStreamId(stream_id)) { return nullptr; @@ -1968,7 +1911,7 @@ bool QuicSession::IsOpenStream(QuicStreamId id) { DCHECK_NE(QuicUtils::GetInvalidStreamId(transport_version()), id); const StreamMap::iterator it = stream_map_.find(id); if (it != stream_map_.end()) { - return remove_zombie_streams_ ? !it->second->IsZombie() : true; + return !it->second->IsZombie(); } if (QuicContainsKey(pending_stream_map_, id) || QuicUtils::IsCryptoStreamId(transport_version(), id)) { @@ -1987,17 +1930,6 @@ bool QuicSession::IsStaticStream(QuicStreamId id) const { } size_t QuicSession::GetNumActiveStreams() const { - if (!VersionHasIetfQuicFrames(transport_version()) && - !GetQuicReloadableFlag(quic_get_stream_information_from_stream_map)) { - // Exclude locally_closed_streams when determine whether to keep connection - // alive. - return stream_id_manager_.num_open_incoming_streams() + - stream_id_manager_.num_open_outgoing_streams() - - locally_closed_streams_highest_offset_.size(); - } - if (GetQuicReloadableFlag(quic_get_stream_information_from_stream_map)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_get_stream_information_from_stream_map); - } DCHECK_GE(static_cast<QuicStreamCount>(stream_map_.size()), num_static_streams_ + num_draining_streams_ + num_zombie_streams_); return stream_map_.size() - num_draining_streams_ - num_static_streams_ - @@ -2071,30 +2003,13 @@ bool QuicSession::IsIncomingStream(QuicStreamId id) const { } void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) { - if (remove_streams_waiting_for_acks_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 2, 4); - } else { - streams_waiting_for_acks_.erase(id); - } - - if (!remove_zombie_streams_) { - auto it = zombie_streams_.find(id); - if (it == zombie_streams_.end()) { - return; - } - - closed_streams_.push_back(std::move(it->second)); - zombie_streams_.erase(it); - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_zombie_streams, 4, 4); - auto it = stream_map_.find(id); - if (it == stream_map_.end()) { - return; - } - --num_zombie_streams_; - closed_streams_.push_back(std::move(it->second)); - stream_map_.erase(it); + auto it = stream_map_.find(id); + if (it == stream_map_.end()) { + return; } + --num_zombie_streams_; + closed_streams_.push_back(std::move(it->second)); + stream_map_.erase(it); if (!closed_streams_clean_up_alarm_->IsSet()) { closed_streams_clean_up_alarm_->Set(connection_->clock()->ApproximateNow()); @@ -2103,43 +2018,12 @@ void QuicSession::OnStreamDoneWaitingForAcks(QuicStreamId id) { streams_with_pending_retransmission_.erase(id); } -void QuicSession::OnStreamWaitingForAcks(QuicStreamId id) { - if (remove_streams_waiting_for_acks_) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 3, 4); - return; - } - // Exclude crypto stream's status since it is counted in HasUnackedCryptoData. - if (GetCryptoStream() != nullptr && id == GetCryptoStream()->id()) { - return; - } - - streams_waiting_for_acks_.insert(id); - - // The number of the streams waiting for acks should not be larger than the - // number of streams. - DCHECK(!remove_zombie_streams_ || zombie_streams_.empty()); - if (static_cast<size_t>(stream_map_.size() + zombie_streams_.size()) < - streams_waiting_for_acks_.size()) { - QUIC_BUG << "More streams are waiting for acks than the number of streams. " - << "Sizes: streams: " << stream_map_.size() - << ", zombie streams: " << zombie_streams_.size() - << ", vs streams waiting for acks: " - << streams_waiting_for_acks_.size(); - } -} - QuicStream* QuicSession::GetStream(QuicStreamId id) const { auto active_stream = stream_map_.find(id); if (active_stream != stream_map_.end()) { return active_stream->second.get(); } - DCHECK(!remove_zombie_streams_ || zombie_streams_.empty()); - auto zombie_stream = zombie_streams_.find(id); - if (zombie_stream != zombie_streams_.end()) { - return zombie_stream->second.get(); - } - if (QuicUtils::IsCryptoStreamId(transport_version(), id)) { return const_cast<QuicCryptoStream*>(GetCryptoStream()); } @@ -2280,14 +2164,6 @@ bool QuicSession::HasUnackedCryptoData() const { } bool QuicSession::HasUnackedStreamData() const { - if (!remove_streams_waiting_for_acks_) { - return !streams_waiting_for_acks_.empty(); - } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_remove_streams_waiting_for_acks, 4, 4); - DCHECK(!remove_zombie_streams_ || zombie_streams_.empty()); - if (!zombie_streams().empty()) { - return true; - } for (const auto& it : stream_map_) { if (it.second->IsWaitingForAcks()) { return true; @@ -2457,7 +2333,8 @@ QuicPacketLength QuicSession::GetGuaranteedLargestMessagePayload() const { return connection_->GetGuaranteedLargestMessagePayload(); } -void QuicSession::SendStopSending(uint16_t code, QuicStreamId stream_id) { +void QuicSession::SendStopSending(QuicRstStreamErrorCode code, + QuicStreamId stream_id) { control_frame_manager_.WriteOrBufferStopSending(code, stream_id); } @@ -2534,8 +2411,7 @@ void QuicSession::PerformActionOnActiveStreams( std::function<bool(QuicStream*)> action) { std::vector<QuicStream*> active_streams; for (const auto& it : stream_map_) { - if (!it.second->is_static() && - (!remove_zombie_streams_ || !it.second->IsZombie())) { + if (!it.second->is_static() && !it.second->IsZombie()) { active_streams.push_back(it.second.get()); } } @@ -2550,8 +2426,7 @@ void QuicSession::PerformActionOnActiveStreams( void QuicSession::PerformActionOnActiveStreams( std::function<bool(QuicStream*)> action) const { for (const auto& it : stream_map_) { - if (!it.second->is_static() && - (!remove_zombie_streams_ || !it.second->IsZombie()) && + if (!it.second->is_static() && !it.second->IsZombie() && !action(it.second.get())) { return; } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session.h b/chromium/net/third_party/quiche/src/quic/core/quic_session.h index e81375d231f..f5e01f85157 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session.h @@ -123,6 +123,7 @@ class QUIC_EXPORT_PRIVATE QuicSession void OnAckNeedsRetransmittableFrame() override; void SendPing() override; bool WillingAndAbleToWrite() const override; + std::string GetStreamsInfoForLogging() const override; void OnPathDegrading() override; void OnForwardProgressMadeAfterPathDegrading() override; bool AllowSelfAddressChange() const override; @@ -231,13 +232,8 @@ class QUIC_EXPORT_PRIVATE QuicSession virtual void SendWindowUpdate(QuicStreamId id, QuicStreamOffset byte_offset); // Create and transmit a STOP_SENDING frame - virtual void SendStopSending(uint16_t code, QuicStreamId stream_id); - - // Close stream |stream_id|. Whether sending RST_STREAM (and STOP_SENDING) - // depends on the sending and receiving states. - // TODO(b/136274541): Deprecate CloseStream, instead always use ResetStream to - // close a stream from session. - virtual void CloseStream(QuicStreamId stream_id); + virtual void SendStopSending(QuicRstStreamErrorCode code, + QuicStreamId stream_id); // Called by stream |stream_id| when it gets closed. virtual void OnStreamClosed(QuicStreamId stream_id); @@ -266,7 +262,7 @@ class QUIC_EXPORT_PRIVATE QuicSession void DiscardOldEncryptionKey(EncryptionLevel level) override; void NeuterUnencryptedData() override; void NeuterHandshakeData() override; - void OnZeroRttRejected() override; + void OnZeroRttRejected(int reason) override; bool FillTransportParameters(TransportParameters* params) override; QuicErrorCode ProcessTransportParameters(const TransportParameters& params, bool is_resumption, @@ -350,10 +346,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // TODO(b/136274541): rename to CloseZombieStreams. void OnStreamDoneWaitingForAcks(QuicStreamId id); - // TODO(b/136274541): Remove this once quic_remove_streams_waiting_for_acks is - // deprecated. Called when stream |id| is newly waiting for acks. - void OnStreamWaitingForAcks(QuicStreamId id); - // Returns true if there is pending handshake data in the crypto stream. // TODO(ianswett): Make this private or remove. bool HasPendingHandshake() const; @@ -372,9 +364,9 @@ class QUIC_EXPORT_PRIVATE QuicSession // connection ID lengths do not change. QuicPacketLength GetGuaranteedLargestMessagePayload() const; - bool goaway_sent() const { return goaway_sent_; } + bool transport_goaway_sent() const { return transport_goaway_sent_; } - bool goaway_received() const { return goaway_received_; } + bool transport_goaway_received() const { return transport_goaway_received_; } // Returns the Google QUIC error code QuicErrorCode error() const { return on_closed_frame_.quic_error_code; } @@ -499,8 +491,6 @@ class QUIC_EXPORT_PRIVATE QuicSession return liveness_testing_in_progress_; } - bool remove_zombie_streams() const { return remove_zombie_streams_; } - protected: using StreamMap = QuicHashMap<QuicStreamId, std::unique_ptr<QuicStream>>; @@ -574,8 +564,6 @@ class QUIC_EXPORT_PRIVATE QuicSession ClosedStreams* closed_streams() { return &closed_streams_; } - const ZombieStreamMap& zombie_streams() const { return zombie_streams_; } - void set_largest_peer_created_stream_id( QuicStreamId largest_peer_created_stream_id); @@ -626,8 +614,6 @@ class QUIC_EXPORT_PRIVATE QuicSession bool was_zero_rtt_rejected() const { return was_zero_rtt_rejected_; } - bool do_not_use_stream_map() const { return do_not_use_stream_map_; } - size_t num_outgoing_draining_streams() const { return num_outgoing_draining_streams_; } @@ -759,9 +745,6 @@ class QUIC_EXPORT_PRIVATE QuicSession QuicWriteBlockedList write_blocked_streams_; ClosedStreams closed_streams_; - // Streams which are closed, but need to be kept alive. Currently, the only - // reason is the stream's sent data (including FIN) does not get fully acked. - ZombieStreamMap zombie_streams_; QuicConfig config_; @@ -772,11 +755,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // which are waiting for the first byte of payload to arrive. PendingStreamMap pending_stream_map_; - // TODO(b/136274541): Remove this once quic_remove_streams_waiting_for_acks is - // deprecated. Set of stream ids that are waiting for acks excluding crypto - // stream id. - QuicHashSet<QuicStreamId> streams_waiting_for_acks_; - // TODO(fayang): Consider moving LegacyQuicStreamIdManager into // UberQuicStreamIdManager. // Manages stream IDs for Google QUIC. @@ -810,11 +788,15 @@ class QUIC_EXPORT_PRIVATE QuicSession // call stack of OnCanWrite. QuicStreamId currently_writing_stream_id_; - // Whether a GoAway has been sent. - bool goaway_sent_; + // Whether a transport layer GOAWAY frame has been sent. + // Such a frame only exists in Google QUIC, therefore |transport_goaway_sent_| + // is always false when using IETF QUIC. + bool transport_goaway_sent_; - // Whether a GoAway has been received. - bool goaway_received_; + // Whether a transport layer GOAWAY frame has been received. + // Such a frame only exists in Google QUIC, therefore + // |transport_goaway_received_| is always false when using IETF QUIC. + bool transport_goaway_received_; QuicControlFrameManager control_frame_manager_; @@ -855,15 +837,6 @@ class QUIC_EXPORT_PRIVATE QuicSession // This indicates a liveness testing is in progress, and push back the // creation of new outgoing bidirectional streams. bool liveness_testing_in_progress_; - - // Latched value of flag quic_remove_streams_waiting_for_acks. - const bool remove_streams_waiting_for_acks_; - - // Latched value of flag quic_do_not_use_stream_map. - const bool do_not_use_stream_map_; - - // Latched value of flag quic_remove_zombie_streams. - const bool remove_zombie_streams_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc index 67cb2be7792..e5b6cff3a03 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_session_test.cc @@ -115,6 +115,9 @@ class TestCryptoStream : public QuicCryptoStream, public QuicCryptoHandshaker { } // QuicCryptoStream implementation + ssl_early_data_reason_t EarlyDataReason() const override { + return ssl_early_data_unknown; + } bool encryption_established() const override { return encryption_established_; } @@ -165,10 +168,9 @@ class TestStream : public QuicStream { StreamType type) : QuicStream(id, session, is_static, type) {} - TestStream(PendingStream* pending, StreamType type) - : QuicStream(pending, type, /*is_static=*/false) {} + TestStream(PendingStream* pending, QuicSession* session, StreamType type) + : QuicStream(pending, session, type, /*is_static=*/false) {} - using QuicStream::CloseReadSide; using QuicStream::CloseWriteSide; using QuicStream::WriteMemSlices; @@ -258,8 +260,9 @@ class TestSession : public QuicSession { TestStream* CreateIncomingStream(PendingStream* pending) override { QuicStreamId id = pending->id(); TestStream* stream = new TestStream( - pending, DetermineStreamType(id, connection()->version(), perspective(), - /*is_incoming=*/true, BIDIRECTIONAL)); + pending, this, + DetermineStreamType(id, connection()->version(), perspective(), + /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); ++num_incoming_streams_created_; return stream; @@ -364,7 +367,6 @@ class TestSession : public QuicSession { using QuicSession::GetNextOutgoingBidirectionalStreamId; using QuicSession::GetNextOutgoingUnidirectionalStreamId; using QuicSession::stream_map; - using QuicSession::zombie_streams; private: StrictMock<TestCryptoStream> crypto_stream_; @@ -1425,7 +1427,7 @@ TEST_P(QuicSessionTestServer, SendGoAway) { .WillOnce( Invoke(connection_, &MockQuicConnection::ReallySendControlFrame)); session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); - EXPECT_TRUE(session_.goaway_sent()); + EXPECT_TRUE(session_.transport_goaway_sent()); const QuicStreamId kTestStreamId = 5u; EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); @@ -1443,7 +1445,7 @@ TEST_P(QuicSessionTestServer, DoNotSendGoAwayTwice) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillOnce(Invoke(&ClearControlFrame)); session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); - EXPECT_TRUE(session_.goaway_sent()); + EXPECT_TRUE(session_.transport_goaway_sent()); session_.SendGoAway(QUIC_PEER_GOING_AWAY, "Going Away."); } @@ -1460,6 +1462,10 @@ TEST_P(QuicSessionTestServer, InvalidGoAway) { // Test that server session will send a connectivity probe in response to a // connectivity probe on the same path. TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) { + if (connection_->send_path_response() && + VersionHasIetfQuicFrames(transport_version())) { + return; + } connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); QuicSocketAddress old_peer_address = QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort); @@ -1472,10 +1478,17 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) { QuicConnectionPeer::GetWriter(session_.connection())); EXPECT_CALL(*writer, WritePacket(_, _, _, new_peer_address, _)) .WillOnce(Return(WriteResult(WRITE_STATUS_OK, 0))); - EXPECT_CALL(*connection_, SendConnectivityProbingResponsePacket(_)) - .WillOnce(Invoke( - connection_, - &MockQuicConnection::ReallySendConnectivityProbingResponsePacket)); + if (connection_->send_path_response()) { + EXPECT_CALL(*connection_, SendConnectivityProbingPacket(_, _)) + .WillOnce( + Invoke(connection_, + &MockQuicConnection::ReallySendConnectivityProbingPacket)); + } else { + EXPECT_CALL(*connection_, SendConnectivityProbingResponsePacket(_)) + .WillOnce(Invoke( + connection_, + &MockQuicConnection::ReallySendConnectivityProbingResponsePacket)); + } if (VersionHasIetfQuicFrames(transport_version())) { // Need to explicitly do this to emulate the reception of a PathChallenge, // which stores its payload for use in generating the response. @@ -1491,7 +1504,8 @@ TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbe) { // packet, the response has both of them AND we do not do migration. This for // IETF QUIC only. TEST_P(QuicSessionTestServer, ServerReplyToConnectivityProbes) { - if (!VersionHasIetfQuicFrames(transport_version())) { + if (connection_->send_path_response() || + !VersionHasIetfQuicFrames(transport_version())) { return; } connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); @@ -2207,6 +2221,17 @@ TEST_P(QuicSessionTestClient, IncomingStreamWithClientInitiatedStreamId) { session_.OnStreamFrame(frame); } +TEST_P(QuicSessionTestClient, MinAckDelaySetOnTheClientQuicConfig) { + if (!session_.version().HasIetfQuicFrames()) { + return; + } + session_.config()->SetClientConnectionOptions({kAFFE}); + session_.Initialize(); + ASSERT_EQ(session_.config()->GetMinAckDelayToSendMs(), + kDefaultMinAckDelayTimeMs); + ASSERT_TRUE(session_.connection()->can_receive_ack_frequency_frame()); +} + TEST_P(QuicSessionTestClient, FailedToCreateStreamIfTooCloseToIdleTimeout) { connection_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); EXPECT_TRUE(session_.CanOpenNextOutgoingBidirectionalStream()); @@ -2235,11 +2260,9 @@ TEST_P(QuicSessionTestServer, ZombieStreams) { EXPECT_TRUE(stream2->IsWaitingForAcks()); CloseStream(stream2->id()); - EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id())); ASSERT_EQ(1u, session_.closed_streams()->size()); EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id()); session_.OnStreamDoneWaitingForAcks(stream2->id()); - EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id())); EXPECT_EQ(1u, session_.closed_streams()->size()); EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id()); } @@ -2294,7 +2317,6 @@ TEST_P(QuicSessionTestServer, TestZombieStreams) { EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); session_.OnStopSendingFrame(frame); } - EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id())); ASSERT_EQ(1u, session_.closed_streams()->size()); EXPECT_EQ(stream2->id(), session_.closed_streams()->front()->id()); @@ -2316,7 +2338,6 @@ TEST_P(QuicSessionTestServer, TestZombieStreams) { // QUIC it sends both a RST_STREAM and a STOP_SENDING (each of which // closes in only one direction). stream4->Reset(QUIC_STREAM_CANCELLED); - EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream4->id())); EXPECT_EQ(2u, session_.closed_streams()->size()); } @@ -2560,17 +2581,13 @@ TEST_P(QuicSessionTestServer, LocallyResetZombieStreams) { session_.set_writev_consumes_all_data(true); TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); std::string body(100, '.'); - stream2->CloseReadSide(); + QuicStreamPeer::CloseReadSide(stream2); stream2->WriteOrBufferData(body, true, nullptr); EXPECT_TRUE(stream2->IsWaitingForAcks()); // Verify stream2 is a zombie streams. - if (!session_.remove_zombie_streams()) { - EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), stream2->id())); - } else { - ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream2->id())); - auto* stream = session_.stream_map().find(stream2->id())->second.get(); - EXPECT_TRUE(stream->IsZombie()); - } + ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream2->id())); + auto* stream = session_.stream_map().find(stream2->id())->second.get(); + EXPECT_TRUE(stream->IsZombie()); QuicStreamFrame frame(stream2->id(), true, 0, 100); EXPECT_CALL(*stream2, HasPendingRetransmission()) @@ -2584,7 +2601,6 @@ TEST_P(QuicSessionTestServer, LocallyResetZombieStreams) { stream2->Reset(QUIC_STREAM_CANCELLED); // Verify stream 2 gets closed. - EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id())); EXPECT_TRUE(session_.IsClosedStream(stream2->id())); EXPECT_CALL(*stream2, OnCanWrite()).Times(0); session_.OnCanWrite(); @@ -2599,7 +2615,6 @@ TEST_P(QuicSessionTestServer, CleanUpClosedStreamsAlarm) { EXPECT_FALSE(stream2->IsWaitingForAcks()); CloseStream(stream2->id()); - EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream2->id())); EXPECT_EQ(1u, session_.closed_streams()->size()); EXPECT_TRUE( QuicSessionPeer::GetCleanUpClosedStreamsAlarm(&session_)->IsSet()); @@ -2616,15 +2631,10 @@ TEST_P(QuicSessionTestServer, WriteUnidirectionalStream) { session_.ActivateStream(QuicWrapUnique(stream4)); std::string body(100, '.'); stream4->WriteOrBufferData(body, false, nullptr); - EXPECT_FALSE(QuicContainsKey(session_.zombie_streams(), stream4->id())); stream4->WriteOrBufferData(body, true, nullptr); - if (!session_.remove_zombie_streams()) { - EXPECT_TRUE(QuicContainsKey(session_.zombie_streams(), stream4->id())); - } else { - ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream4->id())); - auto* stream = session_.stream_map().find(stream4->id())->second.get(); - EXPECT_TRUE(stream->IsZombie()); - } + ASSERT_TRUE(QuicContainsKey(session_.stream_map(), stream4->id())); + auto* stream = session_.stream_map().find(stream4->id())->second.get(); + EXPECT_TRUE(stream->IsZombie()); } TEST_P(QuicSessionTestServer, ReceivedDataOnWriteUnidirectionalStream) { @@ -2809,7 +2819,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInvalidStreamId) { return; } // Check that "invalid" stream ids are rejected. - QuicStopSendingFrame frame(1, -1, 123); + QuicStopSendingFrame frame(1, -1, QUIC_STREAM_CANCELLED); EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, @@ -2822,7 +2832,8 @@ TEST_P(QuicSessionTestServer, OnStopSendingReadUnidirectional) { return; } // It's illegal to send STOP_SENDING with a stream ID that is read-only. - QuicStopSendingFrame frame(1, GetNthClientInitiatedUnidirectionalId(1), 123); + QuicStopSendingFrame frame(1, GetNthClientInitiatedUnidirectionalId(1), + QUIC_STREAM_CANCELLED); EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, @@ -2840,7 +2851,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingStaticStreams) { stream_id, &session_, /*is_static*/ true, BIDIRECTIONAL); QuicSessionPeer::ActivateStream(&session_, std::move(fake_static_stream)); // Check that a stream id in the static stream map is ignored. - QuicStopSendingFrame frame(1, stream_id, 123); + QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED); EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Received STOP_SENDING for a static stream", _)); @@ -2858,7 +2869,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingForWriteClosedStream) { QuicStreamPeer::SetFinSent(stream); stream->CloseWriteSide(); EXPECT_TRUE(stream->write_side_closed()); - QuicStopSendingFrame frame(1, stream_id, 123); + QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); session_.OnStopSendingFrame(frame); } @@ -2872,7 +2883,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingClosedStream) { TestStream* stream = session_.CreateOutgoingBidirectionalStream(); QuicStreamId stream_id = stream->id(); CloseStream(stream_id); - QuicStopSendingFrame frame(1, stream_id, 123); + QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); session_.OnStopSendingFrame(frame); } @@ -2885,7 +2896,7 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputNonExistentLocalStream) { } QuicStopSendingFrame frame(1, GetNthServerInitiatedBidirectionalId(123456), - 123); + QUIC_STREAM_CANCELLED); EXPECT_CALL(*connection_, CloseConnection(QUIC_HTTP_STREAM_WRONG_DIRECTION, "Data for nonexistent stream", _)) .Times(1); @@ -2898,7 +2909,8 @@ TEST_P(QuicSessionTestServer, OnStopSendingNewStream) { if (!VersionHasIetfQuicFrames(transport_version())) { return; } - QuicStopSendingFrame frame(1, GetNthClientInitiatedBidirectionalId(1), 123); + QuicStopSendingFrame frame(1, GetNthClientInitiatedBidirectionalId(1), + QUIC_STREAM_CANCELLED); // A Rst will be sent as a response for STOP_SENDING. EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); @@ -2925,12 +2937,10 @@ TEST_P(QuicSessionTestServer, OnStopSendingInputValidStream) { EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream)); QuicStreamId stream_id = stream->id(); - QuicStopSendingFrame frame(1, stream_id, 123); + QuicStopSendingFrame frame(1, stream_id, QUIC_STREAM_CANCELLED); // Expect a reset to come back out. EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL( - *connection_, - OnStreamReset(stream_id, static_cast<QuicRstStreamErrorCode>(123))); + EXPECT_CALL(*connection_, OnStreamReset(stream_id, QUIC_STREAM_CANCELLED)); EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); session_.OnStopSendingFrame(frame); @@ -2952,6 +2962,9 @@ TEST_P(QuicSessionTestServer, WriteBufferedCryptoFrames) { EXPECT_TRUE(session_.WillingAndAbleToWrite()); EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0); + connection_->SetEncrypter( + ENCRYPTION_ZERO_RTT, + std::make_unique<NullEncrypter>(connection_->perspective())); crypto_stream->WriteCryptoData(ENCRYPTION_ZERO_RTT, data); EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_INITIAL, 350, 1000)) diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc index 5fd63585c18..d973549e555 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.cc @@ -109,12 +109,8 @@ QuicByteCount GetReceivedFlowControlWindow(QuicSession* session, // static const SpdyPriority QuicStream::kDefaultPriority; -// static -const int QuicStream::kDefaultUrgency; - PendingStream::PendingStream(QuicStreamId id, QuicSession* session) : id_(id), - session_(session), stream_delegate_(session), stream_bytes_read_(0), fin_received_(false), @@ -125,8 +121,8 @@ PendingStream::PendingStream(QuicStreamId id, QuicSession* session) GetReceivedFlowControlWindow(session, id), GetInitialStreamFlowControlWindowToSend(session, id), kStreamReceiveWindowLimit, - session_->flow_controller()->auto_tune_receive_window(), - session_->flow_controller()), + session->flow_controller()->auto_tune_receive_window(), + session->flow_controller()), sequencer_(this) {} void PendingStream::OnDataAvailable() { @@ -267,9 +263,12 @@ void PendingStream::StopReading() { sequencer_.StopReading(); } -QuicStream::QuicStream(PendingStream* pending, StreamType type, bool is_static) +QuicStream::QuicStream(PendingStream* pending, + QuicSession* session, + StreamType type, + bool is_static) : QuicStream(pending->id_, - pending->session_, + session, std::move(pending->sequencer_), is_static, type, @@ -362,6 +361,7 @@ QuicStream::QuicStream(QuicStreamId id, session->IsIncomingStream(id_), session->version()) : type), + creation_time_(session->connection()->clock()->ApproximateNow()), perspective_(session->perspective()) { if (type_ == WRITE_UNIDIRECTIONAL) { fin_received_ = true; @@ -388,6 +388,16 @@ QuicStream::~QuicStream() { } } +// static +int QuicStream::DefaultUrgency() { + if (GetQuicReloadableFlag(quic_http3_new_default_urgency_value)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_http3_new_default_urgency_value); + return 3; + } else { + return 1; + } +} + void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { DCHECK_EQ(frame.stream_id, id_); @@ -475,7 +485,7 @@ void QuicStream::OnStreamFrame(const QuicStreamFrame& frame) { sequencer_.OnStreamFrame(frame); } -bool QuicStream::OnStopSending(uint16_t code) { +bool QuicStream::OnStopSending(QuicRstStreamErrorCode code) { // Do not reset the stream if all data has been sent and acknowledged. if (write_side_closed() && !IsWaitingForAcks()) { QUIC_DVLOG(1) << ENDPOINT @@ -493,11 +503,10 @@ bool QuicStream::OnStopSending(uint16_t code) { return false; } - stream_error_ = static_cast<QuicRstStreamErrorCode>(code); + stream_error_ = code; - session()->SendRstStream(id(), - static_cast<quic::QuicRstStreamErrorCode>(code), - stream_bytes_written(), /*send_rst_only = */ true); + session()->SendRstStream(id(), code, stream_bytes_written(), + /*send_rst_only = */ true); rst_sent_ = true; CloseWriteSide(); return true; @@ -1009,8 +1018,7 @@ bool QuicStream::OnStreamFrameAcked(QuicStreamOffset offset, fin_outstanding_ = false; fin_lost_ = false; } - if (!IsWaitingForAcks() && (!session()->remove_zombie_streams() || - (read_side_closed_ && write_side_closed_))) { + if (!IsWaitingForAcks() && read_side_closed_ && write_side_closed_) { session_->OnStreamDoneWaitingForAcks(id_); } return new_data_acked; @@ -1206,10 +1214,6 @@ void QuicStream::WriteBufferedData() { if (consumed_data.bytes_consumed > 0 || consumed_data.fin_consumed) { busy_counter_ = 0; } - - if (IsWaitingForAcks()) { - session_->OnStreamWaitingForAcks(id_); - } } uint64_t QuicStream::BufferedDataBytes() const { @@ -1309,16 +1313,6 @@ void QuicStream::OnDeadlinePassed() { Reset(QUIC_STREAM_TTL_EXPIRED); } -void QuicStream::SendStopSending(uint16_t code) { - if (!VersionHasIetfQuicFrames(transport_version())) { - // If the connection is not version 99, do nothing. - // Do not QUIC_BUG or anything; the application really does not need to know - // what version the connection is in. - return; - } - session_->SendStopSending(code, id_); -} - bool QuicStream::IsFlowControlBlocked() const { if (!flow_controller_.has_value()) { QUIC_BUG << "Trying to access non-existent flow controller."; @@ -1347,7 +1341,7 @@ void QuicStream::UpdateReceiveWindowSize(QuicStreamOffset size) { spdy::SpdyStreamPrecedence QuicStream::CalculateDefaultPriority( const QuicSession* session) { if (VersionUsesHttp3(session->transport_version())) { - return spdy::SpdyStreamPrecedence(QuicStream::kDefaultUrgency); + return spdy::SpdyStreamPrecedence(DefaultUrgency()); } if (session->use_http2_priority_write_scheduler()) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h index 35901906b4f..f0a5a714a21 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream.h @@ -90,9 +90,7 @@ class QUIC_EXPORT_PRIVATE PendingStream // ID of this stream. QuicStreamId id_; - // Session which owns this. - // TODO(b/136274541): Remove session pointer from streams. - QuicSession* session_; + // |stream_delegate_| must outlive this stream. StreamDelegateInterface* stream_delegate_; // Bytes read refers to payload bytes only: they do not include framing, @@ -113,6 +111,7 @@ class QUIC_EXPORT_PRIVATE PendingStream class QUIC_EXPORT_PRIVATE QuicStream : public QuicStreamSequencer::StreamInterface { public: + // Default priority for Google QUIC. // This is somewhat arbitrary. It's possible, but unlikely, we will either // fail to set a priority client-side, or cancel a stream before stripping the // priority from the wire server-side. In either case, start out with a @@ -121,10 +120,6 @@ class QUIC_EXPORT_PRIVATE QuicStream static_assert(kDefaultPriority == (spdy::kV3LowestPriority + spdy::kV3HighestPriority) / 2, "Unexpected value of kDefaultPriority"); - // On the other hand, when using IETF QUIC, use the default value defined by - // the priority extension at - // https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html#default. - static const int kDefaultUrgency = 1; // Creates a new stream with stream_id |id| associated with |session|. If // |is_static| is true, then the stream will be given precedence @@ -136,12 +131,21 @@ class QUIC_EXPORT_PRIVATE QuicStream QuicSession* session, bool is_static, StreamType type); - QuicStream(PendingStream* pending, StreamType type, bool is_static); + QuicStream(PendingStream* pending, + QuicSession* session, + StreamType type, + bool is_static); QuicStream(const QuicStream&) = delete; QuicStream& operator=(const QuicStream&) = delete; virtual ~QuicStream(); + // Default priority for IETF QUIC, defined by the priority extension at + // https://httpwg.org/http-extensions/draft-ietf-httpbis-priority.html#urgency. + // TODO(bnc): Remove this method and reinstate static const int + // kDefaultUrgency member when removing quic_http3_new_default_urgency_value. + static int DefaultUrgency(); + // QuicStreamSequencer::StreamInterface implementation. QuicStreamId id() const override { return id_; } // Called by the stream subclass after it has consumed the final incoming @@ -338,29 +342,9 @@ class QUIC_EXPORT_PRIVATE QuicStream StreamType type() const { return type_; } - // Creates and sends a STOP_SENDING frame. This can be called regardless of - // the version that has been negotiated. If not IETF QUIC/Version 99 then the - // method is a noop, relieving the application of the necessity of - // understanding the connection's QUIC version and knowing whether it can call - // this method or not. - void SendStopSending(uint16_t code); - // Handle received StopSending frame. Returns true if the processing finishes // gracefully. - virtual bool OnStopSending(uint16_t code); - - // Close the write side of the socket. Further writes will fail. - // Can be called by the subclass or internally. - // Does not send a FIN. May cause the stream to be closed. - virtual void CloseWriteSide(); - - // Close the read side of the stream. May cause the stream to be closed. - // Subclasses and consumers should use StopReading to terminate reading early - // if expecting a FIN. Can be used directly by subclasses if not expecting a - // FIN. - // TODO(fayang): move this to protected when removing - // QuicSession::CloseStream. - void CloseReadSide(); + virtual bool OnStopSending(QuicRstStreamErrorCode code); // Returns true if the stream is static. bool is_static() const { return is_static_; } @@ -370,6 +354,10 @@ class QUIC_EXPORT_PRIVATE QuicStream static spdy::SpdyStreamPrecedence CalculateDefaultPriority( const QuicSession* session); + QuicTime creation_time() const { return creation_time_; } + + bool fin_buffered() const { return fin_buffered_; } + protected: // Called when data of [offset, offset + data_length] is buffered in send // buffer. @@ -414,13 +402,16 @@ class QUIC_EXPORT_PRIVATE QuicStream // empty. void SetFinSent(); + // Close the write side of the socket. Further writes will fail. + // Can be called by the subclass or internally. + // Does not send a FIN. May cause the stream to be closed. + virtual void CloseWriteSide(); + void set_rst_received(bool rst_received) { rst_received_ = rst_received; } void set_stream_error(QuicRstStreamErrorCode error) { stream_error_ = error; } StreamDelegateInterface* stream_delegate() { return stream_delegate_; } - bool fin_buffered() const { return fin_buffered_; } - const QuicSession* session() const { return session_; } QuicSession* session() { return session_; } @@ -461,6 +452,9 @@ class QUIC_EXPORT_PRIVATE QuicStream // WriteOrBufferData, Writev and WriteBufferedData. void WriteBufferedData(); + // Close the read side of the stream. May cause the stream to be closed. + void CloseReadSide(); + // Called when bytes are sent to the peer. void AddBytesSent(QuicByteCount bytes); @@ -553,6 +547,9 @@ class QUIC_EXPORT_PRIVATE QuicStream // write unidirectional. const StreamType type_; + // Creation time of this stream, as reported by the QuicClock. + const QuicTime creation_time_; + Perspective perspective_; }; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc index 206fb7123b9..f2b5563344b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_stream_test.cc @@ -58,8 +58,11 @@ class TestStream : public QuicStream { sequencer()->set_level_triggered(true); } - TestStream(PendingStream* pending, StreamType type, bool is_static) - : QuicStream(pending, type, is_static) {} + TestStream(PendingStream* pending, + QuicSession* session, + StreamType type, + bool is_static) + : QuicStream(pending, session, type, is_static) {} MOCK_METHOD(void, OnDataAvailable, (), (override)); @@ -169,11 +172,12 @@ TEST_P(QuicStreamTest, PendingStreamStaticness) { Initialize(); PendingStream pending(kTestStreamId + 2, session_.get()); - TestStream stream(&pending, StreamType::BIDIRECTIONAL, false); + TestStream stream(&pending, session_.get(), StreamType::BIDIRECTIONAL, false); EXPECT_FALSE(stream.is_static()); PendingStream pending2(kTestStreamId + 3, session_.get()); - TestStream stream2(&pending2, StreamType::BIDIRECTIONAL, true); + TestStream stream2(&pending2, session_.get(), StreamType::BIDIRECTIONAL, + true); EXPECT_TRUE(stream2.is_static()); } @@ -233,7 +237,8 @@ TEST_P(QuicStreamTest, FromPendingStream) { QuicStreamFrame frame2(kTestStreamId + 2, true, 3, "."); pending.OnStreamFrame(frame2); - TestStream stream(&pending, StreamType::READ_UNIDIRECTIONAL, false); + TestStream stream(&pending, session_.get(), StreamType::READ_UNIDIRECTIONAL, + false); EXPECT_EQ(3, stream.num_frames_received()); EXPECT_EQ(3u, stream.stream_bytes_read()); EXPECT_EQ(1, stream.num_duplicate_frames_received()); @@ -251,8 +256,8 @@ TEST_P(QuicStreamTest, FromPendingStreamThenData) { QuicStreamFrame frame(kTestStreamId + 2, false, 2, "."); pending.OnStreamFrame(frame); - auto stream = - new TestStream(&pending, StreamType::READ_UNIDIRECTIONAL, false); + auto stream = new TestStream(&pending, session_.get(), + StreamType::READ_UNIDIRECTIONAL, false); session_->ActivateStream(QuicWrapUnique(stream)); QuicStreamFrame frame2(kTestStreamId + 2, true, 3, "."); @@ -455,7 +460,7 @@ TEST_P(QuicStreamTest, RstAlwaysSentIfNoFinSent) { // Now close the stream, and expect that we send a RST. EXPECT_CALL(*session_, SendRstStream(_, _, _, _)); - stream_->CloseReadSide(); + QuicStreamPeer::CloseReadSide(stream_); stream_->CloseWriteSide(); EXPECT_FALSE(session_->HasUnackedStreamData()); EXPECT_FALSE(fin_sent()); @@ -483,7 +488,7 @@ TEST_P(QuicStreamTest, RstNotSentIfFinSent) { EXPECT_FALSE(rst_sent()); // Now close the stream, and expect that we do not send a RST. - stream_->CloseReadSide(); + QuicStreamPeer::CloseReadSide(stream_); stream_->CloseWriteSide(); EXPECT_TRUE(fin_sent()); EXPECT_FALSE(rst_sent()); @@ -508,7 +513,7 @@ TEST_P(QuicStreamTest, OnlySendOneRst) { // Now close the stream (any further resets being sent would break the // expectation above). - stream_->CloseReadSide(); + QuicStreamPeer::CloseReadSide(stream_); stream_->CloseWriteSide(); EXPECT_FALSE(fin_sent()); EXPECT_TRUE(rst_sent()); @@ -642,7 +647,7 @@ TEST_P(QuicStreamTest, InvalidFinalByteOffsetFromRst) { CloseConnection(QUIC_FLOW_CONTROL_RECEIVED_TOO_MUCH_DATA, _, _)); stream_->OnStreamReset(rst_frame); EXPECT_TRUE(stream_->HasReceivedFinalOffset()); - stream_->CloseReadSide(); + QuicStreamPeer::CloseReadSide(stream_); stream_->CloseWriteSide(); } @@ -1554,30 +1559,6 @@ TEST_P(QuicStreamTest, ResetStreamOnTtlExpiresEarlyRetransmitData) { stream_->RetransmitStreamData(0, 100, false, PTO_RETRANSMISSION); } -// Test that QuicStream::StopSending A) is a no-op if the connection is not in -// version 99, B) that it properly invokes QuicSession::StopSending, and C) that -// the correct data is passed along, including getting the stream ID. -TEST_P(QuicStreamTest, CheckStopSending) { - Initialize(); - const int kStopSendingCode = 123; - // These must start as false. - EXPECT_FALSE(stream_->write_side_closed()); - EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); - // Expect to actually see a stop sending if and only if we are in version 99. - if (VersionHasIetfQuicFrames(connection_->transport_version())) { - EXPECT_CALL(*session_, SendStopSending(kStopSendingCode, stream_->id())) - .Times(1); - } else { - EXPECT_CALL(*session_, SendStopSending(_, _)).Times(0); - } - stream_->SendStopSending(kStopSendingCode); - // Sending a STOP_SENDING does not actually close the local stream. - // Our implementation waits for the responding RESET_STREAM to effect the - // closes. Therefore, read- and write-side closes should both be false. - EXPECT_FALSE(stream_->write_side_closed()); - EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); -} - // Test that OnStreamReset does one-way (read) closes if version 99, two way // (read and write) if not version 99. TEST_P(QuicStreamTest, OnStreamResetReadOrReadWrite) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc index eeaf297c1ca..bf352f363ad 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.cc @@ -108,6 +108,75 @@ void QuicTraceVisitor::OnPacketSent(const SerializedPacket& serialized_packet, } } +void QuicTraceVisitor::OnPacketSent( + QuicPacketNumber packet_number, + QuicPacketLength packet_length, + bool /*has_crypto_handshake*/, + TransmissionType /*transmission_type*/, + EncryptionLevel encryption_level, + const QuicFrames& retransmittable_frames, + const QuicFrames& /*nonretransmittable_frames*/, + QuicTime sent_time) { + quic_trace::Event* event = trace_.add_events(); + event->set_event_type(quic_trace::PACKET_SENT); + event->set_time_us(ConvertTimestampToRecordedFormat(sent_time)); + event->set_packet_number(packet_number.ToUint64()); + event->set_packet_size(packet_length); + event->set_encryption_level(EncryptionLevelToProto(encryption_level)); + + for (const QuicFrame& frame : retransmittable_frames) { + switch (frame.type) { + case STREAM_FRAME: + case RST_STREAM_FRAME: + case CONNECTION_CLOSE_FRAME: + case WINDOW_UPDATE_FRAME: + case BLOCKED_FRAME: + case PING_FRAME: + case HANDSHAKE_DONE_FRAME: + case ACK_FREQUENCY_FRAME: + PopulateFrameInfo(frame, event->add_frames()); + break; + + case PADDING_FRAME: + case MTU_DISCOVERY_FRAME: + case STOP_WAITING_FRAME: + case ACK_FRAME: + QUIC_BUG + << "Frames of type are not retransmittable and are not supposed " + "to be in retransmittable_frames"; + break; + + // New IETF frames, not used in current gQUIC version. + case NEW_CONNECTION_ID_FRAME: + case RETIRE_CONNECTION_ID_FRAME: + case MAX_STREAMS_FRAME: + case STREAMS_BLOCKED_FRAME: + case PATH_RESPONSE_FRAME: + case PATH_CHALLENGE_FRAME: + case STOP_SENDING_FRAME: + case MESSAGE_FRAME: + case CRYPTO_FRAME: + case NEW_TOKEN_FRAME: + break; + + // Ignore gQUIC-specific frames. + case GOAWAY_FRAME: + break; + + case NUM_FRAME_TYPES: + QUIC_BUG << "Unknown frame type encountered"; + break; + } + } + + // Output PCC DebugState on packet sent for analysis. + if (connection_->sent_packet_manager() + .GetSendAlgorithm() + ->GetCongestionControlType() == kPCC) { + PopulateTransportState(event->mutable_transport_state()); + } +} + void QuicTraceVisitor::PopulateFrameInfo(const QuicFrame& frame, quic_trace::Frame* frame_record) { switch (frame.type) { diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h index c9732cf423c..889d90a06c0 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_trace_visitor.h @@ -18,10 +18,21 @@ class QUIC_NO_EXPORT QuicTraceVisitor : public QuicConnectionDebugVisitor { public: explicit QuicTraceVisitor(const QuicConnection* connection); + // TODO(wub): Delete when deprecating + // --quic_give_sent_packet_to_debug_visitor_after_sent. void OnPacketSent(const SerializedPacket& serialized_packet, TransmissionType transmission_type, QuicTime sent_time) override; + void OnPacketSent(QuicPacketNumber packet_number, + QuicPacketLength packet_length, + bool has_crypto_handshake, + TransmissionType transmission_type, + EncryptionLevel encryption_level, + const QuicFrames& retransmittable_frames, + const QuicFrames& nonretransmittable_frames, + QuicTime sent_time) override; + void OnIncomingAck(QuicPacketNumber ack_packet_number, EncryptionLevel ack_decrypted_level, const QuicAckFrame& ack_frame, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc index a27b769bccd..02b34b57a14 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.cc @@ -13,20 +13,23 @@ QuicTransmissionInfo::QuicTransmissionInfo() transmission_type(NOT_RETRANSMISSION), in_flight(false), state(OUTSTANDING), - has_crypto_handshake(false) {} + has_crypto_handshake(false), + has_ack_frequency(false) {} QuicTransmissionInfo::QuicTransmissionInfo(EncryptionLevel level, TransmissionType transmission_type, QuicTime sent_time, QuicPacketLength bytes_sent, - bool has_crypto_handshake) + bool has_crypto_handshake, + bool has_ack_frequency) : encryption_level(level), bytes_sent(bytes_sent), sent_time(sent_time), transmission_type(transmission_type), in_flight(false), state(OUTSTANDING), - has_crypto_handshake(has_crypto_handshake) {} + has_crypto_handshake(has_crypto_handshake), + has_ack_frequency(has_ack_frequency) {} QuicTransmissionInfo::QuicTransmissionInfo(const QuicTransmissionInfo& other) = default; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h index 60236650724..acc5667e9fd 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_transmission_info.h @@ -25,7 +25,8 @@ struct QUIC_EXPORT_PRIVATE QuicTransmissionInfo { TransmissionType transmission_type, QuicTime sent_time, QuicPacketLength bytes_sent, - bool has_crypto_handshake); + bool has_crypto_handshake, + bool has_ack_frequency); QuicTransmissionInfo(const QuicTransmissionInfo& other); @@ -43,6 +44,8 @@ struct QUIC_EXPORT_PRIVATE QuicTransmissionInfo { SentPacketState state; // True if the packet contains stream data from the crypto stream. bool has_crypto_handshake; + // True if the packet contains ack frequency frame. + bool has_ack_frequency; // Records the first sent packet after this packet was detected lost. Zero if // this packet has not been detected lost. This is used to keep lost packet // for another RTT (for potential spurious loss detection) diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc index fb2e9c89c4f..4027ffa60ee 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.cc @@ -299,7 +299,6 @@ std::string SerializedPacketFateToString(SerializedPacketFate fate) { RETURN_STRING_LITERAL(COALESCE); RETURN_STRING_LITERAL(BUFFER); RETURN_STRING_LITERAL(SEND_TO_WRITER); - RETURN_STRING_LITERAL(FAILED_TO_WRITE_COALESCED_PACKET); RETURN_STRING_LITERAL(LEGACY_VERSION_ENCAPSULATE); default: return quiche::QuicheStrCat("Unknown(", static_cast<int>(fate), ")"); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_types.h b/chromium/net/third_party/quiche/src/quic/core/quic_types.h index 55c5046b23a..13307bb9d6f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_types.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_types.h @@ -46,9 +46,6 @@ using PacketTimeVector = std::vector<std::pair<QuicPacketNumber, QuicTime>>; enum : size_t { kQuicPathFrameBufferSize = 8 }; using QuicPathFrameBuffer = std::array<uint8_t, kQuicPathFrameBufferSize>; -// Application error code used in the QUIC Stop Sending frame. -using QuicApplicationErrorCode = uint16_t; - // The connection id sequence number specifies the order that connection // ids must be used in. This is also the sequence number carried in // the IETF QUIC NEW_CONNECTION_ID and RETIRE_CONNECTION_ID frames. @@ -533,6 +530,9 @@ enum SentPacketState : uint8_t { PTO_RETRANSMITTED, // This packet has been retransmitted for probing purpose. PROBE_RETRANSMITTED, + // Do not collect RTT sample if this packet is the largest_acked of an + // incoming ACK. + NOT_CONTRIBUTING_RTT, LAST_PACKET_STATE = PROBE_RETRANSMITTED, }; @@ -687,8 +687,6 @@ enum PacketNumberSpace : uint8_t { QUIC_EXPORT_PRIVATE std::string PacketNumberSpaceToString( PacketNumberSpace packet_number_space); -enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING }; - // Used to return the result of processing a received ACK frame. enum AckResult { PACKETS_NEWLY_ACKED, @@ -709,10 +707,6 @@ enum SerializedPacketFate : uint8_t { COALESCE, // Try to coalesce packet. BUFFER, // Buffer packet in buffered_packets_. SEND_TO_WRITER, // Send packet to writer. - // TODO(fayang): remove FAILED_TO_WRITE_COALESCED_PACKET when deprecating - // quic_determine_serialized_packet_fate_early. - FAILED_TO_WRITE_COALESCED_PACKET, // Packet cannot be coalesced, error occurs - // when sending existing coalesced packet. LEGACY_VERSION_ENCAPSULATE, // Perform Legacy Version Encapsulation on this // packet. }; diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc index c5ab345f433..ea68727211c 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_udp_socket_posix.cc @@ -68,11 +68,7 @@ QuicUdpSocketFd CreateNonblockingSocket(int address_family) { << strerror(errno); return kQuicInvalidSocketFd; } - - return fd; - #else - // Create a socket and use fcntl to set it to nonblocking. // This implementation is used when building for iOS, OSX and old versions of // Linux (< 2.6.27) and old versions of Android (< API 21). @@ -98,10 +94,10 @@ QuicUdpSocketFd CreateNonblockingSocket(int address_family) { close(fd); return kQuicInvalidSocketFd; } +#endif + SetGoogleSocketOptions(fd); return fd; - -#endif } // End CreateNonblockingSocket void SetV4SelfIpInControlMessage(const QuicIpAddress& self_address, diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc index dd70f823be6..3e377cfa21b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.cc @@ -128,12 +128,14 @@ QuicUnackedPacketMap::~QuicUnackedPacketMap() { } } -void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, +void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* mutable_packet, TransmissionType transmission_type, QuicTime sent_time, - bool set_in_flight) { - QuicPacketNumber packet_number = packet->packet_number; - QuicPacketLength bytes_sent = packet->encrypted_length; + bool set_in_flight, + bool measure_rtt) { + const SerializedPacket& packet = *mutable_packet; + QuicPacketNumber packet_number = packet.packet_number; + QuicPacketLength bytes_sent = packet.encrypted_length; QUIC_BUG_IF(largest_sent_packet_.IsInitialized() && largest_sent_packet_ >= packet_number) << "largest_sent_packet_: " << largest_sent_packet_ @@ -144,12 +146,17 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, unacked_packets_.back().state = NEVER_SENT; } - const bool has_crypto_handshake = - packet->has_crypto_handshake == IS_HANDSHAKE; - QuicTransmissionInfo info(packet->encryption_level, transmission_type, - sent_time, bytes_sent, has_crypto_handshake); - info.largest_acked = packet->largest_acked; - largest_sent_largest_acked_.UpdateMax(packet->largest_acked); + const bool has_crypto_handshake = packet.has_crypto_handshake == IS_HANDSHAKE; + QuicTransmissionInfo info(packet.encryption_level, transmission_type, + sent_time, bytes_sent, has_crypto_handshake, + packet.has_ack_frequency); + info.largest_acked = packet.largest_acked; + largest_sent_largest_acked_.UpdateMax(packet.largest_acked); + + if (!measure_rtt) { + QUIC_BUG_IF(set_in_flight); + info.state = NOT_CONTRIBUTING_RTT; + } largest_sent_packet_ = packet_number; if (set_in_flight) { @@ -170,7 +177,7 @@ void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, last_crypto_packet_sent_time_ = sent_time; } - packet->retransmittable_frames.swap( + mutable_packet->retransmittable_frames.swap( unacked_packets_.back().retransmittable_frames); } @@ -240,7 +247,8 @@ bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt( // Packet can be used for RTT measurement if it may yet be acked as the // largest observed packet by the receiver. return QuicUtils::IsAckable(info.state) && - (!largest_acked_.IsInitialized() || packet_number > largest_acked_); + (!largest_acked_.IsInitialized() || packet_number > largest_acked_) && + info.state != NOT_CONTRIBUTING_RTT; } bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl( diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h index 9f67e2b74c8..595f435e0fc 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h @@ -30,16 +30,17 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { QuicUnackedPacketMap& operator=(const QuicUnackedPacketMap&) = delete; ~QuicUnackedPacketMap(); - // Adds |serialized_packet| to the map and marks it as sent at |sent_time|. + // Adds |mutable_packet| to the map and marks it as sent at |sent_time|. // Marks the packet as in flight if |set_in_flight| is true. // Packets marked as in flight are expected to be marked as missing when they // don't arrive, indicating the need for retransmission. - // Any AckNotifierWrappers in |serialized_packet| are swapped from the - // serialized packet into the QuicTransmissionInfo. - void AddSentPacket(SerializedPacket* serialized_packet, + // Any retransmittible_frames in |mutable_packet| are swapped from + // |mutable_packet| into the QuicTransmissionInfo. + void AddSentPacket(SerializedPacket* mutable_packet, TransmissionType transmission_type, QuicTime sent_time, - bool set_in_flight); + bool set_in_flight, + bool measure_rtt); // Returns true if the packet |packet_number| is unacked. bool IsUnacked(QuicPacketNumber packet_number) const; @@ -114,10 +115,13 @@ class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { typedef std::deque<QuicTransmissionInfo> UnackedPacketMap; typedef UnackedPacketMap::const_iterator const_iterator; + typedef UnackedPacketMap::const_reverse_iterator const_reverse_iterator; typedef UnackedPacketMap::iterator iterator; const_iterator begin() const { return unacked_packets_.begin(); } const_iterator end() const { return unacked_packets_.end(); } + const_reverse_iterator rbegin() const { return unacked_packets_.rbegin(); } + const_reverse_iterator rend() const { return unacked_packets_.rend(); } iterator begin() { return unacked_packets_.begin(); } iterator end() { return unacked_packets_.end(); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc index 330cc11c8b0..96ba08acb35 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_unacked_packet_map_test.cc @@ -153,7 +153,8 @@ class QuicUnackedPacketMapTest : public QuicTestWithParam<Perspective> { info->first_sent_after_loss = QuicPacketNumber(new_packet_number); SerializedPacket packet( CreateRetransmittablePacketForStream(new_packet_number, stream_id)); - unacked_packets_.AddSentPacket(&packet, transmission_type, now_, true); + unacked_packets_.AddSentPacket(&packet, transmission_type, now_, true, + true); } QuicUnackedPacketMap unacked_packets_; QuicTime now_; @@ -169,7 +170,8 @@ INSTANTIATE_TEST_SUITE_P(Tests, TEST_P(QuicUnackedPacketMapTest, RttOnly) { // Acks are only tracked for RTT measurement purposes. SerializedPacket packet(CreateNonRetransmittablePacket(1)); - unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, false); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, false, + true); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked)); @@ -185,7 +187,7 @@ TEST_P(QuicUnackedPacketMapTest, RttOnly) { TEST_P(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) { // Simulate a retransmittable packet being sent and acked. SerializedPacket packet(CreateRetransmittablePacket(1)); - unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true, true); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked)); @@ -211,7 +213,7 @@ TEST_P(QuicUnackedPacketMapTest, RetransmittableInflightAndRtt) { TEST_P(QuicUnackedPacketMapTest, StopRetransmission) { const QuicStreamId stream_id = 2; SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id)); - unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true, true); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked)); @@ -229,7 +231,7 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmission) { TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) { const QuicStreamId stream_id = 2; SerializedPacket packet(CreateRetransmittablePacketForStream(1, stream_id)); - unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet, NOT_RETRANSMISSION, now_, true, true); uint64_t unacked[] = {1}; VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked)); @@ -247,7 +249,8 @@ TEST_P(QuicUnackedPacketMapTest, StopRetransmissionOnOtherStream) { TEST_P(QuicUnackedPacketMapTest, StopRetransmissionAfterRetransmission) { const QuicStreamId stream_id = 2; SerializedPacket packet1(CreateRetransmittablePacketForStream(1, stream_id)); - unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true, + true); RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION); uint64_t unacked[] = {1, 2}; @@ -266,7 +269,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmittedPacket) { // Simulate a retransmittable packet being sent, retransmitted, and the first // transmission being acked. SerializedPacket packet1(CreateRetransmittablePacket(1)); - unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true, + true); RetransmitAndSendPacket(1, 2, LOSS_RETRANSMISSION); uint64_t unacked[] = {1, 2}; @@ -301,9 +305,11 @@ TEST_P(QuicUnackedPacketMapTest, RetransmittedPacket) { TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) { // Simulate a retransmittable packet being sent and retransmitted twice. SerializedPacket packet1(CreateRetransmittablePacket(1)); - unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true, + true); SerializedPacket packet2(CreateRetransmittablePacket(2)); - unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true, + true); uint64_t unacked[] = {1, 2}; VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked)); @@ -319,7 +325,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.RemoveFromInFlight(QuicPacketNumber(1)); RetransmitAndSendPacket(1, 3, LOSS_RETRANSMISSION); SerializedPacket packet4(CreateRetransmittablePacket(4)); - unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true, + true); uint64_t unacked2[] = {1, 3, 4}; VerifyUnackedPackets(unacked2, QUICHE_ARRAYSIZE(unacked2)); @@ -334,7 +341,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) { unacked_packets_.RemoveRetransmittability(QuicPacketNumber(4)); RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION); SerializedPacket packet6(CreateRetransmittablePacket(6)); - unacked_packets_.AddSentPacket(&packet6, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet6, NOT_RETRANSMISSION, now_, true, + true); std::vector<uint64_t> unacked3 = {3, 5, 6}; std::vector<uint64_t> retransmittable3 = {3, 5, 6}; @@ -366,9 +374,11 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitThreeTimes) { TEST_P(QuicUnackedPacketMapTest, RetransmitFourTimes) { // Simulate a retransmittable packet being sent and retransmitted twice. SerializedPacket packet1(CreateRetransmittablePacket(1)); - unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true, + true); SerializedPacket packet2(CreateRetransmittablePacket(2)); - unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true, + true); uint64_t unacked[] = {1, 2}; VerifyUnackedPackets(unacked, QUICHE_ARRAYSIZE(unacked)); @@ -394,7 +404,8 @@ TEST_P(QuicUnackedPacketMapTest, RetransmitFourTimes) { // TLP 3 (formerly 1) as 4, and don't remove 1 from unacked. RetransmitAndSendPacket(3, 4, TLP_RETRANSMISSION); SerializedPacket packet5(CreateRetransmittablePacket(5)); - unacked_packets_.AddSentPacket(&packet5, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet5, NOT_RETRANSMISSION, now_, true, + true); uint64_t unacked3[] = {1, 3, 4, 5}; VerifyUnackedPackets(unacked3, QUICHE_ARRAYSIZE(unacked3)); @@ -423,9 +434,11 @@ TEST_P(QuicUnackedPacketMapTest, SendWithGap) { // Simulate a retransmittable packet being sent, retransmitted, and the first // transmission being acked. SerializedPacket packet1(CreateRetransmittablePacket(1)); - unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true, + true); SerializedPacket packet3(CreateRetransmittablePacket(3)); - unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true, + true); RetransmitAndSendPacket(3, 5, LOSS_RETRANSMISSION); EXPECT_EQ(QuicPacketNumber(1u), unacked_packets_.GetLeastUnacked()); @@ -571,7 +584,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 1. SerializedPacket packet1(CreateRetransmittablePacket(1)); packet1.encryption_level = ENCRYPTION_INITIAL; - unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet1, NOT_RETRANSMISSION, now_, true, + true); EXPECT_EQ(QuicPacketNumber(1u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace( @@ -583,7 +597,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 2. SerializedPacket packet2(CreateRetransmittablePacket(2)); packet2.encryption_level = ENCRYPTION_HANDSHAKE; - unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet2, NOT_RETRANSMISSION, now_, true, + true); EXPECT_EQ(QuicPacketNumber(2u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace( @@ -598,7 +613,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 3. SerializedPacket packet3(CreateRetransmittablePacket(3)); packet3.encryption_level = ENCRYPTION_ZERO_RTT; - unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet3, NOT_RETRANSMISSION, now_, true, + true); EXPECT_EQ(QuicPacketNumber(3u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace( @@ -618,7 +634,8 @@ TEST_P(QuicUnackedPacketMapTest, LargestSentPacketMultiplePacketNumberSpaces) { // Send packet 4. SerializedPacket packet4(CreateRetransmittablePacket(4)); packet4.encryption_level = ENCRYPTION_FORWARD_SECURE; - unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true); + unacked_packets_.AddSentPacket(&packet4, NOT_RETRANSMISSION, now_, true, + true); EXPECT_EQ(QuicPacketNumber(4u), unacked_packets_.largest_sent_packet()); EXPECT_EQ(QuicPacketNumber(1), unacked_packets_.GetLargestSentRetransmittableOfPacketNumberSpace( diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc index aaadac11c9e..b6619d4398e 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.cc @@ -173,6 +173,7 @@ const char* QuicUtils::SentPacketStateToString(SentPacketState state) { RETURN_STRING_LITERAL(RTO_RETRANSMITTED); RETURN_STRING_LITERAL(PTO_RETRANSMITTED); RETURN_STRING_LITERAL(PROBE_RETRANSMITTED); + RETURN_STRING_LITERAL(NOT_CONTRIBUTING_RTT) } return "INVALID_SENT_PACKET_STATE"; } @@ -304,6 +305,9 @@ bool QuicUtils::IsRetransmittableFrame(QuicFrameType type) { case PADDING_FRAME: case STOP_WAITING_FRAME: case MTU_DISCOVERY_FRAME: + case PATH_CHALLENGE_FRAME: + case PATH_RESPONSE_FRAME: + case NEW_CONNECTION_ID_FRAME: return false; default: return true; @@ -653,5 +657,18 @@ EncryptionLevel QuicUtils::GetEncryptionLevel( } } +// static +bool QuicUtils::IsProbingFrame(QuicFrameType type) { + switch (type) { + case PATH_CHALLENGE_FRAME: + case PATH_RESPONSE_FRAME: + case NEW_CONNECTION_ID_FRAME: + case PADDING_FRAME: + return true; + default: + return false; + } +} + #undef RETURN_STRING_LITERAL // undef for jumbo builds } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h index 9e190e0b386..05c7124194a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_utils.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_utils.h @@ -230,6 +230,9 @@ class QUIC_EXPORT_PRIVATE QuicUtils { // exceeds this value, it will result in a stream ID that exceeds the // implementation limit on stream ID size. static QuicStreamCount GetMaxStreamCount(); + + // Return true if this frame is an IETF probing frame. + static bool IsProbingFrame(QuicFrameType type); }; template <typename Mask> diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc index 52bb9a2d2f0..7cf6a1d8c24 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.cc @@ -19,7 +19,7 @@ QuicVersionManager::QuicVersionManager( GetQuicReloadableFlag(quic_disable_version_draft_29)), disable_version_draft_27_( GetQuicReloadableFlag(quic_disable_version_draft_27)), - enable_version_t051_(GetQuicReloadableFlag(quic_enable_version_t051)), + disable_version_t051_(GetQuicReloadableFlag(quic_disable_version_t051)), disable_version_t050_(GetQuicReloadableFlag(quic_disable_version_t050)), disable_version_q050_(GetQuicReloadableFlag(quic_disable_version_q050)), disable_version_q046_(GetQuicReloadableFlag(quic_disable_version_q046)), @@ -61,7 +61,8 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() { GetQuicReloadableFlag(quic_disable_version_draft_29) || disable_version_draft_27_ != GetQuicReloadableFlag(quic_disable_version_draft_27) || - enable_version_t051_ != GetQuicReloadableFlag(quic_enable_version_t051) || + disable_version_t051_ != + GetQuicReloadableFlag(quic_disable_version_t051) || disable_version_t050_ != GetQuicReloadableFlag(quic_disable_version_t050) || disable_version_q050_ != @@ -74,7 +75,7 @@ void QuicVersionManager::MaybeRefilterSupportedVersions() { GetQuicReloadableFlag(quic_disable_version_draft_29); disable_version_draft_27_ = GetQuicReloadableFlag(quic_disable_version_draft_27); - enable_version_t051_ = GetQuicReloadableFlag(quic_enable_version_t051); + disable_version_t051_ = GetQuicReloadableFlag(quic_disable_version_t051); disable_version_t050_ = GetQuicReloadableFlag(quic_disable_version_t050); disable_version_q050_ = GetQuicReloadableFlag(quic_disable_version_q050); disable_version_q046_ = GetQuicReloadableFlag(quic_disable_version_q046); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h index cbf5de1cd92..9c742f5eece 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_version_manager.h @@ -50,14 +50,16 @@ class QUIC_EXPORT_PRIVATE QuicVersionManager { // Should be called in constructor and RefilterSupportedVersions. void AddCustomAlpn(const std::string& alpn); + bool disable_version_q050() const { return disable_version_q050_; } + private: // Cached value of reloadable flags. // quic_disable_version_draft_29 flag bool disable_version_draft_29_; // quic_disable_version_draft_27 flag bool disable_version_draft_27_; - // quic_enable_version_t051 flag - bool enable_version_t051_; + // quic_disable_version_t051 flag + bool disable_version_t051_; // quic_disable_version_t050 flag bool disable_version_t050_; // quic_disable_version_q050 flag diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc index 4b10cb78a78..d3f707bdda7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions.cc @@ -49,7 +49,7 @@ void SetVersionFlag(const ParsedQuicVersion& version, bool should_enable) { } else if (version == ParsedQuicVersion::Draft27()) { SetQuicReloadableFlag(quic_disable_version_draft_27, disable); } else if (version == ParsedQuicVersion::T051()) { - SetQuicReloadableFlag(quic_enable_version_t051, enable); + SetQuicReloadableFlag(quic_disable_version_t051, disable); } else if (version == ParsedQuicVersion::T050()) { SetQuicReloadableFlag(quic_disable_version_t050, disable); } else if (version == ParsedQuicVersion::Q050()) { @@ -360,7 +360,6 @@ ParsedQuicVersion ParseQuicVersionString( return version; } } - if (GetQuicReloadableFlag(quic_fix_print_draft_version)) { for (const ParsedQuicVersion& version : AllSupportedVersions()) { if (version.UsesHttp3() && version_string == @@ -368,7 +367,6 @@ ParsedQuicVersion ParseQuicVersionString( return version; } } - } // Reading from the client so this should not be considered an ERROR. QUIC_DLOG(INFO) << "Unsupported QUIC version string: \"" << version_string << "\"."; @@ -424,7 +422,7 @@ ParsedQuicVersionVector FilterSupportedVersions( filtered_versions.push_back(version); } } else if (version == ParsedQuicVersion::T051()) { - if (GetQuicReloadableFlag(quic_enable_version_t051)) { + if (!GetQuicReloadableFlag(quic_disable_version_t051)) { filtered_versions.push_back(version); } } else if (version == ParsedQuicVersion::T050()) { @@ -563,16 +561,14 @@ std::string ParsedQuicVersionToString(ParsedQuicVersion version) { if (version == UnsupportedQuicVersion()) { return "0"; } - if (GetQuicReloadableFlag(quic_fix_print_draft_version)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_print_draft_version); - if (version == ParsedQuicVersion::Draft29()) { - DCHECK(version.UsesHttp3()); - return "draft29"; - } else if (version == ParsedQuicVersion::Draft27()) { - DCHECK(version.UsesHttp3()); - return "draft27"; - } + if (version == ParsedQuicVersion::Draft29()) { + DCHECK(version.UsesHttp3()); + return "draft29"; + } else if (version == ParsedQuicVersion::Draft27()) { + DCHECK(version.UsesHttp3()); + return "draft27"; } + return QuicVersionLabelToString(CreateQuicVersionLabel(version)); } @@ -667,7 +663,6 @@ std::string AlpnForVersion(ParsedQuicVersion parsed_version) { void QuicVersionInitializeSupportForIetfDraft() { // Enable necessary flags. - SetQuicRestartFlag(quic_enable_tls_resumption_v4, true); SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true); } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc index 1eff47a845f..fa32de3f9b8 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_versions_test.cc @@ -236,14 +236,10 @@ TEST_F(QuicVersionsTest, ParseQuicVersionString) { EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("T050")); EXPECT_EQ(ParsedQuicVersion::T050(), ParseQuicVersionString("h3-T050")); EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("ff00001d")); - if (GetQuicReloadableFlag(quic_fix_print_draft_version)) { - EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("draft29")); - } + EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("draft29")); EXPECT_EQ(ParsedQuicVersion::Draft29(), ParseQuicVersionString("h3-29")); EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("ff00001b")); - if (GetQuicReloadableFlag(quic_fix_print_draft_version)) { - EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("draft27")); - } + EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("draft27")); EXPECT_EQ(ParsedQuicVersion::Draft27(), ParseQuicVersionString("h3-27")); for (const ParsedQuicVersion& version : AllSupportedVersions()) { @@ -407,17 +403,8 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { EXPECT_EQ("Q046", ParsedQuicVersionToString(ParsedQuicVersion::Q046())); EXPECT_EQ("Q050", ParsedQuicVersionToString(ParsedQuicVersion::Q050())); EXPECT_EQ("T050", ParsedQuicVersionToString(ParsedQuicVersion::T050())); - if (GetQuicReloadableFlag(quic_fix_print_draft_version)) { - EXPECT_EQ("draft27", - ParsedQuicVersionToString(ParsedQuicVersion::Draft27())); - EXPECT_EQ("draft29", - ParsedQuicVersionToString(ParsedQuicVersion::Draft29())); - } else { - EXPECT_EQ("ff00001b", - ParsedQuicVersionToString(ParsedQuicVersion::Draft27())); - EXPECT_EQ("ff00001d", - ParsedQuicVersionToString(ParsedQuicVersion::Draft29())); - } + EXPECT_EQ("draft27", ParsedQuicVersionToString(ParsedQuicVersion::Draft27())); + EXPECT_EQ("draft29", ParsedQuicVersionToString(ParsedQuicVersion::Draft29())); ParsedQuicVersionVector versions_vector = {ParsedQuicVersion::Q043()}; EXPECT_EQ("Q043", ParsedQuicVersionVectorToString(versions_vector)); diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc index 3c1edc43e2f..b3602a6618a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc +++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.cc @@ -149,8 +149,17 @@ void QuicWriteBlockedList::UpdateBytesForStream(QuicStreamId stream_id, if (batch_write_stream_id_[last_priority_popped_] == stream_id) { // If this was the last data stream popped by PopFront, update the // bytes remaining in its batch write. - bytes_left_for_batch_write_[last_priority_popped_] -= - static_cast<int32_t>(bytes); + if (fix_bytes_left_for_batch_write_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_bytes_left_for_batch_write); + // TODO(fayang): change this static_cast to static_cast<uint32_t> when + // deprecating quic_fix_bytes_left_for_batch_write. + bytes_left_for_batch_write_[last_priority_popped_] -= + std::min(bytes_left_for_batch_write_[last_priority_popped_], + static_cast<int32_t>(bytes)); + } else { + bytes_left_for_batch_write_[last_priority_popped_] -= + static_cast<int32_t>(bytes); + } } } diff --git a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h index fd875bccbb5..08f70b39515 100644 --- a/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h +++ b/chromium/net/third_party/quiche/src/quic/core/quic_write_blocked_list.h @@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" #include "net/third_party/quiche/src/spdy/core/fifo_write_scheduler.h" #include "net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h" @@ -103,6 +104,8 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { // Set to kBatchWriteSize when we set a new batch_write_stream_id_ for a given // priority. This is decremented with each write the stream does until it is // done with its batch write. + // TODO(fayang): switch this to uint32_t when deprecating + // quic_fix_bytes_left_for_batch_write. int32_t bytes_left_for_batch_write_[spdy::kV3LowestPriority + 1]; // Tracks the last priority popped for UpdateBytesForStream. spdy::SpdyPriority last_priority_popped_; @@ -153,6 +156,9 @@ class QUIC_EXPORT_PRIVATE QuicWriteBlockedList { StaticStreamCollection static_stream_collection_; spdy::WriteSchedulerType scheduler_type_; + + const bool fix_bytes_left_for_batch_write_ = + GetQuicReloadableFlag(quic_fix_bytes_left_for_batch_write); }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc index dfaab5143dd..ba3f9d4de4a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.cc @@ -295,6 +295,10 @@ bool TlsClientHandshaker::EarlyDataAccepted() const { return SSL_early_data_accepted(ssl()) == 1; } +ssl_early_data_reason_t TlsClientHandshaker::EarlyDataReason() const { + return TlsHandshaker::EarlyDataReason(); +} + bool TlsClientHandshaker::ReceivedInchoateReject() const { QUIC_BUG_IF(!one_rtt_keys_available_); // REJ messages are a QUIC crypto feature, so TLS always returns false. @@ -382,10 +386,16 @@ void TlsClientHandshaker::SetWriteSecret( if (level == ENCRYPTION_FORWARD_SECURE || level == ENCRYPTION_ZERO_RTT) { encryption_established_ = true; } - if (level == ENCRYPTION_FORWARD_SECURE) { + const bool postpone_discarding_zero_rtt_keys = + GetQuicReloadableFlag(quic_postpone_discarding_zero_rtt_keys); + if (!postpone_discarding_zero_rtt_keys && + level == ENCRYPTION_FORWARD_SECURE) { handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT); } TlsHandshaker::SetWriteSecret(level, cipher, write_secret); + if (postpone_discarding_zero_rtt_keys && level == ENCRYPTION_FORWARD_SECURE) { + handshaker_delegate()->DiscardOldEncryptionKey(ENCRYPTION_ZERO_RTT); + } } void TlsClientHandshaker::OnHandshakeConfirmed() { @@ -456,6 +466,14 @@ void TlsClientHandshaker::CloseConnection(QuicErrorCode error, } void TlsClientHandshaker::FinishHandshake() { + // Fill crypto_negotiated_params_: + const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); + if (cipher) { + crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); + } + crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); + crypto_negotiated_params_->peer_signature_algorithm = + SSL_get_peer_signature_algorithm(ssl()); if (SSL_in_early_data(ssl())) { // SSL_do_handshake returns after sending the ClientHello if the session is // 0-RTT-capable, which means that FinishHandshake will get called twice - @@ -470,14 +488,6 @@ void TlsClientHandshaker::FinishHandshake() { } QUIC_LOG(INFO) << "Client: handshake finished"; state_ = STATE_HANDSHAKE_COMPLETE; - // Fill crypto_negotiated_params_: - const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl()); - if (cipher) { - crypto_negotiated_params_->cipher_suite = SSL_CIPHER_get_value(cipher); - } - crypto_negotiated_params_->key_exchange_group = SSL_get_curve_id(ssl()); - crypto_negotiated_params_->peer_signature_algorithm = - SSL_get_peer_signature_algorithm(ssl()); std::string error_details; if (!ProcessTransportParameters(&error_details)) { @@ -522,7 +532,7 @@ void TlsClientHandshaker::HandleZeroRttReject() { DCHECK(session_cache_); // Disable encrytion to block outgoing data until 1-RTT keys are available. encryption_established_ = false; - handshaker_delegate()->OnZeroRttRejected(); + handshaker_delegate()->OnZeroRttRejected(EarlyDataReason()); SSL_reset_early_data_reject(ssl()); session_cache_->ClearEarlyData(server_id_); AdvanceHandshake(); diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h index bf05ca88fb4..2a09fb83818 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker.h @@ -46,6 +46,7 @@ class QUIC_EXPORT_PRIVATE TlsClientHandshaker int num_sent_client_hellos() const override; bool IsResumption() const override; bool EarlyDataAccepted() const override; + ssl_early_data_reason_t EarlyDataReason() const override; bool ReceivedInchoateReject() const override; int num_scup_messages_received() const override; std::string chlo_hash() const override; diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc index e2988d9a9c9..132e6365786 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_client_handshaker_test.cc @@ -174,7 +174,6 @@ class TlsClientHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { server_id_(kServerHostname, kServerPort, false), server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { - SetQuicRestartFlag(quic_enable_tls_resumption_v4, true); SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true); crypto_config_ = std::make_unique<QuicCryptoClientConfig>( std::make_unique<TestProofVerifier>(), @@ -376,6 +375,8 @@ TEST_P(TlsClientHandshakerTest, ResumptionRejection) { EXPECT_TRUE(stream()->one_rtt_keys_available()); EXPECT_FALSE(stream()->IsResumption()); EXPECT_FALSE(stream()->EarlyDataAccepted()); + EXPECT_EQ(stream()->EarlyDataReason(), + ssl_early_data_unsupported_for_session); } TEST_P(TlsClientHandshakerTest, ZeroRttResumption) { @@ -399,6 +400,9 @@ TEST_P(TlsClientHandshakerTest, ZeroRttResumption) { // messages from the server. stream()->CryptoConnect(); EXPECT_TRUE(stream()->encryption_established()); + EXPECT_NE(stream()->crypto_negotiated_params().cipher_suite, 0); + EXPECT_NE(stream()->crypto_negotiated_params().key_exchange_group, 0); + EXPECT_NE(stream()->crypto_negotiated_params().peer_signature_algorithm, 0); // Finish the handshake with the server. QuicConfig config; crypto_test_utils::HandshakeWithFakeServer( @@ -410,6 +414,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRttResumption) { EXPECT_TRUE(stream()->one_rtt_keys_available()); EXPECT_TRUE(stream()->IsResumption()); EXPECT_TRUE(stream()->EarlyDataAccepted()); + EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_accepted); } TEST_P(TlsClientHandshakerTest, ZeroRttRejection) { @@ -458,6 +463,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRttRejection) { EXPECT_TRUE(stream()->one_rtt_keys_available()); EXPECT_TRUE(stream()->IsResumption()); EXPECT_FALSE(stream()->EarlyDataAccepted()); + EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_peer_declined); } TEST_P(TlsClientHandshakerTest, ZeroRttAndResumptionRejection) { @@ -506,6 +512,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRttAndResumptionRejection) { EXPECT_TRUE(stream()->one_rtt_keys_available()); EXPECT_FALSE(stream()->IsResumption()); EXPECT_FALSE(stream()->EarlyDataAccepted()); + EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_session_not_resumed); } TEST_P(TlsClientHandshakerTest, ClientSendsNoSNI) { @@ -553,16 +560,11 @@ TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) { [kTestAlpn](const std::vector<quiche::QuicheStringPiece>& alpns) { return std::find(alpns.cbegin(), alpns.cend(), kTestAlpn); }); -#if BORINGSSL_API_VERSION > 10 EXPECT_CALL(*server_connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failure (ENCRYPTION_INITIAL) 120: " "no application protocol", _)); -#else // BORINGSSL_API_VERSION <= 10 - EXPECT_CALL(*connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not select ALPN", _)); -#endif // BORINGSSL_API_VERSION stream()->CryptoConnect(); crypto_test_utils::AdvanceHandshake(connection_, stream(), 0, @@ -570,13 +572,8 @@ TEST_P(TlsClientHandshakerTest, ServerRequiresCustomALPN) { EXPECT_FALSE(stream()->one_rtt_keys_available()); EXPECT_FALSE(server_stream()->one_rtt_keys_available()); -#if BORINGSSL_API_VERSION > 10 EXPECT_FALSE(stream()->encryption_established()); EXPECT_FALSE(server_stream()->encryption_established()); -#else // BORINGSSL_API_VERSION <= 10 - EXPECT_TRUE(stream()->encryption_established()); - EXPECT_TRUE(server_stream()->encryption_established()); -#endif // BORINGSSL_API_VERSION } TEST_P(TlsClientHandshakerTest, ZeroRTTNotAttemptedOnALPNChange) { @@ -603,6 +600,7 @@ TEST_P(TlsClientHandshakerTest, ZeroRTTNotAttemptedOnALPNChange) { EXPECT_TRUE(stream()->encryption_established()); EXPECT_TRUE(stream()->one_rtt_keys_available()); EXPECT_FALSE(stream()->EarlyDataAccepted()); + EXPECT_EQ(stream()->EarlyDataReason(), ssl_early_data_alpn_mismatch); } TEST_P(TlsClientHandshakerTest, InvalidSNI) { diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc index 1b200636a91..04fab15201a 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.cc @@ -57,6 +57,10 @@ size_t TlsHandshaker::BufferSizeLimitForLevel(EncryptionLevel level) const { ssl(), TlsConnection::BoringEncryptionLevel(level)); } +ssl_early_data_reason_t TlsHandshaker::EarlyDataReason() const { + return SSL_get_early_data_reason(ssl()); +} + const EVP_MD* TlsHandshaker::Prf(const SSL_CIPHER* cipher) { return EVP_get_digestbynid(SSL_CIPHER_get_prf_nid(cipher)); } diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h index 3d5f1e2d26a..2b3c9fc20a1 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker.h @@ -44,14 +44,11 @@ class QUIC_EXPORT_PRIVATE TlsHandshaker : public TlsConnection::Delegate, return parser_error_detail_; } - // From QuicCryptoStream - virtual bool encryption_established() const = 0; - virtual bool one_rtt_keys_available() const = 0; - virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params() - const = 0; - virtual CryptoMessageParser* crypto_message_parser() { return this; } - virtual HandshakeState GetHandshakeState() const = 0; + // The following methods provide implementations to subclasses of + // TlsHandshaker which use them to implement methods of QuicCryptoStream. + CryptoMessageParser* crypto_message_parser() { return this; } size_t BufferSizeLimitForLevel(EncryptionLevel level) const; + ssl_early_data_reason_t EarlyDataReason() const; protected: virtual void AdvanceHandshake() = 0; diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc deleted file mode 100644 index caf9a9c6b1b..00000000000 --- a/chromium/net/third_party/quiche/src/quic/core/tls_handshaker_test.cc +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright (c) 2017 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 <string> -#include <utility> - -#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" -#include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h" -#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h" -#include "net/third_party/quiche/src/quic/core/quic_utils.h" -#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h" -#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" -#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" -#include "net/third_party/quiche/src/quic/test_tools/fake_proof_source.h" -#include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" -#include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_arraysize.h" -#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" - -namespace quic { -namespace test { -namespace { - -using ::testing::_; -using ::testing::ElementsAreArray; -using ::testing::Return; - -class TestProofVerifier : public ProofVerifier { - public: - TestProofVerifier() - : verifier_(crypto_test_utils::ProofVerifierForTesting()) {} - - QuicAsyncStatus VerifyProof( - const std::string& hostname, - const uint16_t port, - const std::string& server_config, - QuicTransportVersion quic_version, - quiche::QuicheStringPiece chlo_hash, - const std::vector<std::string>& certs, - const std::string& cert_sct, - const std::string& signature, - const ProofVerifyContext* context, - std::string* error_details, - std::unique_ptr<ProofVerifyDetails>* details, - std::unique_ptr<ProofVerifierCallback> callback) override { - return verifier_->VerifyProof( - hostname, port, server_config, quic_version, chlo_hash, certs, cert_sct, - signature, context, error_details, details, std::move(callback)); - } - - QuicAsyncStatus VerifyCertChain( - const std::string& hostname, - const uint16_t port, - const std::vector<std::string>& certs, - const std::string& ocsp_response, - const std::string& cert_sct, - const ProofVerifyContext* context, - std::string* error_details, - std::unique_ptr<ProofVerifyDetails>* details, - std::unique_ptr<ProofVerifierCallback> callback) override { - if (!active_) { - return verifier_->VerifyCertChain(hostname, port, certs, ocsp_response, - cert_sct, context, error_details, - details, std::move(callback)); - } - pending_ops_.push_back(std::make_unique<VerifyChainPendingOp>( - hostname, port, certs, ocsp_response, cert_sct, context, error_details, - details, std::move(callback), verifier_.get())); - return QUIC_PENDING; - } - - std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { - return nullptr; - } - - void Activate() { active_ = true; } - - size_t NumPendingCallbacks() const { return pending_ops_.size(); } - - void InvokePendingCallback(size_t n) { - CHECK(NumPendingCallbacks() > n); - pending_ops_[n]->Run(); - auto it = pending_ops_.begin() + n; - pending_ops_.erase(it); - } - - private: - // Implementation of ProofVerifierCallback that fails if the callback is ever - // run. - class FailingProofVerifierCallback : public ProofVerifierCallback { - public: - void Run(bool /*ok*/, - const std::string& /*error_details*/, - std::unique_ptr<ProofVerifyDetails>* /*details*/) override { - FAIL(); - } - }; - - class VerifyChainPendingOp { - public: - VerifyChainPendingOp(const std::string& hostname, - const uint16_t port, - const std::vector<std::string>& certs, - const std::string& ocsp_response, - const std::string& cert_sct, - const ProofVerifyContext* context, - std::string* error_details, - std::unique_ptr<ProofVerifyDetails>* details, - std::unique_ptr<ProofVerifierCallback> callback, - ProofVerifier* delegate) - : hostname_(hostname), - port_(port), - certs_(certs), - ocsp_response_(ocsp_response), - cert_sct_(cert_sct), - context_(context), - error_details_(error_details), - details_(details), - callback_(std::move(callback)), - delegate_(delegate) {} - - void Run() { - // TestProofVerifier depends on crypto_test_utils::ProofVerifierForTesting - // running synchronously. It passes a FailingProofVerifierCallback and - // runs the original callback after asserting that the verification ran - // synchronously. - QuicAsyncStatus status = delegate_->VerifyCertChain( - hostname_, port_, certs_, ocsp_response_, cert_sct_, context_, - error_details_, details_, - std::make_unique<FailingProofVerifierCallback>()); - ASSERT_NE(status, QUIC_PENDING); - callback_->Run(status == QUIC_SUCCESS, *error_details_, details_); - } - - private: - std::string hostname_; - const uint16_t port_; - std::vector<std::string> certs_; - std::string ocsp_response_; - std::string cert_sct_; - const ProofVerifyContext* context_; - std::string* error_details_; - std::unique_ptr<ProofVerifyDetails>* details_; - std::unique_ptr<ProofVerifierCallback> callback_; - ProofVerifier* delegate_; - }; - - std::unique_ptr<ProofVerifier> verifier_; - bool active_ = false; - std::vector<std::unique_ptr<VerifyChainPendingOp>> pending_ops_; -}; - -class TestQuicCryptoStream : public QuicCryptoStream { - public: - explicit TestQuicCryptoStream(QuicSession* session) - : QuicCryptoStream(session) {} - - ~TestQuicCryptoStream() override = default; - - virtual TlsHandshaker* handshaker() const = 0; - - bool encryption_established() const override { - return handshaker()->encryption_established(); - } - - bool one_rtt_keys_available() const override { - return handshaker()->one_rtt_keys_available(); - } - - const QuicCryptoNegotiatedParameters& crypto_negotiated_params() - const override { - return handshaker()->crypto_negotiated_params(); - } - - CryptoMessageParser* crypto_message_parser() override { - return handshaker()->crypto_message_parser(); - } - - void WriteCryptoData(EncryptionLevel level, - quiche::QuicheStringPiece data) override { - pending_writes_.push_back(std::make_pair(std::string(data), level)); - } - - void OnPacketDecrypted(EncryptionLevel /*level*/) override {} - void OnOneRttPacketAcknowledged() override {} - void OnHandshakePacketSent() override {} - - HandshakeState GetHandshakeState() const override { - return handshaker()->GetHandshakeState(); - } - void SetServerApplicationStateForResumption( - std::unique_ptr<ApplicationState> /*application_state*/) override {} - - const std::vector<std::pair<std::string, EncryptionLevel>>& pending_writes() { - return pending_writes_; - } - - // Sends the pending frames to |stream| and clears the array of pending - // writes. - void SendCryptoMessagesToPeer(QuicCryptoStream* stream) { - QUIC_LOG(INFO) << "Sending " << pending_writes_.size() << " frames"; - // This is a minimal re-implementation of QuicCryptoStream::OnDataAvailable. - // It doesn't work to call QuicStream::OnStreamFrame because - // QuicCryptoStream::OnDataAvailable currently (as an implementation detail) - // relies on the QuicConnection to know the EncryptionLevel to pass into - // CryptoMessageParser::ProcessInput. Since the crypto messages in this test - // never reach the framer or connection and never get encrypted/decrypted, - // QuicCryptoStream::OnDataAvailable isn't able to call ProcessInput with - // the correct EncryptionLevel. Instead, that can be short-circuited by - // directly calling ProcessInput here. - for (size_t i = 0; i < pending_writes_.size(); ++i) { - if (!stream->crypto_message_parser()->ProcessInput( - pending_writes_[i].first, pending_writes_[i].second)) { - OnUnrecoverableError(stream->crypto_message_parser()->error(), - stream->crypto_message_parser()->error_detail()); - break; - } - } - pending_writes_.clear(); - } - - private: - std::vector<std::pair<std::string, EncryptionLevel>> pending_writes_; -}; - -class MockProofHandler : public QuicCryptoClientStream::ProofHandler { - public: - MockProofHandler() = default; - ~MockProofHandler() override {} - - MOCK_METHOD( // NOLINT(build/deprecated) - void, - OnProofValid, - (const QuicCryptoClientConfig::CachedState&), - (override)); - MOCK_METHOD( // NOLINT(build/deprecated) - void, - OnProofVerifyDetailsAvailable, - (const ProofVerifyDetails&), - (override)); -}; - -class TestQuicCryptoClientStream : public TestQuicCryptoStream { - public: - explicit TestQuicCryptoClientStream(QuicSession* session) - : TestQuicCryptoClientStream(session, - QuicServerId("test.example.com", 443), - std::make_unique<TestProofVerifier>()) {} - - TestQuicCryptoClientStream(QuicSession* session, - const QuicServerId& server_id, - std::unique_ptr<ProofVerifier> proof_verifier) - : TestQuicCryptoStream(session), - crypto_config_(std::move(proof_verifier), - /*session_cache*/ nullptr), - handshaker_(new TlsClientHandshaker( - server_id, - this, - session, - crypto_test_utils::ProofVerifyContextForTesting(), - &crypto_config_, - &proof_handler_, - /*has_application_state = */ false)) {} - - ~TestQuicCryptoClientStream() override = default; - - TlsHandshaker* handshaker() const override { return handshaker_.get(); } - TlsClientHandshaker* client_handshaker() const { return handshaker_.get(); } - const MockProofHandler& proof_handler() { return proof_handler_; } - void OnHandshakeDoneReceived() override {} - - bool CryptoConnect() { return handshaker_->CryptoConnect(); } - - TestProofVerifier* GetTestProofVerifier() const { - return static_cast<TestProofVerifier*>(crypto_config_.proof_verifier()); - } - - private: - MockProofHandler proof_handler_; - QuicCryptoClientConfig crypto_config_; - std::unique_ptr<TlsClientHandshaker> handshaker_; -}; - -class TestTlsServerHandshaker : public TlsServerHandshaker { - public: - TestTlsServerHandshaker(QuicSession* session, - const QuicCryptoServerConfig& crypto_config, - TestQuicCryptoStream* test_stream) - : TlsServerHandshaker(session, crypto_config), - test_stream_(test_stream) {} - - void WriteCryptoData(EncryptionLevel level, - quiche::QuicheStringPiece data) override { - test_stream_->WriteCryptoData(level, data); - } - - private: - TestQuicCryptoStream* test_stream_; -}; - -class TestQuicCryptoServerStream : public TestQuicCryptoStream { - public: - TestQuicCryptoServerStream(QuicSession* session) - : TestQuicCryptoStream(session), - crypto_config_(QuicCryptoServerConfig::TESTING, - QuicRandom::GetInstance(), - std::make_unique<FakeProofSource>(), - KeyExchangeSource::Default()), - handshaker_( - new TestTlsServerHandshaker(session, crypto_config_, this)) {} - - ~TestQuicCryptoServerStream() override = default; - - void CancelOutstandingCallbacks() { - handshaker_->CancelOutstandingCallbacks(); - } - - void OnPacketDecrypted(EncryptionLevel level) override { - handshaker_->OnPacketDecrypted(level); - } - void OnHandshakeDoneReceived() override { DCHECK(false); } - - TlsHandshaker* handshaker() const override { return handshaker_.get(); } - - FakeProofSource* GetFakeProofSource() const { - return static_cast<FakeProofSource*>(crypto_config_.proof_source()); - } - - private: - QuicCryptoServerConfig crypto_config_; - std::unique_ptr<TlsServerHandshaker> handshaker_; -}; - -void ExchangeHandshakeMessages(TestQuicCryptoStream* client, - TestQuicCryptoServerStream* server) { - while (!client->pending_writes().empty() || - !server->pending_writes().empty()) { - client->SendCryptoMessagesToPeer(server); - server->SendCryptoMessagesToPeer(client); - } -} - -class TlsHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { - public: - TlsHandshakerTest() - : version_(GetParam()), - client_conn_(new MockQuicConnection(&conn_helper_, - &alarm_factory_, - Perspective::IS_CLIENT, - {version_})), - server_conn_(new MockQuicConnection(&conn_helper_, - &alarm_factory_, - Perspective::IS_SERVER, - {version_})), - client_session_(client_conn_, /*create_mock_crypto_stream=*/false), - server_session_(server_conn_, /*create_mock_crypto_stream=*/false) { - client_stream_ = new TestQuicCryptoClientStream(&client_session_); - client_session_.SetCryptoStream(client_stream_); - server_stream_ = new TestQuicCryptoServerStream(&server_session_); - server_session_.SetCryptoStream(server_stream_); - client_session_.Initialize(); - server_session_.Initialize(); - EXPECT_FALSE(client_stream_->encryption_established()); - EXPECT_FALSE(client_stream_->one_rtt_keys_available()); - EXPECT_FALSE(server_stream_->encryption_established()); - EXPECT_FALSE(server_stream_->one_rtt_keys_available()); - const std::string default_alpn = - AlpnForVersion(client_session_.connection()->version()); - ON_CALL(client_session_, GetAlpnsToOffer()) - .WillByDefault(Return(std::vector<std::string>({default_alpn}))); - ON_CALL(server_session_, SelectAlpn(_)) - .WillByDefault( - [default_alpn]( - const std::vector<quiche::QuicheStringPiece>& alpns) { - return std::find(alpns.begin(), alpns.end(), default_alpn); - }); - } - - void ExpectHandshakeSuccessful() { - EXPECT_TRUE(client_stream_->one_rtt_keys_available()); - EXPECT_TRUE(client_stream_->encryption_established()); - EXPECT_TRUE(server_stream_->one_rtt_keys_available()); - EXPECT_TRUE(server_stream_->encryption_established()); - EXPECT_EQ(HANDSHAKE_COMPLETE, client_stream_->GetHandshakeState()); - EXPECT_EQ(HANDSHAKE_CONFIRMED, server_stream_->GetHandshakeState()); - - const auto& client_crypto_params = - client_stream_->crypto_negotiated_params(); - const auto& server_crypto_params = - server_stream_->crypto_negotiated_params(); - // The TLS params should be filled in on the client. - EXPECT_NE(0, client_crypto_params.cipher_suite); - EXPECT_NE(0, client_crypto_params.key_exchange_group); - EXPECT_NE(0, client_crypto_params.peer_signature_algorithm); - - // The cipher suite and key exchange group should match on the client and - // server. - EXPECT_EQ(client_crypto_params.cipher_suite, - server_crypto_params.cipher_suite); - EXPECT_EQ(client_crypto_params.key_exchange_group, - server_crypto_params.key_exchange_group); - // We don't support client certs on the server (yet), so the server - // shouldn't have a peer signature algorithm to report. - EXPECT_EQ(0, server_crypto_params.peer_signature_algorithm); - } - - ParsedQuicVersion version_; - MockQuicConnectionHelper conn_helper_; - MockAlarmFactory alarm_factory_; - MockQuicConnection* client_conn_; - MockQuicConnection* server_conn_; - MockQuicSession client_session_; - MockQuicSession server_session_; - - TestQuicCryptoClientStream* client_stream_; - TestQuicCryptoServerStream* server_stream_; -}; - -std::vector<ParsedQuicVersion> AllSupportedTlsVersions() { - std::vector<ParsedQuicVersion> tls_versions; - for (const ParsedQuicVersion& version : AllSupportedVersions()) { - if (version.handshake_protocol == PROTOCOL_TLS1_3) { - tls_versions.push_back(version); - } - } - return tls_versions; -} - -INSTANTIATE_TEST_SUITE_P(TlsHandshakerTests, - TlsHandshakerTest, - ::testing::ValuesIn(AllSupportedTlsVersions()), - ::testing::PrintToStringParamName()); - -TEST_P(TlsHandshakerTest, CryptoHandshake) { - EXPECT_FALSE(client_conn_->IsHandshakeComplete()); - EXPECT_FALSE(server_conn_->IsHandshakeComplete()); - - EXPECT_CALL(*client_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(*server_conn_, CloseConnection(_, _, _)).Times(0); - EXPECT_CALL(client_stream_->proof_handler(), OnProofVerifyDetailsAvailable); - client_stream_->CryptoConnect(); - ExchangeHandshakeMessages(client_stream_, server_stream_); - - ExpectHandshakeSuccessful(); -} - -} // namespace -} // namespace test -} // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc index 46e4b81704f..a8f926ea457 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.cc @@ -175,6 +175,10 @@ void TlsServerHandshaker::OnConnectionClosed(QuicErrorCode /*error*/, state_ = STATE_CONNECTION_CLOSED; } +ssl_early_data_reason_t TlsServerHandshaker::EarlyDataReason() const { + return TlsHandshaker::EarlyDataReason(); +} + bool TlsServerHandshaker::encryption_established() const { return encryption_established_; } @@ -287,6 +291,19 @@ bool TlsServerHandshaker::ProcessTransportParameters( // Notify QuicConnectionDebugVisitor. session()->connection()->OnTransportParametersReceived(client_params); + // Chrome clients before 86.0.4233.0 did not send the + // key_update_not_yet_supported transport parameter, but they did send a + // Google-internal transport parameter with identifier 0x4751. We treat + // reception of 0x4751 as having received key_update_not_yet_supported to + // ensure we do not use key updates with those older clients. + // TODO(dschinazi) remove this workaround once all of our QUIC+TLS Finch + // experiments have a min_version greater than 86.0.4233.0. + if (client_params.custom_parameters.find( + static_cast<TransportParameters::TransportParameterId>(0x4751)) != + client_params.custom_parameters.end()) { + client_params.key_update_not_yet_supported = true; + } + // When interoperating with non-Google implementations that do not send // the version extension, set it to what we expect. if (client_params.version == 0) { @@ -388,7 +405,10 @@ void TlsServerHandshaker::FinishHandshake() { return; } - QUIC_DLOG(INFO) << "Server: handshake finished"; + ssl_early_data_reason_t reason_code = EarlyDataReason(); + QUIC_DLOG(INFO) << "Server: handshake finished. Early data reason " + << reason_code << " (" + << CryptoUtils::EarlyDataReasonToString(reason_code) << ")"; state_ = STATE_HANDSHAKE_COMPLETE; one_rtt_keys_available_ = true; @@ -442,7 +462,6 @@ int TlsServerHandshaker::SessionTicketSeal(uint8_t* out, size_t* out_len, size_t max_out_len, quiche::QuicheStringPiece in) { - QUIC_CODE_COUNT(quic_tls_ticket_seal); DCHECK(proof_source_->GetTicketCrypter()); std::vector<uint8_t> ticket = proof_source_->GetTicketCrypter()->Encrypt(in); if (max_out_len < ticket.size()) { @@ -462,7 +481,6 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen( size_t* out_len, size_t max_out_len, quiche::QuicheStringPiece in) { - QUIC_CODE_COUNT(quic_tls_ticket_open); DCHECK(proof_source_->GetTicketCrypter()); if (!ticket_decryption_callback_) { @@ -496,7 +514,6 @@ ssl_ticket_aead_result_t TlsServerHandshaker::SessionTicketOpen( memcpy(out, decrypted_session_ticket_.data(), decrypted_session_ticket_.size()); *out_len = decrypted_session_ticket_.size(); - QUIC_RESTART_FLAG_COUNT(quic_enable_tls_resumption_v4); return ssl_ticket_aead_success; } @@ -532,19 +549,8 @@ int TlsServerHandshaker::SelectCertificate(int* out_alert) { return SSL_TLSEXT_ERR_ALERT_FATAL; } - std::vector<CRYPTO_BUFFER*> certs; - certs.resize(chain->certs.size()); - for (size_t i = 0; i < certs.size(); i++) { - certs[i] = CRYPTO_BUFFER_new( - reinterpret_cast<const uint8_t*>(chain->certs[i].data()), - chain->certs[i].length(), nullptr); - } - - tls_connection_.SetCertChain(certs); - - for (size_t i = 0; i < certs.size(); i++) { - CRYPTO_BUFFER_free(certs[i]); - } + CryptoBuffers cert_buffers = chain->ToCryptoBuffers(); + tls_connection_.SetCertChain(cert_buffers.value); std::string error_details; if (!ProcessTransportParameters(&error_details)) { diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h index b0212db06ad..063e5ca827b 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker.h @@ -56,6 +56,7 @@ class QUIC_EXPORT_PRIVATE TlsServerHandshaker const ProofSource::Details* ProofSourceDetails() const override; // From QuicCryptoServerStreamBase and TlsHandshaker + ssl_early_data_reason_t EarlyDataReason() const override; bool encryption_established() const override; bool one_rtt_keys_available() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() diff --git a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc index 05b7d686f67..295af9d6ee7 100644 --- a/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/tls_server_handshaker_test.cc @@ -42,13 +42,13 @@ namespace { const char kServerHostname[] = "test.example.com"; const uint16_t kServerPort = 443; -class TlsServerHandshakerTest : public QuicTest { +class TlsServerHandshakerTest : public QuicTestWithParam<ParsedQuicVersion> { public: TlsServerHandshakerTest() : server_compressed_certs_cache_( QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), - server_id_(kServerHostname, kServerPort, false) { - SetQuicRestartFlag(quic_enable_tls_resumption_v4, true); + server_id_(kServerHostname, kServerPort, false), + supported_versions_({GetParam()}) { SetQuicRestartFlag(quic_enable_zero_rtt_for_tls_v2, true); client_crypto_config_ = std::make_unique<QuicCryptoClientConfig>( crypto_test_utils::ProofVerifierForTesting(), @@ -223,21 +223,26 @@ class TlsServerHandshakerTest : public QuicTest { std::pair<size_t, size_t> moved_messages_counts_ = {0, 0}; // Which QUIC versions the client and server support. - ParsedQuicVersionVector supported_versions_ = AllSupportedVersionsWithTls(); + ParsedQuicVersionVector supported_versions_; }; -TEST_F(TlsServerHandshakerTest, NotInitiallyConected) { +INSTANTIATE_TEST_SUITE_P(TlsServerHandshakerTests, + TlsServerHandshakerTest, + ::testing::ValuesIn(AllSupportedVersionsWithTls()), + ::testing::PrintToStringParamName()); + +TEST_P(TlsServerHandshakerTest, NotInitiallyConected) { EXPECT_FALSE(server_stream()->encryption_established()); EXPECT_FALSE(server_stream()->one_rtt_keys_available()); } -TEST_F(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) { +TEST_P(TlsServerHandshakerTest, ConnectedAfterTlsHandshake) { CompleteCryptoHandshake(); EXPECT_EQ(PROTOCOL_TLS1_3, server_stream()->handshake_protocol()); ExpectHandshakeSuccessful(); } -TEST_F(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) { +TEST_P(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) { EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); // Enable FakeProofSource to capture call to ComputeTlsSignature and run it @@ -255,7 +260,7 @@ TEST_F(TlsServerHandshakerTest, HandshakeWithAsyncProofSource) { ExpectHandshakeSuccessful(); } -TEST_F(TlsServerHandshakerTest, CancelPendingProofSource) { +TEST_P(TlsServerHandshakerTest, CancelPendingProofSource) { EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); // Enable FakeProofSource to capture call to ComputeTlsSignature and run it @@ -271,7 +276,7 @@ TEST_F(TlsServerHandshakerTest, CancelPendingProofSource) { proof_source_->InvokePendingCallback(0); } -TEST_F(TlsServerHandshakerTest, ExtractSNI) { +TEST_P(TlsServerHandshakerTest, ExtractSNI) { CompleteCryptoHandshake(); ExpectHandshakeSuccessful(); @@ -279,7 +284,7 @@ TEST_F(TlsServerHandshakerTest, ExtractSNI) { "test.example.com"); } -TEST_F(TlsServerHandshakerTest, ConnectionClosedOnTlsError) { +TEST_P(TlsServerHandshakerTest, ConnectionClosedOnTlsError) { EXPECT_CALL(*server_connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, _, _)); @@ -297,11 +302,10 @@ TEST_F(TlsServerHandshakerTest, ConnectionClosedOnTlsError) { EXPECT_FALSE(server_stream()->one_rtt_keys_available()); } -TEST_F(TlsServerHandshakerTest, ClientSendingBadALPN) { +TEST_P(TlsServerHandshakerTest, ClientSendingBadALPN) { const std::string kTestBadClientAlpn = "bad-client-alpn"; EXPECT_CALL(*client_session_, GetAlpnsToOffer()) .WillOnce(Return(std::vector<std::string>({kTestBadClientAlpn}))); -#if BORINGSSL_API_VERSION > 10 EXPECT_CALL(*server_connection_, CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failure (ENCRYPTION_INITIAL) 120: " @@ -314,26 +318,9 @@ TEST_F(TlsServerHandshakerTest, ClientSendingBadALPN) { EXPECT_FALSE(client_stream()->encryption_established()); EXPECT_FALSE(server_stream()->one_rtt_keys_available()); EXPECT_FALSE(server_stream()->encryption_established()); -#else // BORINGSSL_API_VERSION <=10 - EXPECT_CALL( - *client_connection_, - CloseConnection(QUIC_HANDSHAKE_FAILED, "Server did not select ALPN", _)); - EXPECT_CALL(*server_connection_, - CloseConnection(QUIC_HANDSHAKE_FAILED, - "Server did not receive a known ALPN", _)); - - // Process two flights of handshake messages. - AdvanceHandshakeWithFakeClient(); - AdvanceHandshakeWithFakeClient(); - - EXPECT_FALSE(client_stream()->one_rtt_keys_available()); - EXPECT_TRUE(client_stream()->encryption_established()); - EXPECT_FALSE(server_stream()->one_rtt_keys_available()); - EXPECT_TRUE(server_stream()->encryption_established()); -#endif // BORINGSSL_API_VERSION } -TEST_F(TlsServerHandshakerTest, CustomALPNNegotiation) { +TEST_P(TlsServerHandshakerTest, CustomALPNNegotiation) { EXPECT_CALL(*client_connection_, CloseConnection(_, _, _)).Times(0); EXPECT_CALL(*server_connection_, CloseConnection(_, _, _)).Times(0); @@ -357,7 +344,7 @@ TEST_F(TlsServerHandshakerTest, CustomALPNNegotiation) { ExpectHandshakeSuccessful(); } -TEST_F(TlsServerHandshakerTest, RejectInvalidSNI) { +TEST_P(TlsServerHandshakerTest, RejectInvalidSNI) { server_id_ = QuicServerId("invalid!.example.com", kServerPort, false); InitializeFakeClient(); static_cast<TlsClientHandshaker*>( @@ -370,7 +357,7 @@ TEST_F(TlsServerHandshakerTest, RejectInvalidSNI) { EXPECT_FALSE(server_stream()->one_rtt_keys_available()); } -TEST_F(TlsServerHandshakerTest, Resumption) { +TEST_P(TlsServerHandshakerTest, Resumption) { // Do the first handshake InitializeFakeClient(); CompleteCryptoHandshake(); @@ -389,7 +376,7 @@ TEST_F(TlsServerHandshakerTest, Resumption) { EXPECT_TRUE(server_stream()->ResumptionAttempted()); } -TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) { +TEST_P(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) { // Do the first handshake InitializeFakeClient(); CompleteCryptoHandshake(); @@ -412,7 +399,7 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithAsyncDecryptCallback) { EXPECT_TRUE(server_stream()->ResumptionAttempted()); } -TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) { +TEST_P(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) { // Do the first handshake InitializeFakeClient(); CompleteCryptoHandshake(); @@ -429,7 +416,7 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingDecryptCallback) { EXPECT_TRUE(server_stream()->ResumptionAttempted()); } -TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) { +TEST_P(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) { // Do the first handshake InitializeFakeClient(); CompleteCryptoHandshake(); @@ -453,7 +440,7 @@ TEST_F(TlsServerHandshakerTest, ResumptionWithFailingAsyncDecryptCallback) { EXPECT_TRUE(server_stream()->ResumptionAttempted()); } -TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) { +TEST_P(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) { InitializeServerConfigWithFailingProofSource(); InitializeServer(); InitializeFakeClient(); @@ -465,7 +452,7 @@ TEST_F(TlsServerHandshakerTest, HandshakeFailsWithFailingProofSource) { EXPECT_EQ(moved_messages_counts_.second, 0u); } -TEST_F(TlsServerHandshakerTest, ZeroRttResumption) { +TEST_P(TlsServerHandshakerTest, ZeroRttResumption) { std::vector<uint8_t> application_state = {0, 1, 2, 3}; // Do the first handshake @@ -488,7 +475,7 @@ TEST_F(TlsServerHandshakerTest, ZeroRttResumption) { EXPECT_TRUE(server_stream()->IsZeroRtt()); } -TEST_F(TlsServerHandshakerTest, ZeroRttRejectOnApplicationStateChange) { +TEST_P(TlsServerHandshakerTest, ZeroRttRejectOnApplicationStateChange) { std::vector<uint8_t> original_application_state = {1, 2}; std::vector<uint8_t> new_application_state = {3, 4}; diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc index b017a84fcbf..7b2b32f894f 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.cc @@ -76,20 +76,18 @@ void UberReceivedPacketManager::MaybeUpdateAckTimeout( bool should_last_packet_instigate_acks, EncryptionLevel decrypted_packet_level, QuicPacketNumber last_received_packet_number, - QuicTime time_of_last_received_packet, QuicTime now, const RttStats* rtt_stats) { if (!supports_multiple_packet_number_spaces_) { received_packet_managers_[0].MaybeUpdateAckTimeout( - should_last_packet_instigate_acks, last_received_packet_number, - time_of_last_received_packet, now, rtt_stats); + should_last_packet_instigate_acks, last_received_packet_number, now, + rtt_stats); return; } received_packet_managers_[QuicUtils::GetPacketNumberSpace( decrypted_packet_level)] .MaybeUpdateAckTimeout(should_last_packet_instigate_acks, - last_received_packet_number, - time_of_last_received_packet, now, rtt_stats); + last_received_packet_number, now, rtt_stats); } void UberReceivedPacketManager::ResetAckStates( @@ -216,20 +214,20 @@ void UberReceivedPacketManager::set_max_ack_ranges(size_t max_ack_ranges) { } } -void UberReceivedPacketManager::set_max_ack_delay( - QuicTime::Delta max_ack_delay) { - if (!supports_multiple_packet_number_spaces_) { - received_packet_managers_[0].set_local_max_ack_delay(max_ack_delay); - return; - } - received_packet_managers_[APPLICATION_DATA].set_local_max_ack_delay( - max_ack_delay); -} - void UberReceivedPacketManager::set_save_timestamps(bool save_timestamps) { for (auto& received_packet_manager : received_packet_managers_) { received_packet_manager.set_save_timestamps(save_timestamps); } } +void UberReceivedPacketManager::OnAckFrequencyFrame( + const QuicAckFrequencyFrame& frame) { + if (!supports_multiple_packet_number_spaces_) { + QUIC_BUG << "Received AckFrequencyFrame when multiple packet number spaces " + "is not supported"; + return; + } + received_packet_managers_[APPLICATION_DATA].OnAckFrequencyFrame(frame); +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h index 9cfa247130c..17b5e268063 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h +++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager.h @@ -5,6 +5,7 @@ #ifndef QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_ #define QUICHE_QUIC_CORE_UBER_RECEIVED_PACKET_MANAGER_H_ +#include "net/third_party/quiche/src/quic/core/frames/quic_ack_frequency_frame.h" #include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h" namespace quic { @@ -46,7 +47,6 @@ class QUIC_EXPORT_PRIVATE UberReceivedPacketManager { void MaybeUpdateAckTimeout(bool should_last_packet_instigate_acks, EncryptionLevel decrypted_packet_level, QuicPacketNumber last_received_packet_number, - QuicTime time_of_last_received_packet, QuicTime now, const RttStats* rtt_stats); @@ -90,8 +90,7 @@ class QUIC_EXPORT_PRIVATE UberReceivedPacketManager { void set_max_ack_ranges(size_t max_ack_ranges); - // Set the max ack delay to use for application data. - void set_max_ack_delay(QuicTime::Delta max_ack_delay); + void OnAckFrequencyFrame(const QuicAckFrequencyFrame& frame); void set_save_timestamps(bool save_timestamps); diff --git a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc index 1b5a1966fc2..b7063d2fede 100644 --- a/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc +++ b/chromium/net/third_party/quiche/src/quic/core/uber_received_packet_manager_test.cc @@ -18,20 +18,6 @@ namespace test { class UberReceivedPacketManagerPeer { public: - static void SetAckMode(UberReceivedPacketManager* manager, AckMode ack_mode) { - for (auto& received_packet_manager : manager->received_packet_managers_) { - received_packet_manager.ack_mode_ = ack_mode; - } - } - - static void SetFastAckAfterQuiescence(UberReceivedPacketManager* manager, - bool fast_ack_after_quiescence) { - for (auto& received_packet_manager : manager->received_packet_managers_) { - received_packet_manager.fast_ack_after_quiescence_ = - fast_ack_after_quiescence; - } - } - static void SetAckDecimationDelay(UberReceivedPacketManager* manager, float ack_decimation_delay) { for (auto& received_packet_manager : manager->received_packet_managers_) { @@ -99,7 +85,7 @@ class UberReceivedPacketManagerTest : public QuicTest { manager_->MaybeUpdateAckTimeout( should_last_packet_instigate_acks, decrypted_packet_level, QuicPacketNumber(last_received_packet_number), clock_.ApproximateNow(), - clock_.ApproximateNow(), &rtt_stats_); + &rtt_stats_); } void CheckAckTimeout(QuicTime time) { @@ -315,8 +301,6 @@ TEST_F(UberReceivedPacketManagerTest, AckSentEveryNthPacket) { TEST_F(UberReceivedPacketManagerTest, AckDecimationReducesAcks) { EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), - ACK_DECIMATION_WITH_REORDERING); // Start ack decimation from 10th packet. manager_->set_min_received_before_ack_decimation(10); @@ -348,59 +332,8 @@ TEST_F(UberReceivedPacketManagerTest, AckDecimationReducesAcks) { CheckAckTimeout(clock_.ApproximateNow()); } -TEST_F(UberReceivedPacketManagerTest, SendDelayedAfterQuiescence) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(), - true); - // The beginning of the connection counts as quiescence. - QuicTime ack_time = - clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - - RecordPacketReceipt(1, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 1); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - CheckAckTimeout(clock_.ApproximateNow()); - - // Process another packet immediately after sending the ack and expect the - // ack timeout to be set delayed ack time in the future. - ack_time = clock_.ApproximateNow() + kDelayedAckTime; - RecordPacketReceipt(2, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 2); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(kDelayedAckTime); - CheckAckTimeout(clock_.ApproximateNow()); - - // Wait 1 second and enesure the ack timeout is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(3, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 3); - CheckAckTimeout(ack_time); -} - -TEST_F(UberReceivedPacketManagerTest, SendDelayedMaxAckDelay) { - EXPECT_FALSE(HasPendingAck()); - QuicTime::Delta max_ack_delay = QuicTime::Delta::FromMilliseconds(100); - manager_->set_max_ack_delay(max_ack_delay); - QuicTime ack_time = clock_.ApproximateNow() + max_ack_delay; - - RecordPacketReceipt(1, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 1); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(max_ack_delay); - CheckAckTimeout(clock_.ApproximateNow()); -} - TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) { EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION); // The ack time should be based on min_rtt * 1/4, since it's less than the // default delayed ack time. QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; @@ -431,76 +364,6 @@ TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimation) { } TEST_F(UberReceivedPacketManagerTest, - SendDelayedAckAckDecimationAfterQuiescence) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION); - UberReceivedPacketManagerPeer::SetFastAckAfterQuiescence(manager_.get(), - true); - // The beginning of the connection counts as quiescence. - QuicTime ack_time = - clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(1, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 1); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - CheckAckTimeout(clock_.ApproximateNow()); - - // Process another packet immedately after sending the ack and expect the - // ack timeout to be set delayed ack time in the future. - ack_time = clock_.ApproximateNow() + kDelayedAckTime; - RecordPacketReceipt(2, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 2); - CheckAckTimeout(ack_time); - // Simulate delayed ack alarm firing. - clock_.AdvanceTime(kDelayedAckTime); - CheckAckTimeout(clock_.ApproximateNow()); - - // Wait 1 second and enesure the ack timeout is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(3, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, 3); - CheckAckTimeout(ack_time); - // Process enough packets to get into ack decimation behavior. - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 4; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } - EXPECT_FALSE(HasPendingAck()); - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (uint64_t i = 1; i < 10; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); - } - CheckAckTimeout(clock_.ApproximateNow()); - - // Wait 1 second and enesure the ack timeout is set to 1ms in the future. - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); - RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); - CheckAckTimeout(ack_time); -} - -TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationUnlimitedAggregation) { EXPECT_FALSE(HasPendingAck()); QuicConfig config; @@ -543,7 +406,6 @@ TEST_F(UberReceivedPacketManagerTest, TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) { EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), ACK_DECIMATION); UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125); // The ack time should be based on min_rtt/8, since it's less than the @@ -575,190 +437,6 @@ TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationEighthRtt) { CheckAckTimeout(clock_.ApproximateNow()); } -TEST_F(UberReceivedPacketManagerTest, SendDelayedAckDecimationWithReordering) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), - ACK_DECIMATION_WITH_REORDERING); - - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; - // Process all the packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } - - // Receive one packet out of order and then the rest in order. - // The loop leaves a one packet gap between acks sent to simulate some loss. - for (int j = 0; j < 3; ++j) { - // Process packet 10 first and ensure the timeout is one eighth min_rtt. - RecordPacketReceipt(kFirstDecimatedPacket + 9 + (j * 11), - clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9 + (j * 11)); - ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (int i = 0; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i + (j * 11), - clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, - kFirstDecimatedPacket + i + (j * 11)); - } - CheckAckTimeout(clock_.ApproximateNow()); - } -} - -TEST_F(UberReceivedPacketManagerTest, - SendDelayedAckDecimationWithLargeReordering) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), - ACK_DECIMATION_WITH_REORDERING); - // The ack time should be based on min_rtt/4, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.25; - - // Process all the packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } - - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); - - RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); - ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (int i = 1; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); - } - CheckAckTimeout(clock_.ApproximateNow()); - - // The next packet received in order will cause an immediate ack, because it - // fills a hole. - RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); - CheckAckTimeout(clock_.ApproximateNow()); -} - -TEST_F(UberReceivedPacketManagerTest, - SendDelayedAckDecimationWithReorderingEighthRtt) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), - ACK_DECIMATION_WITH_REORDERING); - UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125); - // The ack time should be based on min_rtt/8, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; - - // Process all the packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } - - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); - - // Process packet 10 first and ensure the timeout is one eighth min_rtt. - RecordPacketReceipt(kFirstDecimatedPacket + 9, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 9); - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (int i = 1; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck + i, kFirstDecimatedPacket); - } - CheckAckTimeout(clock_.ApproximateNow()); -} - -TEST_F(UberReceivedPacketManagerTest, - SendDelayedAckDecimationWithLargeReorderingEighthRtt) { - if (GetQuicReloadableFlag(quic_remove_unused_ack_options)) { - return; - } - EXPECT_FALSE(HasPendingAck()); - UberReceivedPacketManagerPeer::SetAckMode(manager_.get(), - ACK_DECIMATION_WITH_REORDERING); - UberReceivedPacketManagerPeer::SetAckDecimationDelay(manager_.get(), 0.125); - - // The ack time should be based on min_rtt/8, since it's less than the - // default delayed ack time. - QuicTime ack_time = clock_.ApproximateNow() + kMinRttMs * 0.125; - // Process all the packets in order so there aren't missing packets. - uint64_t kFirstDecimatedPacket = 101; - for (uint64_t i = 1; i < kFirstDecimatedPacket; ++i) { - RecordPacketReceipt(i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, i); - if (i % 2 == 0) { - // Ack every 2 packets by default. - CheckAckTimeout(clock_.ApproximateNow()); - } else { - CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime); - } - } - - RecordPacketReceipt(kFirstDecimatedPacket, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket); - CheckAckTimeout(ack_time); - - RecordPacketReceipt(kFirstDecimatedPacket + 19, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 19); - CheckAckTimeout(ack_time); - - // The 10th received packet causes an ack to be sent. - for (int i = 1; i < 9; ++i) { - RecordPacketReceipt(kFirstDecimatedPacket + i, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + i); - } - CheckAckTimeout(clock_.ApproximateNow()); - - // The next packet received in order will cause an immediate ack, because it - // fills a hole. - RecordPacketReceipt(kFirstDecimatedPacket + 10, clock_.ApproximateNow()); - MaybeUpdateAckTimeout(kInstigateAck, kFirstDecimatedPacket + 10); - CheckAckTimeout(clock_.ApproximateNow()); -} - TEST_F(UberReceivedPacketManagerTest, DontWaitForPacketsBeforeMultiplePacketNumberSpaces) { manager_->EnableMultiplePacketNumberSpacesSupport(); diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_testvalue.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_testvalue.h new file mode 100644 index 00000000000..0df0c4050be --- /dev/null +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_testvalue.h @@ -0,0 +1,25 @@ +// Copyright 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. + +#ifndef QUICHE_QUIC_PLATFORM_API_QUIC_TESTVALUE_H_ +#define QUICHE_QUIC_PLATFORM_API_QUIC_TESTVALUE_H_ + +#include "net/quic/platform/impl/quic_testvalue_impl.h" +#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" + +namespace quic { + +// Interface allowing injection of test-specific code in production codepaths. +// |label| is an arbitrary value identifying the location, and |var| is a +// pointer to the value to be modified. +// +// Note that this method does nothing in Chromium. +template <class T> +void AdjustTestValue(quiche::QuicheStringPiece label, T* var) { + AdjustTestValueImpl(label, var); +} + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_API_QUIC_TESTVALUE_H_ diff --git a/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h b/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h index 2b1f9c3fbc5..10307efc298 100644 --- a/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h +++ b/chromium/net/third_party/quiche/src/quic/platform/api/quic_udp_socket_platform_api.h @@ -20,6 +20,10 @@ inline bool GetGooglePacketHeadersFromControlMessage( packet_headers_len); } +inline void SetGoogleSocketOptions(int fd) { + SetGoogleSocketOptionsImpl(fd); +} + } // namespace quic #endif // QUICHE_QUIC_PLATFORM_API_QUIC_UDP_SOCKET_PLATFORM_API_H_ diff --git a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc index 9c2f1382887..fe855765940 100644 --- a/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session_test.cc @@ -109,15 +109,9 @@ TEST_F(QuicTransportClientSessionTest, SuccessfulConnection) { EXPECT_TRUE(session_->IsSessionReady()); QuicStream* client_indication_stream; - if (session_->remove_zombie_streams()) { - client_indication_stream = - QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()] - .get(); - } else { - client_indication_stream = QuicSessionPeer::zombie_streams( - session_.get())[ClientIndicationStream()] - .get(); - } + client_indication_stream = + QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()] + .get(); ASSERT_TRUE(client_indication_stream != nullptr); const std::string client_indication = DataInStream(client_indication_stream); const std::string expected_client_indication{ @@ -141,15 +135,9 @@ TEST_F(QuicTransportClientSessionTest, SuccessfulConnectionWithPath) { EXPECT_TRUE(session_->IsSessionReady()); QuicStream* client_indication_stream; - if (session_->remove_zombie_streams()) { - client_indication_stream = - QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()] - .get(); - } else { - client_indication_stream = QuicSessionPeer::zombie_streams( - session_.get())[ClientIndicationStream()] - .get(); - } + client_indication_stream = + QuicSessionPeer::stream_map(session_.get())[ClientIndicationStream()] + .get(); ASSERT_TRUE(client_indication_stream != nullptr); const std::string client_indication = DataInStream(client_indication_stream); const std::string expected_client_indication{ diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc index 6f9c8c6e837..1949df17a85 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.cc @@ -210,26 +210,6 @@ void QuicConnectionPeer::ReInitializeMtuDiscoverer( } // static -void QuicConnectionPeer::SetAckMode(QuicConnection* connection, - AckMode ack_mode) { - for (auto& received_packet_manager : - connection->uber_received_packet_manager_.received_packet_managers_) { - received_packet_manager.ack_mode_ = ack_mode; - } -} - -// static -void QuicConnectionPeer::SetFastAckAfterQuiescence( - QuicConnection* connection, - bool fast_ack_after_quiescence) { - for (auto& received_packet_manager : - connection->uber_received_packet_manager_.received_packet_managers_) { - received_packet_manager.fast_ack_after_quiescence_ = - fast_ack_after_quiescence; - } -} - -// static void QuicConnectionPeer::SetAckDecimationDelay(QuicConnection* connection, float ack_decimation_delay) { for (auto& received_packet_manager : @@ -392,5 +372,12 @@ size_t QuicConnectionPeer::NumUndecryptablePackets(QuicConnection* connection) { return connection->undecryptable_packets_.size(); } +// static +const QuicCircularDeque<std::pair<QuicPathFrameBuffer, QuicSocketAddress>>& +QuicConnectionPeer::pending_path_challenge_payloads( + QuicConnection* connection) { + return connection->pending_path_challenge_payloads_; +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h index 01d16f2ca68..b470653b793 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h @@ -102,9 +102,6 @@ class QuicConnectionPeer { QuicConnection* connection, QuicPacketCount packets_between_probes_base, QuicPacketNumber next_probe_at); - static void SetAckMode(QuicConnection* connection, AckMode ack_mode); - static void SetFastAckAfterQuiescence(QuicConnection* connection, - bool fast_ack_after_quiescence); static void SetAckDecimationDelay(QuicConnection* connection, float ack_decimation_delay); static bool HasRetransmittableFrames(QuicConnection* connection, @@ -156,6 +153,10 @@ class QuicConnectionPeer { const QuicConnectionId& server_connection_id); static size_t NumUndecryptablePackets(QuicConnection* connection); + + static const QuicCircularDeque< + std::pair<QuicPathFrameBuffer, QuicSocketAddress>>& + pending_path_challenge_payloads(QuicConnection* connection); }; } // namespace test diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc index 151575a0db0..f94620bd5d5 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_packet_creator_peer.cc @@ -111,7 +111,9 @@ SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames( bool success = creator->AddFrame(frame, NOT_RETRANSMISSION); DCHECK(success); } - creator->SerializePacket(QuicOwnedPacketBuffer(buffer, nullptr), buffer_len); + const bool success = creator->SerializePacket( + QuicOwnedPacketBuffer(buffer, nullptr), buffer_len); + DCHECK(success); SerializedPacket packet = std::move(creator->packet_); // The caller takes ownership of the QuicEncryptedPacket. creator->packet_.encrypted_buffer = nullptr; diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc index 68236917921..05d74d75701 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.cc @@ -137,12 +137,6 @@ const QuicSession::ClosedStreams& QuicSessionPeer::closed_streams( } // static -QuicSession::ZombieStreamMap& QuicSessionPeer::zombie_streams( - QuicSession* session) { - return session->zombie_streams_; -} - -// static void QuicSessionPeer::ActivateStream(QuicSession* session, std::unique_ptr<QuicStream> stream) { return session->ActivateStream(std::move(stream)); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h index 1366ddbdbec..ffd6c6f300f 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_session_peer.h @@ -58,7 +58,6 @@ class QuicSessionPeer { GetLocallyClosedStreamsHighestOffset(QuicSession* session); static QuicSession::StreamMap& stream_map(QuicSession* session); static const QuicSession::ClosedStreams& closed_streams(QuicSession* session); - static QuicSession::ZombieStreamMap& zombie_streams(QuicSession* session); static void ActivateStream(QuicSession* session, std::unique_ptr<QuicStream> stream); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc index 85a86b70bca..f311079a350 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_server.cc @@ -252,7 +252,7 @@ void ImmediateGoAwaySession::OnNewEncryptionKeyAvailable( QuicSimpleServerSession::OnNewEncryptionKeyAvailable(level, std::move(encrypter)); if (VersionUsesHttp3(transport_version())) { - if (IsEncryptionEstablished() && !http3_goaway_sent()) { + if (IsEncryptionEstablished() && !goaway_sent()) { SendHttp3GoAway(); } } diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc index 7ee037a38a6..ed7dc7592f3 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.cc @@ -14,6 +14,7 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_utils.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" @@ -27,6 +28,7 @@ #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_error_code_wrappers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" @@ -583,7 +585,7 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket packet) { OnPacketSent(packet.encryption_level, packet.transmission_type); QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent( &packet, clock_.ApproximateNow(), NOT_RETRANSMISSION, - HAS_RETRANSMITTABLE_DATA); + HAS_RETRANSMITTABLE_DATA, true); } MockQuicSession::MockQuicSession(QuicConnection* connection) @@ -643,6 +645,10 @@ MockQuicCryptoStream::MockQuicCryptoStream(QuicSession* session) MockQuicCryptoStream::~MockQuicCryptoStream() {} +ssl_early_data_reason_t MockQuicCryptoStream::EarlyDataReason() const { + return ssl_early_data_unknown; +} + bool MockQuicCryptoStream::encryption_established() const { return false; } @@ -1309,5 +1315,207 @@ QuicMemSlice MemSliceFromString(quiche::QuicheStringPiece data) { return QuicMemSlice(std::move(buffer), data.size()); } +bool TaggingEncrypter::EncryptPacket( + uint64_t /*packet_number*/, + quiche::QuicheStringPiece /*associated_data*/, + quiche::QuicheStringPiece plaintext, + char* output, + size_t* output_length, + size_t max_output_length) { + const size_t len = plaintext.size() + kTagSize; + if (max_output_length < len) { + return false; + } + // Memmove is safe for inplace encryption. + memmove(output, plaintext.data(), plaintext.size()); + output += plaintext.size(); + memset(output, tag_, kTagSize); + *output_length = len; + return true; +} + +bool TaggingDecrypter::DecryptPacket( + uint64_t /*packet_number*/, + quiche::QuicheStringPiece /*associated_data*/, + quiche::QuicheStringPiece ciphertext, + char* output, + size_t* output_length, + size_t /*max_output_length*/) { + if (ciphertext.size() < kTagSize) { + return false; + } + if (!CheckTag(ciphertext, GetTag(ciphertext))) { + return false; + } + *output_length = ciphertext.size() - kTagSize; + memcpy(output, ciphertext.data(), *output_length); + return true; +} + +bool TaggingDecrypter::CheckTag(quiche::QuicheStringPiece ciphertext, + uint8_t tag) { + for (size_t i = ciphertext.size() - kTagSize; i < ciphertext.size(); i++) { + if (ciphertext.data()[i] != tag) { + return false; + } + } + + return true; +} + +TestPacketWriter::TestPacketWriter(ParsedQuicVersion version, + MockClock* clock, + Perspective perspective) + : version_(version), + framer_(SupportedVersions(version_), + QuicUtils::InvertPerspective(perspective)), + clock_(clock) { + QuicFramerPeer::SetLastSerializedServerConnectionId(framer_.framer(), + TestConnectionId()); + framer_.framer()->SetInitialObfuscators(TestConnectionId()); + + for (int i = 0; i < 128; ++i) { + PacketBuffer* p = new PacketBuffer(); + packet_buffer_pool_.push_back(p); + packet_buffer_pool_index_[p->buffer] = p; + packet_buffer_free_list_.push_back(p); + } +} + +TestPacketWriter::~TestPacketWriter() { + EXPECT_EQ(packet_buffer_pool_.size(), packet_buffer_free_list_.size()) + << packet_buffer_pool_.size() - packet_buffer_free_list_.size() + << " out of " << packet_buffer_pool_.size() + << " packet buffers have been leaked."; + for (auto p : packet_buffer_pool_) { + delete p; + } +} + +WriteResult TestPacketWriter::WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& /*self_address*/, + const QuicSocketAddress& peer_address, + PerPacketOptions* /*options*/) { + last_write_peer_address_ = peer_address; + // If the buffer is allocated from the pool, return it back to the pool. + // Note the buffer content doesn't change. + if (packet_buffer_pool_index_.find(const_cast<char*>(buffer)) != + packet_buffer_pool_index_.end()) { + FreePacketBuffer(buffer); + } + + QuicEncryptedPacket packet(buffer, buf_len); + ++packets_write_attempts_; + + if (packet.length() >= sizeof(final_bytes_of_last_packet_)) { + final_bytes_of_previous_packet_ = final_bytes_of_last_packet_; + memcpy(&final_bytes_of_last_packet_, packet.data() + packet.length() - 4, + sizeof(final_bytes_of_last_packet_)); + } + + if (use_tagging_decrypter_) { + if (framer_.framer()->version().KnowsWhichDecrypterToUse()) { + framer_.framer()->InstallDecrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingDecrypter>()); + framer_.framer()->InstallDecrypter(ENCRYPTION_HANDSHAKE, + std::make_unique<TaggingDecrypter>()); + framer_.framer()->InstallDecrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<TaggingDecrypter>()); + framer_.framer()->InstallDecrypter(ENCRYPTION_FORWARD_SECURE, + std::make_unique<TaggingDecrypter>()); + } else { + framer_.framer()->SetDecrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingDecrypter>()); + } + } else if (framer_.framer()->version().KnowsWhichDecrypterToUse()) { + framer_.framer()->InstallDecrypter( + ENCRYPTION_HANDSHAKE, + std::make_unique<NullDecrypter>(framer_.framer()->perspective())); + framer_.framer()->InstallDecrypter( + ENCRYPTION_ZERO_RTT, + std::make_unique<NullDecrypter>(framer_.framer()->perspective())); + framer_.framer()->InstallDecrypter( + ENCRYPTION_FORWARD_SECURE, + std::make_unique<NullDecrypter>(framer_.framer()->perspective())); + } + EXPECT_TRUE(framer_.ProcessPacket(packet)) + << framer_.framer()->detailed_error() << " perspective " + << framer_.framer()->perspective(); + if (block_on_next_write_) { + write_blocked_ = true; + block_on_next_write_ = false; + } + if (next_packet_too_large_) { + next_packet_too_large_ = false; + return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE); + } + if (always_get_packet_too_large_) { + return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE); + } + if (IsWriteBlocked()) { + return WriteResult(is_write_blocked_data_buffered_ + ? WRITE_STATUS_BLOCKED_DATA_BUFFERED + : WRITE_STATUS_BLOCKED, + 0); + } + + if (ShouldWriteFail()) { + return WriteResult(WRITE_STATUS_ERROR, 0); + } + + last_packet_size_ = packet.length(); + last_packet_header_ = framer_.header(); + if (!framer_.connection_close_frames().empty()) { + ++connection_close_packets_; + } + if (!write_pause_time_delta_.IsZero()) { + clock_->AdvanceTime(write_pause_time_delta_); + } + if (is_batch_mode_) { + bytes_buffered_ += last_packet_size_; + return WriteResult(WRITE_STATUS_OK, 0); + } + return WriteResult(WRITE_STATUS_OK, last_packet_size_); +} + +QuicPacketBuffer TestPacketWriter::GetNextWriteLocation( + const QuicIpAddress& /*self_address*/, + const QuicSocketAddress& /*peer_address*/) { + return {AllocPacketBuffer(), [this](const char* p) { FreePacketBuffer(p); }}; +} + +WriteResult TestPacketWriter::Flush() { + flush_attempts_++; + if (block_on_next_flush_) { + block_on_next_flush_ = false; + SetWriteBlocked(); + return WriteResult(WRITE_STATUS_BLOCKED, /*errno*/ -1); + } + if (write_should_fail_) { + return WriteResult(WRITE_STATUS_ERROR, /*errno*/ -1); + } + int bytes_flushed = bytes_buffered_; + bytes_buffered_ = 0; + return WriteResult(WRITE_STATUS_OK, bytes_flushed); +} + +char* TestPacketWriter::AllocPacketBuffer() { + PacketBuffer* p = packet_buffer_free_list_.front(); + EXPECT_FALSE(p->in_use); + p->in_use = true; + packet_buffer_free_list_.pop_front(); + return p->buffer; +} + +void TestPacketWriter::FreePacketBuffer(const char* buffer) { + auto iter = packet_buffer_pool_index_.find(const_cast<char*>(buffer)); + ASSERT_TRUE(iter != packet_buffer_pool_index_.end()); + PacketBuffer* p = iter->second; + ASSERT_TRUE(p->in_use); + p->in_use = false; + packet_buffer_free_list_.push_back(p); +} + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h index aac4a2ca212..457663e8817 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/quic_test_utils.h @@ -27,11 +27,14 @@ #include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" #include "net/third_party/quiche/src/quic/test_tools/mock_quic_session_visitor.h" #include "net/third_party/quiche/src/quic/test_tools/mock_random.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_framer_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/simple_quic_framer.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" @@ -529,6 +532,7 @@ class MockQuicConnectionVisitor : public QuicConnectionVisitorInterface { MOCK_METHOD(void, OnForwardProgressMadeAfterPathDegrading, (), (override)); MOCK_METHOD(bool, WillingAndAbleToWrite, (), (const, override)); MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override)); + MOCK_METHOD(std::string, GetStreamsInfoForLogging, (), (const, override)); MOCK_METHOD(void, OnSuccessfulVersionNegotiation, (const ParsedQuicVersion& version), @@ -813,7 +817,7 @@ class MockQuicSession : public QuicSession { MOCK_METHOD(bool, ShouldKeepConnectionAlive, (), (const, override)); MOCK_METHOD(void, SendStopSending, - (uint16_t code, QuicStreamId stream_id), + (QuicRstStreamErrorCode code, QuicStreamId stream_id), (override)); MOCK_METHOD(std::vector<std::string>, GetAlpnsToOffer, (), (const, override)); MOCK_METHOD(std::vector<quiche::QuicheStringPiece>::const_iterator, @@ -850,6 +854,7 @@ class MockQuicCryptoStream : public QuicCryptoStream { ~MockQuicCryptoStream() override; + ssl_early_data_reason_t EarlyDataReason() const override; bool encryption_established() const override; bool one_rtt_keys_available() const override; const QuicCryptoNegotiatedParameters& crypto_negotiated_params() @@ -1365,12 +1370,26 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { MockQuicConnectionDebugVisitor(); ~MockQuicConnectionDebugVisitor() override; + // TODO(wub): Delete when deprecating + // --quic_give_sent_packet_to_debug_visitor_after_sent. MOCK_METHOD(void, OnPacketSent, (const SerializedPacket&, TransmissionType, QuicTime), (override)); MOCK_METHOD(void, + OnPacketSent, + (QuicPacketNumber, + QuicPacketLength, + bool, + TransmissionType, + EncryptionLevel, + const QuicFrames&, + const QuicFrames&, + QuicTime), + (override)); + + MOCK_METHOD(void, OnCoalescedPacketSent, (const QuicCoalescedPacket&, size_t), (override)); @@ -1464,6 +1483,9 @@ class MockQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { OnTransportParametersReceived, (const TransportParameters&), (override)); + + MOCK_METHOD(void, OnZeroRttRejected, (int), (override)); + MOCK_METHOD(void, OnZeroRttPacketAcked, (), (override)); }; class MockReceivedPacketManager : public QuicReceivedPacketManager { @@ -1722,6 +1744,358 @@ MATCHER(IsQuicStreamNoError, return arg == QUIC_STREAM_NO_ERROR; } +// TaggingEncrypter appends kTagSize bytes of |tag| to the end of each message. +class TaggingEncrypter : public QuicEncrypter { + public: + explicit TaggingEncrypter(uint8_t tag) : tag_(tag) {} + TaggingEncrypter(const TaggingEncrypter&) = delete; + TaggingEncrypter& operator=(const TaggingEncrypter&) = delete; + + ~TaggingEncrypter() override {} + + // QuicEncrypter interface. + bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; } + + bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override { + return true; + } + + bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; } + + bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override { + return true; + } + + bool EncryptPacket(uint64_t packet_number, + quiche::QuicheStringPiece associated_data, + quiche::QuicheStringPiece plaintext, + char* output, + size_t* output_length, + size_t max_output_length) override; + + std::string GenerateHeaderProtectionMask( + quiche::QuicheStringPiece /*sample*/) override { + return std::string(5, 0); + } + + size_t GetKeySize() const override { return 0; } + size_t GetNoncePrefixSize() const override { return 0; } + size_t GetIVSize() const override { return 0; } + + size_t GetMaxPlaintextSize(size_t ciphertext_size) const override { + return ciphertext_size - kTagSize; + } + + size_t GetCiphertextSize(size_t plaintext_size) const override { + return plaintext_size + kTagSize; + } + + quiche::QuicheStringPiece GetKey() const override { + return quiche::QuicheStringPiece(); + } + + quiche::QuicheStringPiece GetNoncePrefix() const override { + return quiche::QuicheStringPiece(); + } + + private: + enum { + kTagSize = 12, + }; + + const uint8_t tag_; +}; + +// TaggingDecrypter ensures that the final kTagSize bytes of the message all +// have the same value and then removes them. +class TaggingDecrypter : public QuicDecrypter { + public: + ~TaggingDecrypter() override {} + + // QuicDecrypter interface + bool SetKey(quiche::QuicheStringPiece /*key*/) override { return true; } + + bool SetNoncePrefix(quiche::QuicheStringPiece /*nonce_prefix*/) override { + return true; + } + + bool SetIV(quiche::QuicheStringPiece /*iv*/) override { return true; } + + bool SetHeaderProtectionKey(quiche::QuicheStringPiece /*key*/) override { + return true; + } + + bool SetPreliminaryKey(quiche::QuicheStringPiece /*key*/) override { + QUIC_BUG << "should not be called"; + return false; + } + + bool SetDiversificationNonce(const DiversificationNonce& /*key*/) override { + return true; + } + + bool DecryptPacket(uint64_t packet_number, + quiche::QuicheStringPiece associated_data, + quiche::QuicheStringPiece ciphertext, + char* output, + size_t* output_length, + size_t max_output_length) override; + + std::string GenerateHeaderProtectionMask( + QuicDataReader* /*sample_reader*/) override { + return std::string(5, 0); + } + + size_t GetKeySize() const override { return 0; } + size_t GetNoncePrefixSize() const override { return 0; } + size_t GetIVSize() const override { return 0; } + quiche::QuicheStringPiece GetKey() const override { + return quiche::QuicheStringPiece(); + } + quiche::QuicheStringPiece GetNoncePrefix() const override { + return quiche::QuicheStringPiece(); + } + // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. + uint32_t cipher_id() const override { return 0xFFFFFFF0; } + + protected: + virtual uint8_t GetTag(quiche::QuicheStringPiece ciphertext) { + return ciphertext.data()[ciphertext.size() - 1]; + } + + private: + enum { + kTagSize = 12, + }; + + bool CheckTag(quiche::QuicheStringPiece ciphertext, uint8_t tag); +}; + +class TestPacketWriter : public QuicPacketWriter { + struct PacketBuffer { + QUIC_CACHELINE_ALIGNED char buffer[1500]; + bool in_use = false; + }; + + public: + TestPacketWriter(ParsedQuicVersion version, + MockClock* clock, + Perspective perspective); + + TestPacketWriter(const TestPacketWriter&) = delete; + TestPacketWriter& operator=(const TestPacketWriter&) = delete; + + ~TestPacketWriter() override; + + // QuicPacketWriter interface + WriteResult WritePacket(const char* buffer, + size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) override; + + bool ShouldWriteFail() { return write_should_fail_; } + + bool IsWriteBlocked() const override { return write_blocked_; } + + void SetWriteBlocked() { write_blocked_ = true; } + + void SetWritable() override { write_blocked_ = false; } + + void SetShouldWriteFail() { write_should_fail_ = true; } + + QuicByteCount GetMaxPacketSize( + const QuicSocketAddress& /*peer_address*/) const override { + return max_packet_size_; + } + + bool SupportsReleaseTime() const override { return supports_release_time_; } + + bool IsBatchMode() const override { return is_batch_mode_; } + + QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& /*self_address*/, + const QuicSocketAddress& /*peer_address*/) override; + + WriteResult Flush() override; + + void BlockOnNextFlush() { block_on_next_flush_ = true; } + + void BlockOnNextWrite() { block_on_next_write_ = true; } + + void SimulateNextPacketTooLarge() { next_packet_too_large_ = true; } + + void AlwaysGetPacketTooLarge() { always_get_packet_too_large_ = true; } + + // Sets the amount of time that the writer should before the actual write. + void SetWritePauseTimeDelta(QuicTime::Delta delta) { + write_pause_time_delta_ = delta; + } + + void SetBatchMode(bool new_value) { is_batch_mode_ = new_value; } + + const QuicPacketHeader& header() { return framer_.header(); } + + size_t frame_count() const { return framer_.num_frames(); } + + const std::vector<QuicAckFrame>& ack_frames() const { + return framer_.ack_frames(); + } + + const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const { + return framer_.stop_waiting_frames(); + } + + const std::vector<QuicConnectionCloseFrame>& connection_close_frames() const { + return framer_.connection_close_frames(); + } + + const std::vector<QuicRstStreamFrame>& rst_stream_frames() const { + return framer_.rst_stream_frames(); + } + + const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const { + return framer_.stream_frames(); + } + + const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const { + return framer_.crypto_frames(); + } + + const std::vector<QuicPingFrame>& ping_frames() const { + return framer_.ping_frames(); + } + + const std::vector<QuicMessageFrame>& message_frames() const { + return framer_.message_frames(); + } + + const std::vector<QuicWindowUpdateFrame>& window_update_frames() const { + return framer_.window_update_frames(); + } + + const std::vector<QuicPaddingFrame>& padding_frames() const { + return framer_.padding_frames(); + } + + const std::vector<QuicPathChallengeFrame>& path_challenge_frames() const { + return framer_.path_challenge_frames(); + } + + const std::vector<QuicPathResponseFrame>& path_response_frames() const { + return framer_.path_response_frames(); + } + + const QuicEncryptedPacket* coalesced_packet() const { + return framer_.coalesced_packet(); + } + + size_t last_packet_size() { return last_packet_size_; } + + const QuicPacketHeader& last_packet_header() const { + return last_packet_header_; + } + + const QuicVersionNegotiationPacket* version_negotiation_packet() { + return framer_.version_negotiation_packet(); + } + + void set_is_write_blocked_data_buffered(bool buffered) { + is_write_blocked_data_buffered_ = buffered; + } + + void set_perspective(Perspective perspective) { + // We invert perspective here, because the framer needs to parse packets + // we send. + QuicFramerPeer::SetPerspective(framer_.framer(), + QuicUtils::InvertPerspective(perspective)); + framer_.framer()->SetInitialObfuscators(TestConnectionId()); + } + + // final_bytes_of_last_packet_ returns the last four bytes of the previous + // packet as a little-endian, uint32_t. This is intended to be used with a + // TaggingEncrypter so that tests can determine which encrypter was used for + // a given packet. + uint32_t final_bytes_of_last_packet() { return final_bytes_of_last_packet_; } + + // Returns the final bytes of the second to last packet. + uint32_t final_bytes_of_previous_packet() { + return final_bytes_of_previous_packet_; + } + + void use_tagging_decrypter() { use_tagging_decrypter_ = true; } + + uint32_t packets_write_attempts() const { return packets_write_attempts_; } + + uint32_t flush_attempts() const { return flush_attempts_; } + + uint32_t connection_close_packets() const { + return connection_close_packets_; + } + + void Reset() { framer_.Reset(); } + + void SetSupportedVersions(const ParsedQuicVersionVector& versions) { + framer_.SetSupportedVersions(versions); + } + + void set_max_packet_size(QuicByteCount max_packet_size) { + max_packet_size_ = max_packet_size; + } + + void set_supports_release_time(bool supports_release_time) { + supports_release_time_ = supports_release_time; + } + + SimpleQuicFramer* framer() { return &framer_; } + + const QuicSocketAddress& last_write_peer_address() const { + return last_write_peer_address_; + } + + private: + char* AllocPacketBuffer(); + + void FreePacketBuffer(const char* buffer); + + ParsedQuicVersion version_; + SimpleQuicFramer framer_; + size_t last_packet_size_ = 0; + QuicPacketHeader last_packet_header_; + bool write_blocked_ = false; + bool write_should_fail_ = false; + bool block_on_next_flush_ = false; + bool block_on_next_write_ = false; + bool next_packet_too_large_ = false; + bool always_get_packet_too_large_ = false; + bool is_write_blocked_data_buffered_ = false; + bool is_batch_mode_ = false; + // Number of times Flush() was called. + uint32_t flush_attempts_ = 0; + // (Batch mode only) Number of bytes buffered in writer. It is used as the + // return value of a successful Flush(). + uint32_t bytes_buffered_ = 0; + uint32_t final_bytes_of_last_packet_ = 0; + uint32_t final_bytes_of_previous_packet_ = 0; + bool use_tagging_decrypter_ = false; + uint32_t packets_write_attempts_ = 0; + uint32_t connection_close_packets_ = 0; + MockClock* clock_ = nullptr; + // If non-zero, the clock will pause during WritePacket for this amount of + // time. + QuicTime::Delta write_pause_time_delta_ = QuicTime::Delta::Zero(); + QuicByteCount max_packet_size_ = kMaxOutgoingPacketSize; + bool supports_release_time_ = false; + // Used to verify writer-allocated packet buffers are properly released. + std::vector<PacketBuffer*> packet_buffer_pool_; + // Buffer address => Address of the owning PacketBuffer. + QuicHashMap<char*, PacketBuffer*> packet_buffer_pool_index_; + // Indices in packet_buffer_pool_ that are not allocated. + std::list<PacketBuffer*> packet_buffer_free_list_; + // The peer address passed into WritePacket(). + QuicSocketAddress last_write_peer_address_; +}; + } // namespace test } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc index b72a9522036..bc65f448c2e 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simple_session_notifier_test.cc @@ -265,9 +265,9 @@ TEST_F(SimpleSessionNotifierTest, OnCanWriteCryptoFrames) { producer.SaveCryptoData(ENCRYPTION_INITIAL, 500, crypto_data2); notifier_.WriteCryptoData(ENCRYPTION_INITIAL, 1024, 0); // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT. - connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, std::make_unique<NullEncrypter>( Perspective::IS_CLIENT)); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); EXPECT_CALL(connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1024, 0)) .WillOnce(Invoke(&connection_, &MockQuicConnection::QuicConnection_SendCryptoData)); diff --git a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h index cb3c38644f7..ff9b680f58f 100644 --- a/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h +++ b/chromium/net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h @@ -59,6 +59,7 @@ class QuicEndpoint : public QuicEndpointBase, bool WillingAndAbleToWrite() const override; bool ShouldKeepConnectionAlive() const override; + std::string GetStreamsInfoForLogging() const override { return ""; } void OnWindowUpdateFrame(const QuicWindowUpdateFrame& /*frame*/) override {} void OnBlockedFrame(const QuicBlockedFrame& /*frame*/) override {} void OnRstStream(const QuicRstStreamFrame& /*frame*/) override {} diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h index 6537987a381..af6cf84ee0c 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h @@ -40,9 +40,6 @@ class QuicBackendResponse { INCOMPLETE_RESPONSE, // The server will act as if there is a non-empty // trailer but it will not be sent, as a result, FIN // will not be sent too. - STOP_SENDING, // Acts like INCOMPLETE_RESPONSE in that the entire - // response is not sent. After sending what is sent, - // the server will send a STOP_SENDING. GENERATE_BYTES // Sends a response with a length equal to the number // of bytes in the URL path. }; @@ -73,15 +70,12 @@ class QuicBackendResponse { void set_body(quiche::QuicheStringPiece body) { body_.assign(body.data(), body.size()); } - uint16_t stop_sending_code() const { return stop_sending_code_; } - void set_stop_sending_code(uint16_t code) { stop_sending_code_ = code; } private: SpecialResponseType response_type_; spdy::SpdyHeaderBlock headers_; spdy::SpdyHeaderBlock trailers_; std::string body_; - uint16_t stop_sending_code_; }; } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc index a9a932071f7..16499d2f8aa 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc @@ -32,9 +32,12 @@ namespace quic { namespace tools { -QuicSocketAddress LookupAddress(std::string host, std::string port) { +QuicSocketAddress LookupAddress(int address_family_for_lookup, + std::string host, + std::string port) { addrinfo hint; memset(&hint, 0, sizeof(hint)); + hint.ai_family = address_family_for_lookup; hint.ai_protocol = IPPROTO_UDP; addrinfo* info_list = nullptr; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h index 7ce795d719c..ff01cec5831 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.h @@ -31,7 +31,13 @@ class QuicClientPeer; namespace tools { -QuicSocketAddress LookupAddress(std::string host, std::string port); +QuicSocketAddress LookupAddress(int address_family_for_lookup, + std::string host, + std::string port); + +inline QuicSocketAddress LookupAddress(std::string host, std::string port) { + return LookupAddress(0, host, port); +} } // namespace tools diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc index f0def98fe4c..c1d2ea2103c 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc @@ -114,14 +114,17 @@ void QuicClientBase::StartConnect() { UpdateStats(); } + const quic::ParsedQuicVersionVector client_supported_versions = + can_reconnect_with_different_version + ? ParsedQuicVersionVector{mutual_version} + : supported_versions(); + session_ = CreateQuicClientSession( - supported_versions(), + client_supported_versions, new QuicConnection(GetNextConnectionId(), server_address(), helper(), alarm_factory(), writer, /* owns_writer= */ false, Perspective::IS_CLIENT, - can_reconnect_with_different_version - ? ParsedQuicVersionVector{mutual_version} - : supported_versions())); + client_supported_versions)); if (connection_debug_visitor_ != nullptr) { session()->connection()->set_debug_visitor(connection_debug_visitor_); } @@ -283,7 +286,7 @@ bool QuicClientBase::connected() const { } bool QuicClientBase::goaway_received() const { - return session_ != nullptr && session_->goaway_received(); + return session_ != nullptr && session_->transport_goaway_received(); } int QuicClientBase::GetNumSentClientHellos() { diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h index ff600ae0de7..4df3a2bb927 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.h @@ -128,7 +128,7 @@ class QuicClientBase { const QuicSession* session() const; bool connected() const; - bool goaway_received() const; + virtual bool goaway_received() const; const QuicServerId& server_id() const { return server_id_; } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc index 38dc582c1f3..b7dbb07fa7b 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.cc @@ -20,12 +20,13 @@ namespace quic { std::unique_ptr<QuicSpdyClientBase> QuicEpollClientFactory::CreateClient( std::string host_for_handshake, std::string host_for_lookup, + int address_family_for_lookup, uint16_t port, ParsedQuicVersionVector versions, const QuicConfig& config, std::unique_ptr<ProofVerifier> verifier) { - QuicSocketAddress addr = - tools::LookupAddress(host_for_lookup, quiche::QuicheStrCat(port)); + QuicSocketAddress addr = tools::LookupAddress( + address_family_for_lookup, host_for_lookup, quiche::QuicheStrCat(port)); if (!addr.IsInitialized()) { QUIC_LOG(ERROR) << "Unable to resolve address: " << host_for_lookup; return nullptr; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h index 392bd6cc47c..84dbc98ef28 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_epoll_client_factory.h @@ -16,6 +16,7 @@ class QuicEpollClientFactory : public QuicToyClient::ClientFactory { std::unique_ptr<QuicSpdyClientBase> CreateClient( std::string host_for_handshake, std::string host_for_lookup, + int address_family_for_lookup, uint16_t port, ParsedQuicVersionVector versions, const QuicConfig& config, diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc index c7ac9127790..370eb4aaedb 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc @@ -199,8 +199,8 @@ void QuicMemoryCacheBackend::AddResponse( SpdyHeaderBlock response_headers, quiche::QuicheStringPiece response_body) { AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE, - std::move(response_headers), response_body, SpdyHeaderBlock(), - 0); + std::move(response_headers), response_body, + SpdyHeaderBlock()); } void QuicMemoryCacheBackend::AddResponse( @@ -211,7 +211,7 @@ void QuicMemoryCacheBackend::AddResponse( SpdyHeaderBlock response_trailers) { AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE, std::move(response_headers), response_body, - std::move(response_trailers), 0); + std::move(response_trailers)); } void QuicMemoryCacheBackend::AddSpecialResponse( @@ -219,7 +219,7 @@ void QuicMemoryCacheBackend::AddSpecialResponse( quiche::QuicheStringPiece path, SpecialResponseType response_type) { AddResponseImpl(host, path, response_type, SpdyHeaderBlock(), "", - SpdyHeaderBlock(), 0); + SpdyHeaderBlock()); } void QuicMemoryCacheBackend::AddSpecialResponse( @@ -229,18 +229,7 @@ void QuicMemoryCacheBackend::AddSpecialResponse( quiche::QuicheStringPiece response_body, SpecialResponseType response_type) { AddResponseImpl(host, path, response_type, std::move(response_headers), - response_body, SpdyHeaderBlock(), 0); -} - -void QuicMemoryCacheBackend::AddStopSendingResponse( - quiche::QuicheStringPiece host, - quiche::QuicheStringPiece path, - spdy::SpdyHeaderBlock response_headers, - quiche::QuicheStringPiece response_body, - uint16_t stop_sending_code) { - AddResponseImpl(host, path, SpecialResponseType::STOP_SENDING, - std::move(response_headers), response_body, SpdyHeaderBlock(), - stop_sending_code); + response_body, SpdyHeaderBlock()); } QuicMemoryCacheBackend::QuicMemoryCacheBackend() : cache_initialized_(false) {} @@ -369,8 +358,7 @@ void QuicMemoryCacheBackend::AddResponseImpl( SpecialResponseType response_type, SpdyHeaderBlock response_headers, quiche::QuicheStringPiece response_body, - SpdyHeaderBlock response_trailers, - uint16_t stop_sending_code) { + SpdyHeaderBlock response_trailers) { QuicWriterMutexLock lock(&response_mutex_); DCHECK(!host.empty()) << "Host must be populated, e.g. \"www.google.com\""; @@ -384,7 +372,6 @@ void QuicMemoryCacheBackend::AddResponseImpl( new_response->set_headers(std::move(response_headers)); new_response->set_body(response_body); new_response->set_trailers(std::move(response_trailers)); - new_response->set_stop_sending_code(stop_sending_code); QUIC_DVLOG(1) << "Add response with key " << key; responses_[key] = std::move(new_response); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h index 56a2323b190..1c56ce6355e 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h @@ -124,12 +124,6 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { quiche::QuicheStringPiece response_body, QuicBackendResponse::SpecialResponseType response_type); - void AddStopSendingResponse(quiche::QuicheStringPiece host, - quiche::QuicheStringPiece path, - spdy::SpdyHeaderBlock response_headers, - quiche::QuicheStringPiece response_body, - uint16_t stop_sending_code); - // Sets a default response in case of cache misses. Takes ownership of // 'response'. void AddDefaultResponse(QuicBackendResponse* response); @@ -159,8 +153,7 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend { QuicBackendResponse::SpecialResponseType response_type, spdy::SpdyHeaderBlock response_headers, quiche::QuicheStringPiece response_body, - spdy::SpdyHeaderBlock response_trailers, - uint16_t stop_sending_code); + spdy::SpdyHeaderBlock response_trailers); std::string GetKey(quiche::QuicheStringPiece host, quiche::QuicheStringPiece path) const; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc index f5dad7d2d3f..780ff9df099 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc @@ -296,9 +296,8 @@ class QuicSimpleServerSessionTest return; } EXPECT_CALL(owner_, OnStopSendingReceived(_)).Times(1); - QuicStopSendingFrame stop_sending( - kInvalidControlFrameId, stream_id, - static_cast<QuicApplicationErrorCode>(rst_stream_code)); + QuicStopSendingFrame stop_sending(kInvalidControlFrameId, stream_id, + rst_stream_code); // Expect the RESET_STREAM that is generated in response to receiving a // STOP_SENDING. EXPECT_CALL(*connection_, OnStreamReset(stream_id, rst_stream_code)); diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc index a6775ccd7a0..84ddb055aa7 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc @@ -254,15 +254,6 @@ void QuicSimpleServerStream::OnResponseBackendComplete( return; } - if (response->response_type() == QuicBackendResponse::STOP_SENDING) { - QUIC_DVLOG(1) - << "Stream " << id() - << " sending an incomplete response, i.e. no trailer, no fin."; - SendIncompleteResponse(response->headers().Clone(), response->body()); - SendStopSending(response->stop_sending_code()); - return; - } - if (response->response_type() == QuicBackendResponse::GENERATE_BYTES) { QUIC_DVLOG(1) << "Stream " << id() << " sending a generate bytes response."; std::string path = request_headers_[":path"].as_string().substr(1); diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc index 09de8138570..212e605f298 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc @@ -188,13 +188,15 @@ QuicSpdyClientStream* QuicSpdyClientBase::CreateClientStream() { auto* stream = static_cast<QuicSpdyClientStream*>( client_session()->CreateOutgoingBidirectionalStream()); if (stream) { - stream->SetPriority( - spdy::SpdyStreamPrecedence(QuicStream::kDefaultPriority)); stream->set_visitor(this); } return stream; } +bool QuicSpdyClientBase::goaway_received() const { + return client_session() && client_session()->goaway_received(); +} + bool QuicSpdyClientBase::EarlyDataAccepted() { return client_session()->EarlyDataAccepted(); } diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h index 874aa2da4d2..fdd67fbc3b5 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h @@ -143,6 +143,8 @@ class QuicSpdyClientBase : public QuicClientBase, // TODO(b/151641466): Rename this method. void SetMaxAllowedPushId(PushId max) { max_allowed_push_id_ = max; } + // QuicClientBase methods. + bool goaway_received() const override; bool EarlyDataAccepted() override; bool ReceivedInchoateReject() override; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc index b42f967caf0..582f3c7cd4a 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.cc @@ -53,6 +53,7 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_default_proof_providers.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ip_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_system_event_loop.h" #include "net/third_party/quiche/src/quic/tools/fake_proof_verifier.h" @@ -78,6 +79,12 @@ DEFINE_QUIC_COMMAND_LINE_FLAG( DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to."); DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, + ip_version_for_host_lookup, + "", + "Only used if host address lookup is needed. " + "4=ipv4; 6=ipv6; otherwise=don't care."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(std::string, body, "", "If set, send a POST with this body."); @@ -259,9 +266,17 @@ int QuicToyClient::SendRequestsAndPrintResponses( ParseQuicTagVector(client_connection_options_string)); } + int address_family_for_lookup = AF_UNSPEC; + if (GetQuicFlag(FLAGS_ip_version_for_host_lookup) == "4") { + address_family_for_lookup = AF_INET; + } else if (GetQuicFlag(FLAGS_ip_version_for_host_lookup) == "6") { + address_family_for_lookup = AF_INET6; + } + // Build the client, and try to connect. std::unique_ptr<QuicSpdyClientBase> client = client_factory_->CreateClient( - url.host(), host, port, versions, config, std::move(proof_verifier)); + url.host(), host, address_family_for_lookup, port, versions, config, + std::move(proof_verifier)); if (client == nullptr) { std::cerr << "Failed to create client." << std::endl; diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h index d9d8ecaf87a..bf56bf8946d 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_toy_client.h @@ -24,6 +24,8 @@ class QuicToyClient { virtual std::unique_ptr<QuicSpdyClientBase> CreateClient( std::string host_for_handshake, std::string host_for_lookup, + // AF_INET, AF_INET6, or AF_UNSPEC(=don't care). + int address_family_for_lookup, uint16_t port, ParsedQuicVersionVector versions, const QuicConfig& config, diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc index 49c86e52000..d07da11672b 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc @@ -176,6 +176,12 @@ void QuicTransportSimpleServerSession::OnIncomingDataStream( break; } break; + + case OUTGOING_BIDIRECTIONAL: + stream->set_visitor(std::make_unique<DiscardVisitor>(stream)); + ++pending_outgoing_bidirectional_streams_; + MaybeCreateOutgoingBidirectionalStream(); + break; } } @@ -183,6 +189,8 @@ void QuicTransportSimpleServerSession::OnCanCreateNewOutgoingStream( bool unidirectional) { if (mode_ == ECHO && unidirectional) { MaybeEchoStreamsBack(); + } else if (mode_ == OUTGOING_BIDIRECTIONAL && !unidirectional) { + MaybeCreateOutgoingBidirectionalStream(); } } @@ -208,6 +216,10 @@ bool QuicTransportSimpleServerSession::ProcessPath(const GURL& url) { mode_ = ECHO; return true; } + if (url.path() == "/receive-bidirectional") { + mode_ = OUTGOING_BIDIRECTIONAL; + return true; + } QUIC_DLOG(WARNING) << "Unknown path requested: " << url.path(); return false; @@ -246,4 +258,21 @@ void QuicTransportSimpleServerSession::MaybeEchoStreamsBack() { } } +void QuicTransportSimpleServerSession:: + MaybeCreateOutgoingBidirectionalStream() { + while (pending_outgoing_bidirectional_streams_ > 0 && + CanOpenNextOutgoingBidirectionalStream()) { + auto stream_owned = std::make_unique<QuicTransportStream>( + GetNextOutgoingBidirectionalStreamId(), this, this); + QuicTransportStream* stream = stream_owned.get(); + ActivateStream(std::move(stream_owned)); + QUIC_DVLOG(1) << "Opened outgoing bidirectional stream " << stream->id(); + stream->set_visitor(std::make_unique<BidirectionalEchoVisitor>(stream)); + if (!stream->Write("hello")) { + QUIC_DVLOG(1) << "Write failed."; + } + --pending_outgoing_bidirectional_streams_; + } +} + } // namespace quic diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h index 7a5fb097cd9..7cfd1975c4e 100644 --- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h +++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h @@ -34,6 +34,13 @@ class QuicTransportSimpleServerSession // a server-initiated unidirectional stream that is sent as soon as a FIN is // received on the incoming stream. ECHO, + // In OUTGOING_BIDIRECTIONAL mode, a server-originated bidirectional stream + // is created on receipt of a unidirectional stream. The contents of the + // unidirectional stream are disregarded. The bidirectional stream initially + // sends "hello", then any received data is echoed back. + // TODO(ricea): Maybe this should be replaced by a more general mechanism + // where commands on the unidirectional stream trigger different behaviour? + OUTGOING_BIDIRECTIONAL, }; QuicTransportSimpleServerSession( @@ -60,8 +67,10 @@ class QuicTransportSimpleServerSession private: void MaybeEchoStreamsBack(); + void MaybeCreateOutgoingBidirectionalStream(); const bool owns_connection_; + size_t pending_outgoing_bidirectional_streams_ = 0u; Mode mode_; std::vector<url::Origin> accepted_origins_; QuicCircularDeque<std::string> streams_to_echo_back_; diff --git a/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_benchmark.cc b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_benchmark.cc new file mode 100644 index 00000000000..aeea7268965 --- /dev/null +++ b/chromium/net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table_benchmark.cc @@ -0,0 +1,64 @@ +// Copyright 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. + +// +// $ blaze run -c opt --dynamic_mode=off \ +// -- //net/third_party/quiche/src/spdy/core/hpack:hpack_huffman_table_benchmark \ +// --benchmarks=all --benchmark_memory_usage --benchmark_repetitions=1 +// +// Benchmark Time(ns) CPU(ns) Allocs Iterations +// ----------------------------------------------------------------------------- +// BM_EncodeSmallStrings 463 441 0 100000 0.000B peak-mem +// BM_EncodeLargeString/1k 9003 9069 5 4861 1.125kB peak-mem +// BM_EncodeLargeString/4k 34808 35157 7 1597 4.500kB peak-mem +// BM_EncodeLargeString/32k 275973 270741 10 207 36.000kB peak-mem +// BM_EncodeLargeString/256k 2234748 2236850 13 29 288.000kB peak-mem +// BM_EncodeLargeString/2M 18248449 18717995 16 3 2.250MB peak-mem +// BM_EncodeLargeString/16M 144944895 144415061 19 1 18.000MB peak-mem +// BM_EncodeLargeString/128M 1200907841 1207238809 86 1 144.009MB peak-mem +// + +#include <string> + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +// This header has multiple DCHECK_* macros with signed-unsigned comparison. +#include "testing/base/public/benchmark.h" +#pragma clang diagnostic pop + +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_constants.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_huffman_table.h" +#include "net/third_party/quiche/src/spdy/core/hpack/hpack_output_stream.h" + +namespace spdy { +namespace { + +void BM_EncodeSmallStrings(benchmark::State& state) { + const HpackHuffmanTable& table = ObtainHpackHuffmanTable(); + const std::vector<const std::string> inputs{ + ":method", ":path", "cookie", "set-cookie", "vary", "accept-encoding"}; + for (auto s : state) { + for (const auto& input : inputs) { + HpackOutputStream output_stream; + table.EncodedSize(input); + table.EncodeString(input, &output_stream); + } + } +} + +void BM_EncodeLargeString(benchmark::State& state) { + const HpackHuffmanTable& table = ObtainHpackHuffmanTable(); + const std::string input(state.range(0), 'a'); + for (auto s : state) { + HpackOutputStream output_stream; + table.EncodedSize(input); + table.EncodeString(input, &output_stream); + } +} + +BENCHMARK(BM_EncodeSmallStrings); +BENCHMARK(BM_EncodeLargeString)->Range(1024, 128 * 1024 * 1024); + +} // namespace +} // namespace spdy diff --git a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h index a50745f1897..a58e2240eff 100644 --- a/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h +++ b/chromium/net/third_party/quiche/src/spdy/core/http2_priority_write_scheduler.h @@ -17,7 +17,6 @@ #include <utility> #include <vector> -#include "net/third_party/quiche/src/common/platform/api/quiche_map_util.h" #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" #include "net/third_party/quiche/src/spdy/core/spdy_intrusive_list.h" #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h" @@ -211,7 +210,7 @@ Http2PriorityWriteScheduler<StreamIdType>::Http2PriorityWriteScheduler() { template <typename StreamIdType> bool Http2PriorityWriteScheduler<StreamIdType>::StreamRegistered( StreamIdType stream_id) const { - return quiche::QuicheContainsKey(all_stream_infos_, stream_id); + return all_stream_infos_.find(stream_id) != all_stream_infos_.end(); } template <typename StreamIdType> |