Project import generated by Copybara. PiperOrigin-RevId: 235760953 Change-Id: I302811f663a1f4772520f3fa3148e54851e0227a
diff --git a/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc b/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc index bf928d3..0221328 100644 --- a/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc +++ b/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
@@ -96,10 +96,9 @@ const uint32_t value_length_; }; -INSTANTIATE_TEST_CASE_P(VariousOriginAndValueLengths, - AltSvcPayloadLengthTests, - ::testing::Combine(::testing::Values(0, 1, 3, 65535), - ::testing::Values(0, 1, 3, 65537))); +INSTANTIATE_TEST_SUITE_P(VariousOriginAndValueLengths, AltSvcPayloadLengthTests, + ::testing::Combine(::testing::Values(0, 1, 3, 65535), + ::testing::Values(0, 1, 3, 65537))); TEST_P(AltSvcPayloadLengthTests, ValidOriginAndValueLength) { Http2String origin = Random().RandString(origin_length_);
diff --git a/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc b/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc index 63888d3..6e81828 100644 --- a/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc +++ b/http2/decoder/payload_decoders/continuation_payload_decoder_test.cc
@@ -67,9 +67,8 @@ const uint32_t length_; }; -INSTANTIATE_TEST_CASE_P(VariousLengths, - ContinuationPayloadDecoderTest, - ::testing::Values(0, 1, 2, 3, 4, 5, 6)); +INSTANTIATE_TEST_SUITE_P(VariousLengths, ContinuationPayloadDecoderTest, + ::testing::Values(0, 1, 2, 3, 4, 5, 6)); TEST_P(ContinuationPayloadDecoderTest, ValidLength) { Http2String hpack_payload = Random().RandString(length_);
diff --git a/http2/decoder/payload_decoders/data_payload_decoder_test.cc b/http2/decoder/payload_decoders/data_payload_decoder_test.cc index e5253b9..0622f17 100644 --- a/http2/decoder/payload_decoders/data_payload_decoder_test.cc +++ b/http2/decoder/payload_decoders/data_payload_decoder_test.cc
@@ -98,9 +98,8 @@ } }; -INSTANTIATE_TEST_CASE_P(VariousPadLengths, - DataPayloadDecoderTest, - ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256)); +INSTANTIATE_TEST_SUITE_P(VariousPadLengths, DataPayloadDecoderTest, + ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256)); TEST_P(DataPayloadDecoderTest, VariousDataPayloadSizes) { for (size_t data_size : {0, 1, 2, 3, 255, 256, 1024}) {
diff --git a/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc b/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc index 1df5214..c90cdcc 100644 --- a/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc +++ b/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
@@ -83,9 +83,8 @@ const uint32_t length_; }; -INSTANTIATE_TEST_CASE_P(VariousLengths, - GoAwayOpaqueDataLengthTests, - ::testing::Values(0, 1, 2, 3, 4, 5, 6)); +INSTANTIATE_TEST_SUITE_P(VariousLengths, GoAwayOpaqueDataLengthTests, + ::testing::Values(0, 1, 2, 3, 4, 5, 6)); TEST_P(GoAwayOpaqueDataLengthTests, ValidLength) { Http2GoAwayFields goaway;
diff --git a/http2/decoder/payload_decoders/headers_payload_decoder_test.cc b/http2/decoder/payload_decoders/headers_payload_decoder_test.cc index a6fcb65..cb58b8e 100644 --- a/http2/decoder/payload_decoders/headers_payload_decoder_test.cc +++ b/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
@@ -94,9 +94,8 @@ HeadersPayloadDecoderPeer, Listener> {}; -INSTANTIATE_TEST_CASE_P(VariousPadLengths, - HeadersPayloadDecoderTest, - ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256)); +INSTANTIATE_TEST_SUITE_P(VariousPadLengths, HeadersPayloadDecoderTest, + ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256)); // Decode various sizes of (fake) HPACK payload, both with and without the // PRIORITY flag set.
diff --git a/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc b/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc index 9d55a80..94220f7 100644 --- a/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc +++ b/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
@@ -87,9 +87,8 @@ PushPromisePayloadDecoderPeer, Listener> {}; -INSTANTIATE_TEST_CASE_P(VariousPadLengths, - PushPromisePayloadDecoderTest, - ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256)); +INSTANTIATE_TEST_SUITE_P(VariousPadLengths, PushPromisePayloadDecoderTest, + ::testing::Values(0, 1, 2, 3, 4, 254, 255, 256)); // Payload contains the required Http2PushPromiseFields, followed by some // (fake) HPACK payload.
diff --git a/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc b/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc index 7ba95f7..f9d203a 100644 --- a/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc +++ b/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
@@ -77,9 +77,8 @@ const uint32_t length_; }; -INSTANTIATE_TEST_CASE_P(VariousLengths, - UnknownPayloadDecoderTest, - ::testing::Values(0, 1, 2, 3, 255, 256)); +INSTANTIATE_TEST_SUITE_P(VariousLengths, UnknownPayloadDecoderTest, + ::testing::Values(0, 1, 2, 3, 255, 256)); TEST_P(UnknownPayloadDecoderTest, ValidLength) { Http2String unknown_payload = Random().RandString(length_);
diff --git a/http2/hpack/decoder/hpack_decoder_test.cc b/http2/hpack/decoder/hpack_decoder_test.cc index 563e977..83a0ede 100644 --- a/http2/hpack/decoder/hpack_decoder_test.cc +++ b/http2/hpack/decoder/hpack_decoder_test.cc
@@ -224,7 +224,7 @@ bool saw_start_ = false; bool saw_end_ = false; }; -INSTANTIATE_TEST_CASE_P(AllWays, HpackDecoderTest, ::testing::Bool()); +INSTANTIATE_TEST_SUITE_P(AllWays, HpackDecoderTest, ::testing::Bool()); // Test based on RFC 7541, section C.3: Request Examples without Huffman Coding. // This section shows several consecutive header lists, corresponding to HTTP
diff --git a/http2/hpack/decoder/hpack_entry_decoder_test.cc b/http2/hpack/decoder/hpack_entry_decoder_test.cc index 7249bd5..b447e82 100644 --- a/http2/hpack/decoder/hpack_entry_decoder_test.cc +++ b/http2/hpack/decoder/hpack_entry_decoder_test.cc
@@ -157,9 +157,8 @@ const HpackEntryType entry_type_; }; -INSTANTIATE_TEST_CASE_P( - AllLiteralTypes, - HpackLiteralEntryDecoderTest, +INSTANTIATE_TEST_SUITE_P( + AllLiteralTypes, HpackLiteralEntryDecoderTest, testing::Values(HpackEntryType::kIndexedLiteralHeader, HpackEntryType::kUnindexedLiteralHeader, HpackEntryType::kNeverIndexedLiteralHeader));
diff --git a/http2/hpack/huffman/hpack_huffman_transcoder_test.cc b/http2/hpack/huffman/hpack_huffman_transcoder_test.cc index cfd73b5..2791d6a 100644 --- a/http2/hpack/huffman/hpack_huffman_transcoder_test.cc +++ b/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
@@ -139,9 +139,9 @@ const char c_; }; -INSTANTIATE_TEST_CASE_P(HpackHuffmanTranscoderAdjacentCharTest, - HpackHuffmanTranscoderAdjacentCharTest, - ::testing::Range(0, 256)); +INSTANTIATE_TEST_SUITE_P(HpackHuffmanTranscoderAdjacentCharTest, + HpackHuffmanTranscoderAdjacentCharTest, + ::testing::Range(0, 256)); // Test c_ adjacent to every other character, both before and after. TEST_P(HpackHuffmanTranscoderAdjacentCharTest, RoundTripAdjacentChar) { @@ -169,11 +169,11 @@ const size_t length_; }; -INSTANTIATE_TEST_CASE_P( - HpackHuffmanTranscoderRepeatedCharTest, - HpackHuffmanTranscoderRepeatedCharTest, - ::testing::Combine(::testing::Range(0, 256), - ::testing::Values(1, 2, 3, 4, 8, 16, 32))); +INSTANTIATE_TEST_SUITE_P(HpackHuffmanTranscoderRepeatedCharTest, + HpackHuffmanTranscoderRepeatedCharTest, + ::testing::Combine(::testing::Range(0, 256), + ::testing::Values(1, 2, 3, 4, 8, 16, + 32))); TEST_P(HpackHuffmanTranscoderRepeatedCharTest, RoundTripRepeatedChar) { ASSERT_TRUE(TranscodeAndValidateSeveralWays(MakeString()));
diff --git a/http2/hpack/varint/hpack_varint_decoder_test.cc b/http2/hpack/varint/hpack_varint_decoder_test.cc index 32a4a30..2d589fd 100644 --- a/http2/hpack/varint/hpack_varint_decoder_test.cc +++ b/http2/hpack/varint/hpack_varint_decoder_test.cc
@@ -107,9 +107,8 @@ uint8_t prefix_length_; }; -INSTANTIATE_TEST_CASE_P( - HpackVarintDecoderTest, - HpackVarintDecoderTest, +INSTANTIATE_TEST_SUITE_P( + HpackVarintDecoderTest, HpackVarintDecoderTest, ::testing::Combine( // Bits of the first byte not part of the prefix should be ignored. ::testing::Values(0b00000000, 0b11111111, 0b10101010),
diff --git a/http2/http2_structures_test.cc b/http2/http2_structures_test.cc index 30ebb36..78107f7 100644 --- a/http2/http2_structures_test.cc +++ b/http2/http2_structures_test.cc
@@ -163,10 +163,9 @@ }; class IsEndStreamTest : public Http2FrameHeaderTypeAndFlagTest {}; -INSTANTIATE_TEST_CASE_P(IsEndStream, - IsEndStreamTest, - Combine(ValuesIn(ValidFrameTypes()), - Values(~Http2FrameFlag::END_STREAM, 0xff))); +INSTANTIATE_TEST_SUITE_P(IsEndStream, IsEndStreamTest, + Combine(ValuesIn(ValidFrameTypes()), + Values(~Http2FrameFlag::END_STREAM, 0xff))); TEST_P(IsEndStreamTest, IsEndStream) { const bool is_set = (flags_ & Http2FrameFlag::END_STREAM) == Http2FrameFlag::END_STREAM; @@ -201,10 +200,9 @@ } class IsACKTest : public Http2FrameHeaderTypeAndFlagTest {}; -INSTANTIATE_TEST_CASE_P(IsAck, - IsACKTest, - Combine(ValuesIn(ValidFrameTypes()), - Values(~Http2FrameFlag::ACK, 0xff))); +INSTANTIATE_TEST_SUITE_P(IsAck, IsACKTest, + Combine(ValuesIn(ValidFrameTypes()), + Values(~Http2FrameFlag::ACK, 0xff))); TEST_P(IsACKTest, IsAck) { const bool is_set = (flags_ & Http2FrameFlag::ACK) == Http2FrameFlag::ACK; Http2String flags_string; @@ -238,10 +236,9 @@ } class IsEndHeadersTest : public Http2FrameHeaderTypeAndFlagTest {}; -INSTANTIATE_TEST_CASE_P(IsEndHeaders, - IsEndHeadersTest, - Combine(ValuesIn(ValidFrameTypes()), - Values(~Http2FrameFlag::END_HEADERS, 0xff))); +INSTANTIATE_TEST_SUITE_P(IsEndHeaders, IsEndHeadersTest, + Combine(ValuesIn(ValidFrameTypes()), + Values(~Http2FrameFlag::END_HEADERS, 0xff))); TEST_P(IsEndHeadersTest, IsEndHeaders) { const bool is_set = (flags_ & Http2FrameFlag::END_HEADERS) == Http2FrameFlag::END_HEADERS; @@ -279,10 +276,9 @@ } class IsPaddedTest : public Http2FrameHeaderTypeAndFlagTest {}; -INSTANTIATE_TEST_CASE_P(IsPadded, - IsPaddedTest, - Combine(ValuesIn(ValidFrameTypes()), - Values(~Http2FrameFlag::PADDED, 0xff))); +INSTANTIATE_TEST_SUITE_P(IsPadded, IsPaddedTest, + Combine(ValuesIn(ValidFrameTypes()), + Values(~Http2FrameFlag::PADDED, 0xff))); TEST_P(IsPaddedTest, IsPadded) { const bool is_set = (flags_ & Http2FrameFlag::PADDED) == Http2FrameFlag::PADDED; @@ -318,10 +314,9 @@ } class HasPriorityTest : public Http2FrameHeaderTypeAndFlagTest {}; -INSTANTIATE_TEST_CASE_P(HasPriority, - HasPriorityTest, - Combine(ValuesIn(ValidFrameTypes()), - Values(~Http2FrameFlag::PRIORITY, 0xff))); +INSTANTIATE_TEST_SUITE_P(HasPriority, HasPriorityTest, + Combine(ValuesIn(ValidFrameTypes()), + Values(~Http2FrameFlag::PRIORITY, 0xff))); TEST_P(HasPriorityTest, HasPriority) { const bool is_set = (flags_ & Http2FrameFlag::PRIORITY) == Http2FrameFlag::PRIORITY;
diff --git a/quic/core/chlo_extractor.cc b/quic/core/chlo_extractor.cc index b44aa9c..caf0af1 100644 --- a/quic/core/chlo_extractor.cc +++ b/quic/core/chlo_extractor.cc
@@ -39,6 +39,7 @@ bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override {} bool OnPacketHeader(const QuicPacketHeader& header) override; + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override; bool OnStreamFrame(const QuicStreamFrame& frame) override; bool OnCryptoFrame(const QuicCryptoFrame& frame) override; bool OnAckFrameStart(QuicPacketNumber largest_acked, @@ -75,6 +76,9 @@ void OnError(CryptoFramer* framer) override; void OnHandshakeMessage(const CryptoHandshakeMessage& message) override; + // Shared implementation between OnStreamFrame and OnCryptoFrame. + bool OnHandshakeData(QuicStringPiece data); + bool found_chlo() { return found_chlo_; } bool chlo_contains_tags() { return chlo_contains_tags_; } @@ -119,39 +123,56 @@ bool ChloFramerVisitor::OnPacketHeader(const QuicPacketHeader& header) { return true; } +void ChloFramerVisitor::OnCoalescedPacket(const QuicEncryptedPacket& packet) {} bool ChloFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) { + if (framer_->transport_version() >= QUIC_VERSION_47) { + // CHLO will be sent in CRYPTO frames in v47 and above. + return false; + } QuicStringPiece data(frame.data_buffer, frame.data_length); if (frame.stream_id == QuicUtils::GetCryptoStreamId(framer_->transport_version()) && frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) { - CryptoFramer crypto_framer; - crypto_framer.set_visitor(this); - if (!crypto_framer.ProcessInput(data)) { - return false; - } - // Interrogate the crypto framer and see if there are any - // intersecting tags between what we saw in the maybe-CHLO and the - // indicator set. - for (const QuicTag tag : create_session_tag_indicators_) { - if (crypto_framer.HasTag(tag)) { - chlo_contains_tags_ = true; - } - } - if (chlo_contains_tags_ && delegate_) { - // Unfortunately, because this is a partial CHLO, - // OnHandshakeMessage was never called, so the ALPN was never - // extracted. Fake it up a bit and send it to the delegate so that - // the correct dispatch can happen. - crypto_framer.ForceHandshake(); - } + return OnHandshakeData(data); } - return true; } bool ChloFramerVisitor::OnCryptoFrame(const QuicCryptoFrame& frame) { - // TODO(nharper): Implement. - return false; + if (framer_->transport_version() < QUIC_VERSION_47) { + // CHLO will be in stream frames before v47. + return false; + } + QuicStringPiece data(frame.data_buffer, frame.data_length); + if (frame.offset == 0 && QuicTextUtils::StartsWith(data, "CHLO")) { + return OnHandshakeData(data); + } + return true; +} + +bool ChloFramerVisitor::OnHandshakeData(QuicStringPiece data) { + CryptoFramer crypto_framer; + crypto_framer.set_visitor(this); + if (!crypto_framer.ProcessInput(data)) { + return false; + } + // Interrogate the crypto framer and see if there are any + // intersecting tags between what we saw in the maybe-CHLO and the + // indicator set. + for (const QuicTag tag : create_session_tag_indicators_) { + if (crypto_framer.HasTag(tag)) { + chlo_contains_tags_ = true; + } + } + if (chlo_contains_tags_ && delegate_) { + // Unfortunately, because this is a partial CHLO, + // OnHandshakeMessage was never called, so the ALPN was never + // extracted. Fake it up a bit and send it to the delegate so that + // the correct dispatch can happen. + crypto_framer.ForceHandshake(); + } + + return true; } bool ChloFramerVisitor::OnAckFrameStart(QuicPacketNumber /*largest_acked*/,
diff --git a/quic/core/chlo_extractor_test.cc b/quic/core/chlo_extractor_test.cc index d16050b..e8b6483 100644 --- a/quic/core/chlo_extractor_test.cc +++ b/quic/core/chlo_extractor_test.cc
@@ -53,14 +53,35 @@ header_.reset_flag = false; header_.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; header_.packet_number = QuicPacketNumber(1); + if (QuicVersionHasLongHeaderLengths(header_.version.transport_version)) { + header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } } - void MakePacket(const QuicStreamFrame& stream_frame) { - QuicFrame frame(stream_frame); + void MakePacket(ParsedQuicVersion version, + QuicStringPiece data, + bool munge_offset, + bool munge_stream_id) { QuicFrames frames; - frames.push_back(frame); + size_t offset = 0; + if (munge_offset) { + offset++; + } QuicFramer framer(SupportedVersions(header_.version), QuicTime::Zero(), Perspective::IS_CLIENT); + if (version.transport_version < QUIC_VERSION_47 || munge_stream_id) { + QuicStreamId stream_id = + QuicUtils::GetCryptoStreamId(version.transport_version); + if (munge_stream_id) { + stream_id++; + } + frames.push_back( + QuicFrame(QuicStreamFrame(stream_id, false, offset, data))); + } else { + frames.push_back( + QuicFrame(new QuicCryptoFrame(ENCRYPTION_NONE, offset, data))); + } std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header_, frames)); EXPECT_TRUE(packet != nullptr); @@ -70,6 +91,7 @@ ASSERT_NE(0u, encrypted_length); packet_ = QuicMakeUnique<QuicEncryptedPacket>(buffer_, encrypted_length); EXPECT_TRUE(packet_ != nullptr); + DeleteFrames(&frames); } protected: @@ -86,11 +108,19 @@ QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); // Construct a CHLO with each supported version for (ParsedQuicVersion version : AllSupportedVersions()) { + SCOPED_TRACE(version); ParsedQuicVersionVector versions(SupportedVersions(version)); header_.version = version; - MakePacket( - QuicStreamFrame(QuicUtils::GetCryptoStreamId(version.transport_version), - false, 0, client_hello_str)); + if (QuicVersionHasLongHeaderLengths(version.transport_version) && + header_.version_flag) { + header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } else { + header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + header_.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + } + MakePacket(version, client_hello_str, /*munge_offset*/ false, + /*munge_stream_id*/ false); EXPECT_TRUE(ChloExtractor::Extract(*packet_, versions, {}, &delegate_)) << ParsedQuicVersionToString(version); EXPECT_EQ(version.transport_version, delegate_.transport_version()); @@ -105,10 +135,8 @@ client_hello.set_tag(kCHLO); QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); - MakePacket(QuicStreamFrame(QuicUtils::GetCryptoStreamId( - AllSupportedVersions()[0].transport_version) + - 1, - false, 0, client_hello_str)); + MakePacket(AllSupportedVersions()[0], client_hello_str, + /*munge_offset*/ false, /*munge_stream_id*/ true); EXPECT_FALSE( ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); } @@ -118,17 +146,15 @@ client_hello.set_tag(kCHLO); QuicString client_hello_str(client_hello.GetSerialized().AsStringPiece()); - MakePacket(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(AllSupportedVersions()[0].transport_version), - false, 1, client_hello_str)); + MakePacket(AllSupportedVersions()[0], client_hello_str, /*munge_offset*/ true, + /*munge_stream_id*/ false); EXPECT_FALSE( ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); } TEST_F(ChloExtractorTest, DoesNotFindInvalidChlo) { - MakePacket(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(AllSupportedVersions()[0].transport_version), - false, 0, "foo")); + MakePacket(AllSupportedVersions()[0], "foo", /*munge_offset*/ false, + /*munge_stream_id*/ true); EXPECT_FALSE( ChloExtractor::Extract(*packet_, AllSupportedVersions(), {}, &delegate_)); }
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc index 27a3ab8..8cd5e71 100644 --- a/quic/core/congestion_control/general_loss_algorithm.cc +++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -32,7 +32,7 @@ GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type) : loss_detection_timeout_(QuicTime::Zero()), least_in_flight_(1), - faster_detect_loss_(GetQuicReloadableFlag(quic_faster_detect_loss)) { + packet_number_space_(NUM_PACKET_NUMBER_SPACES) { SetLossDetectionType(loss_type); } @@ -64,16 +64,14 @@ const AckedPacketVector& packets_acked, LostPacketVector* packets_lost) { loss_detection_timeout_ = QuicTime::Zero(); - if (faster_detect_loss_ && !packets_acked.empty() && + if (!packets_acked.empty() && packets_acked.front().packet_number == least_in_flight_) { if (least_in_flight_ + packets_acked.size() - 1 == largest_newly_acked) { // Optimization for the case when no packet is missing. - QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 1, 3); least_in_flight_ = largest_newly_acked + 1; largest_previously_acked_ = largest_newly_acked; return; } - QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 2, 3); // There is hole in acked_packets, increment least_in_flight_ if possible. for (const auto& acked : packets_acked) { if (acked.packet_number != least_in_flight_) { @@ -89,34 +87,29 @@ max_rtt + (max_rtt >> reordering_shift_)); QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked(); auto it = unacked_packets.begin(); - if (faster_detect_loss_) { - if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) { - if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) { - QUIC_BUG << "least_in_flight: " << least_in_flight_ - << " is greater than largest_sent_packet + 1: " - << unacked_packets.largest_sent_packet() + 1; - } else { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_faster_detect_loss, 3, 3); - it += (least_in_flight_ - packet_number); - packet_number = least_in_flight_; - } - } - // Clear least_in_flight_. - least_in_flight_.Clear(); - } else { - if (largest_lost_.IsInitialized() && largest_lost_ >= packet_number) { - if (largest_lost_ > unacked_packets.largest_sent_packet()) { - QUIC_BUG << "largest_lost: " << largest_lost_ - << " is greater than largest_sent_packet: " - << unacked_packets.largest_sent_packet(); - } else { - it += (largest_lost_ - packet_number + 1); - packet_number = largest_lost_ + 1; - } + if (least_in_flight_.IsInitialized() && least_in_flight_ >= packet_number) { + if (least_in_flight_ > unacked_packets.largest_sent_packet() + 1) { + QUIC_BUG << "least_in_flight: " << least_in_flight_ + << " is greater than largest_sent_packet + 1: " + << unacked_packets.largest_sent_packet() + 1; + } else { + it += (least_in_flight_ - packet_number); + packet_number = least_in_flight_; } } + // Clear least_in_flight_. + least_in_flight_.Clear(); + DCHECK(!unacked_packets.use_uber_loss_algorithm() || + packet_number_space_ == + unacked_packets.GetPacketNumberSpace(largest_newly_acked)); for (; it != unacked_packets.end() && packet_number <= largest_newly_acked; ++it, ++packet_number) { + if (unacked_packets.use_uber_loss_algorithm() && + unacked_packets.GetPacketNumberSpace(it->encryption_level) != + packet_number_space_) { + // Skip packets of different packet number space. + continue; + } if (!it->in_flight) { continue; } @@ -144,8 +137,18 @@ // Only early retransmit(RFC5827) when the last packet gets acked and // there are retransmittable packets in flight. // This also implements a timer-protected variant of FACK. - if (unacked_packets.largest_sent_retransmittable_packet() <= - largest_newly_acked || + QuicPacketNumber largest_sent_retransmittable_packet; + if (unacked_packets.use_uber_loss_algorithm()) { + // Use largest_sent_retransmittable_packet of corresponding packet number + // space for timer based loss detection. + largest_sent_retransmittable_packet = + unacked_packets.GetLargestSentRetransmittableOfPacketNumberSpace( + packet_number_space_); + } else { + largest_sent_retransmittable_packet = + unacked_packets.largest_sent_retransmittable_packet(); + } + if (largest_sent_retransmittable_packet <= largest_newly_acked || loss_type_ == kTime || loss_type_ == kAdaptiveTime) { QuicTime when_lost = it->sent_time + loss_delay; if (time < when_lost) { @@ -176,11 +179,6 @@ least_in_flight_ = largest_newly_acked + 1; } largest_previously_acked_ = largest_newly_acked; - if (!packets_lost->empty()) { - DCHECK(!largest_lost_.IsInitialized() || - largest_lost_ < packets_lost->back().packet_number); - largest_lost_ = packets_lost->back().packet_number; - } } QuicTime GeneralLossAlgorithm::GetLossTimeout() const { @@ -225,4 +223,14 @@ } while (proposed_extra_time < extra_time_needed && reordering_shift_ > 0); } +void GeneralLossAlgorithm::SetPacketNumberSpace( + PacketNumberSpace packet_number_space) { + if (packet_number_space_ < NUM_PACKET_NUMBER_SPACES) { + QUIC_BUG << "Cannot switch packet_number_space"; + return; + } + + packet_number_space_ = packet_number_space; +} + } // namespace quic
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h index 0d8e565..a2bcadd 100644 --- a/quic/core/congestion_control/general_loss_algorithm.h +++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -55,6 +55,8 @@ const RttStats& rtt_stats, QuicPacketNumber spurious_retransmission) override; + void SetPacketNumberSpace(PacketNumberSpace packet_number_space); + int reordering_shift() const { return reordering_shift_; } private: @@ -71,15 +73,11 @@ int reordering_shift_; // The largest newly acked from the previous call to DetectLosses. QuicPacketNumber largest_previously_acked_; - // The largest lost packet. - // TODO(fayang): Remove this variable when deprecating - // quic_faster_detect_loss. - QuicPacketNumber largest_lost_; // The least in flight packet. Loss detection should start from this. Please // note, least_in_flight_ could be largest packet ever sent + 1. QuicPacketNumber least_in_flight_; - // Latched value of quic_faster_detect_loss flag. - const bool faster_detect_loss_; + // This is only used when quic_use_uber_loss_algorithm is true. + PacketNumberSpace packet_number_space_; }; } // namespace quic
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc index 2cd19a7..91a25da 100644 --- a/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -23,10 +23,13 @@ class GeneralLossAlgorithmTest : public QuicTest { protected: - GeneralLossAlgorithmTest() { + GeneralLossAlgorithmTest() : unacked_packets_(Perspective::IS_CLIENT) { rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100), QuicTime::Delta::Zero(), clock_.Now()); EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds()); + if (unacked_packets_.use_uber_loss_algorithm()) { + loss_algorithm_.SetPacketNumberSpace(HANDSHAKE_DATA); + } } ~GeneralLossAlgorithmTest() override {} @@ -54,9 +57,12 @@ void VerifyLosses(uint64_t largest_newly_acked, const AckedPacketVector& packets_acked, const std::vector<uint64_t>& losses_expected) { - if (!unacked_packets_.largest_acked().IsInitialized() || - QuicPacketNumber(largest_newly_acked) > - unacked_packets_.largest_acked()) { + if (unacked_packets_.use_uber_loss_algorithm()) { + unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_NONE, QuicPacketNumber(largest_newly_acked)); + } else if (!unacked_packets_.largest_acked().IsInitialized() || + QuicPacketNumber(largest_newly_acked) > + unacked_packets_.largest_acked()) { unacked_packets_.IncreaseLargestAcked( QuicPacketNumber(largest_newly_acked)); } @@ -208,7 +214,12 @@ clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); // Early retransmit when the final packet gets acked and the first is nacked. - unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2)); + if (unacked_packets_.use_uber_loss_algorithm()) { + unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_NONE, QuicPacketNumber(2)); + } else { + unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2)); + } unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2)); packets_acked.push_back( AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero())); @@ -226,7 +237,12 @@ clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); // Early retransmit when the final packet gets acked and the first is nacked. - unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2)); + if (unacked_packets_.use_uber_loss_algorithm()) { + unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_NONE, QuicPacketNumber(2)); + } else { + unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2)); + } unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2)); packets_acked.push_back( AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero())); @@ -253,7 +269,12 @@ AckedPacketVector packets_acked; // Wait another RTT and ack 2. clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); - unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2)); + if (unacked_packets_.use_uber_loss_algorithm()) { + unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_NONE, QuicPacketNumber(2)); + } else { + unacked_packets_.IncreaseLargestAcked(QuicPacketNumber(2)); + } unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2)); packets_acked.push_back( AckedPacket(QuicPacketNumber(2), kMaxPacketSize, QuicTime::Zero()));
diff --git a/quic/core/congestion_control/send_algorithm_test.cc b/quic/core/congestion_control/send_algorithm_test.cc index 6001690..d7bfd85 100644 --- a/quic/core/congestion_control/send_algorithm_test.cc +++ b/quic/core/congestion_control/send_algorithm_test.cc
@@ -268,10 +268,9 @@ SendAlgorithmInterface* sender_; }; -INSTANTIATE_TEST_CASE_P(SendAlgorithmTests, - SendAlgorithmTest, - ::testing::ValuesIn(GetTestParams()), - TestParamToString); +INSTANTIATE_TEST_SUITE_P(SendAlgorithmTests, SendAlgorithmTest, + ::testing::ValuesIn(GetTestParams()), + TestParamToString); // Test a simple long data transfer in the default setup. TEST_P(SendAlgorithmTest, SimpleWiredNetworkTransfer) {
diff --git a/quic/core/congestion_control/uber_loss_algorithm.cc b/quic/core/congestion_control/uber_loss_algorithm.cc new file mode 100644 index 0000000..8db151b --- /dev/null +++ b/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -0,0 +1,86 @@ +// Copyright 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. + +#include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h" + +#include <algorithm> + +namespace quic { + +UberLossAlgorithm::UberLossAlgorithm() : UberLossAlgorithm(kNack) {} + +UberLossAlgorithm::UberLossAlgorithm(LossDetectionType loss_type) + : loss_type_(loss_type) { + SetLossDetectionType(loss_type); + for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { + general_loss_algorithms_[i].SetPacketNumberSpace( + static_cast<PacketNumberSpace>(i)); + } +} + +LossDetectionType UberLossAlgorithm::GetLossDetectionType() const { + return loss_type_; +} + +void UberLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) { + loss_type_ = loss_type; + for (auto& loss_algorithm : general_loss_algorithms_) { + loss_algorithm.SetLossDetectionType(loss_type); + } +} + +void UberLossAlgorithm::DetectLosses( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber /*largest_newly_acked*/, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) { + DCHECK(unacked_packets.use_uber_loss_algorithm()); + for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { + const QuicPacketNumber largest_acked = + unacked_packets.GetLargestAckedOfPacketNumberSpace( + static_cast<PacketNumberSpace>(i)); + if (!largest_acked.IsInitialized() || + unacked_packets.GetLeastUnacked() > largest_acked) { + // Skip detecting losses if no packet has been received for this packet + // number space or the least_unacked is greater than largest_acked. + continue; + } + + general_loss_algorithms_[i].DetectLosses(unacked_packets, time, rtt_stats, + largest_acked, packets_acked, + packets_lost); + } +} + +QuicTime UberLossAlgorithm::GetLossTimeout() const { + QuicTime loss_timeout = QuicTime::Zero(); + // Returns the earliest non-zero loss timeout. + for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { + const QuicTime timeout = general_loss_algorithms_[i].GetLossTimeout(); + if (!loss_timeout.IsInitialized()) { + loss_timeout = timeout; + continue; + } + if (timeout.IsInitialized()) { + loss_timeout = std::min(loss_timeout, timeout); + } + } + return loss_timeout; +} + +void UberLossAlgorithm::SpuriousRetransmitDetected( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber spurious_retransmission) { + DCHECK(unacked_packets.use_uber_loss_algorithm()); + general_loss_algorithms_[unacked_packets.GetPacketNumberSpace( + spurious_retransmission)] + .SpuriousRetransmitDetected(unacked_packets, time, rtt_stats, + spurious_retransmission); +} + +} // namespace quic
diff --git a/quic/core/congestion_control/uber_loss_algorithm.h b/quic/core/congestion_control/uber_loss_algorithm.h new file mode 100644 index 0000000..dddbcb3 --- /dev/null +++ b/quic/core/congestion_control/uber_loss_algorithm.h
@@ -0,0 +1,53 @@ +// Copyright 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_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_ +#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_ + +#include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h" + +namespace quic { + +// This class comprises multiple loss algorithms, each per packet number space. +class QUIC_EXPORT_PRIVATE UberLossAlgorithm : public LossDetectionInterface { + public: + UberLossAlgorithm(); + explicit UberLossAlgorithm(LossDetectionType loss_type); + UberLossAlgorithm(const UberLossAlgorithm&) = delete; + UberLossAlgorithm& operator=(const UberLossAlgorithm&) = delete; + ~UberLossAlgorithm() override {} + + LossDetectionType GetLossDetectionType() const override; + + // Switches the loss detection type to |loss_type| and resets loss algorithm + // for all packet number spaces. + void SetLossDetectionType(LossDetectionType loss_type); + + // Detects lost packets. + void DetectLosses(const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber largest_newly_acked, + const AckedPacketVector& packets_acked, + LostPacketVector* packets_lost) override; + + // Returns the earliest time the early retransmit timer should be active. + QuicTime GetLossTimeout() const override; + + // Increases the loss detection threshold for time loss detection. + void SpuriousRetransmitDetected( + const QuicUnackedPacketMap& unacked_packets, + QuicTime time, + const RttStats& rtt_stats, + QuicPacketNumber spurious_retransmission) override; + + private: + LossDetectionType loss_type_; + // One loss algorithm per packet number space. + GeneralLossAlgorithm general_loss_algorithms_[NUM_PACKET_NUMBER_SPACES]; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_CONGESTION_CONTROL_UBER_LOSS_ALGORITHM_H_
diff --git a/quic/core/congestion_control/uber_loss_algorithm_test.cc b/quic/core/congestion_control/uber_loss_algorithm_test.cc new file mode 100644 index 0000000..9aa2041 --- /dev/null +++ b/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -0,0 +1,159 @@ +// Copyright 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. + +#include "net/third_party/quiche/src/quic/core/congestion_control/uber_loss_algorithm.h" + +#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" +#include "net/third_party/quiche/src/quic/core/quic_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.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/quic_unacked_packet_map_peer.h" + +namespace quic { +namespace test { +namespace { + +// Default packet length. +const uint32_t kDefaultLength = 1000; + +class UberLossAlgorithmTest : public QuicTest { + protected: + UberLossAlgorithmTest() { + SetQuicReloadableFlag(quic_use_uber_loss_algorithm, true); + unacked_packets_ = + QuicMakeUnique<QuicUnackedPacketMap>(Perspective::IS_CLIENT); + rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100), + QuicTime::Delta::Zero(), clock_.Now()); + EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds()); + } + + void SendPacket(uint64_t packet_number, EncryptionLevel encryption_level) { + QuicStreamFrame frame; + frame.stream_id = + encryption_level == ENCRYPTION_NONE + ? QuicUtils::GetCryptoStreamId( + CurrentSupportedVersions()[0].transport_version) + : QuicUtils::GetHeadersStreamId( + CurrentSupportedVersions()[0].transport_version); + SerializedPacket packet(QuicPacketNumber(packet_number), + PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, + false, false); + packet.encryption_level = encryption_level; + packet.retransmittable_frames.push_back(QuicFrame(frame)); + unacked_packets_->AddSentPacket(&packet, QuicPacketNumber(), + NOT_RETRANSMISSION, clock_.Now(), true); + } + + void AckPackets(const std::vector<uint64_t>& packets_acked) { + packets_acked_.clear(); + for (uint64_t acked : packets_acked) { + unacked_packets_->RemoveFromInFlight(QuicPacketNumber(acked)); + packets_acked_.push_back(AckedPacket(QuicPacketNumber(acked), + kMaxPacketSize, QuicTime::Zero())); + } + } + + void VerifyLosses(uint64_t largest_newly_acked, + const AckedPacketVector& packets_acked, + const std::vector<uint64_t>& losses_expected) { + LostPacketVector lost_packets; + loss_algorithm_.DetectLosses(*unacked_packets_, clock_.Now(), rtt_stats_, + QuicPacketNumber(largest_newly_acked), + packets_acked, &lost_packets); + ASSERT_EQ(losses_expected.size(), lost_packets.size()); + for (size_t i = 0; i < losses_expected.size(); ++i) { + EXPECT_EQ(lost_packets[i].packet_number, + QuicPacketNumber(losses_expected[i])); + } + } + + MockClock clock_; + std::unique_ptr<QuicUnackedPacketMap> unacked_packets_; + RttStats rtt_stats_; + UberLossAlgorithm loss_algorithm_; + AckedPacketVector packets_acked_; +}; + +TEST_F(UberLossAlgorithmTest, ScenarioA) { + // This test mimics a scenario: client sends 1-CHLO, 2-0RTT, 3-0RTT, + // timeout and retransmits 4-CHLO. Server acks packet 1 (ack gets lost). + // Server receives and buffers packets 2 and 3. Server receives packet 4 and + // processes handshake asynchronously, so server acks 4 and cannot process + // packets 2 and 3. + SendPacket(1, ENCRYPTION_NONE); + SendPacket(2, ENCRYPTION_ZERO_RTT); + SendPacket(3, ENCRYPTION_ZERO_RTT); + unacked_packets_->RemoveFromInFlight(QuicPacketNumber(1)); + SendPacket(4, ENCRYPTION_NONE); + + AckPackets({1, 4}); + unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_NONE, QuicPacketNumber(4)); + // Verify no packet is detected lost. + VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); +} + +TEST_F(UberLossAlgorithmTest, ScenarioB) { + // This test mimics a scenario: client sends 3-0RTT, 4-0RTT, receives SHLO, + // sends 5-1RTT, 6-1RTT. + SendPacket(3, ENCRYPTION_ZERO_RTT); + SendPacket(4, ENCRYPTION_ZERO_RTT); + SendPacket(5, ENCRYPTION_FORWARD_SECURE); + SendPacket(6, ENCRYPTION_FORWARD_SECURE); + + AckPackets({4}); + unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_ZERO_RTT, QuicPacketNumber(4)); + // No packet loss by acking 4. + VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + + // Acking 6 causes 3 to be detected loss. + AckPackets({6}); + unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(6)); + VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3}); + EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout()); + packets_acked_.clear(); + + clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt()); + // Verify 5 will be early retransmitted. + VerifyLosses(6, packets_acked_, {5}); +} + +TEST_F(UberLossAlgorithmTest, ScenarioC) { + // This test mimics a scenario: server sends 1-SHLO, 2-1RTT, 3-1RTT, 4-1RTT + // and retransmit 4-SHLO. Client receives and buffers packet 4. Client + // receives packet 5 and processes 4. + QuicUnackedPacketMapPeer::SetPerspective(unacked_packets_.get(), + Perspective::IS_SERVER); + SendPacket(1, ENCRYPTION_ZERO_RTT); + SendPacket(2, ENCRYPTION_FORWARD_SECURE); + SendPacket(3, ENCRYPTION_FORWARD_SECURE); + SendPacket(4, ENCRYPTION_FORWARD_SECURE); + unacked_packets_->RemoveFromInFlight(QuicPacketNumber(1)); + SendPacket(5, ENCRYPTION_ZERO_RTT); + + AckPackets({4, 5}); + unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_FORWARD_SECURE, QuicPacketNumber(4)); + unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace( + ENCRYPTION_ZERO_RTT, QuicPacketNumber(5)); + // No packet loss by acking 5. + VerifyLosses(5, packets_acked_, std::vector<uint64_t>{}); + EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), + loss_algorithm_.GetLossTimeout()); + packets_acked_.clear(); + + clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt()); + // Verify 2 and 3 will be early retransmitted. + VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3}); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/crypto/aead_base_decrypter.cc b/quic/core/crypto/aead_base_decrypter.cc index 51cfa26..53bd0f0 100644 --- a/quic/core/crypto/aead_base_decrypter.cc +++ b/quic/core/crypto/aead_base_decrypter.cc
@@ -141,8 +141,7 @@ return true; } -bool AeadBaseDecrypter::DecryptPacket(QuicTransportVersion /*version*/, - uint64_t packet_number, +bool AeadBaseDecrypter::DecryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/quic/core/crypto/aead_base_decrypter.h b/quic/core/crypto/aead_base_decrypter.h index b4906b8..d374722 100644 --- a/quic/core/crypto/aead_base_decrypter.h +++ b/quic/core/crypto/aead_base_decrypter.h
@@ -35,8 +35,7 @@ bool SetIV(QuicStringPiece iv) override; bool SetPreliminaryKey(QuicStringPiece key) override; bool SetDiversificationNonce(const DiversificationNonce& nonce) override; - bool DecryptPacket(QuicTransportVersion version, - uint64_t packet_number, + bool DecryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.cc b/quic/core/crypto/aead_base_encrypter.cc index 199851e..405292e 100644 --- a/quic/core/crypto/aead_base_encrypter.cc +++ b/quic/core/crypto/aead_base_encrypter.cc
@@ -123,8 +123,7 @@ return true; } -bool AeadBaseEncrypter::EncryptPacket(QuicTransportVersion /*version*/, - uint64_t packet_number, +bool AeadBaseEncrypter::EncryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/quic/core/crypto/aead_base_encrypter.h b/quic/core/crypto/aead_base_encrypter.h index 255bd87..316d24e 100644 --- a/quic/core/crypto/aead_base_encrypter.h +++ b/quic/core/crypto/aead_base_encrypter.h
@@ -33,8 +33,7 @@ bool SetKey(QuicStringPiece key) override; bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; bool SetIV(QuicStringPiece iv) override; - bool EncryptPacket(QuicTransportVersion version, - uint64_t packet_number, + bool EncryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc index eb2fa5e..6513e45 100644 --- a/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc +++ b/quic/core/crypto/aes_128_gcm_12_decrypter_test.cc
@@ -212,8 +212,8 @@ std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicTransportVersionMax(), packet_number, associated_data, ciphertext, - output.get(), &output_length, ciphertext.length()); + packet_number, associated_data, ciphertext, output.get(), &output_length, + ciphertext.length()); if (!success) { return nullptr; }
diff --git a/quic/core/crypto/aes_128_gcm_decrypter_test.cc b/quic/core/crypto/aes_128_gcm_decrypter_test.cc index ef66204..300e8a2 100644 --- a/quic/core/crypto/aes_128_gcm_decrypter_test.cc +++ b/quic/core/crypto/aes_128_gcm_decrypter_test.cc
@@ -206,9 +206,9 @@ decrypter->SetIV(nonce); std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; - const bool success = decrypter->DecryptPacket( - QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), - &output_length, ciphertext.length()); + const bool success = + decrypter->DecryptPacket(0, associated_data, ciphertext, output.get(), + &output_length, ciphertext.length()); if (!success) { return nullptr; }
diff --git a/quic/core/crypto/aes_128_gcm_encrypter_test.cc b/quic/core/crypto/aes_128_gcm_encrypter_test.cc index 79276ca..959cb9d 100644 --- a/quic/core/crypto/aes_128_gcm_encrypter_test.cc +++ b/quic/core/crypto/aes_128_gcm_encrypter_test.cc
@@ -233,8 +233,8 @@ Aes128GcmEncrypter encrypter; ASSERT_TRUE(encrypter.SetKey(key)); ASSERT_TRUE(encrypter.SetIV(iv)); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_43, packet_num, aad, pt, - out.data(), &out_size, out.size())); + ASSERT_TRUE(encrypter.EncryptPacket(packet_num, aad, pt, out.data(), + &out_size, out.size())); EXPECT_EQ(out_size, out.size()); test::CompareCharArraysWithHexError("ciphertext", out.data(), out.size(), ct.data(), ct.size());
diff --git a/quic/core/crypto/aes_256_gcm_decrypter_test.cc b/quic/core/crypto/aes_256_gcm_decrypter_test.cc index b25b66b..cb5f702 100644 --- a/quic/core/crypto/aes_256_gcm_decrypter_test.cc +++ b/quic/core/crypto/aes_256_gcm_decrypter_test.cc
@@ -210,9 +210,9 @@ decrypter->SetIV(nonce); std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; - const bool success = decrypter->DecryptPacket( - QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), - &output_length, ciphertext.length()); + const bool success = + decrypter->DecryptPacket(0, associated_data, ciphertext, output.get(), + &output_length, ciphertext.length()); if (!success) { return nullptr; }
diff --git a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc index a0c3cbe..5f5ae01 100644 --- a/quic/core/crypto/chacha20_poly1305_decrypter_test.cc +++ b/quic/core/crypto/chacha20_poly1305_decrypter_test.cc
@@ -125,8 +125,8 @@ std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; const bool success = decrypter->DecryptPacket( - QuicTransportVersionMax(), packet_number, associated_data, ciphertext, - output.get(), &output_length, ciphertext.length()); + packet_number, associated_data, ciphertext, output.get(), &output_length, + ciphertext.length()); if (!success) { return nullptr; }
diff --git a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc index 8d9a900..d8c27bf 100644 --- a/quic/core/crypto/chacha20_poly1305_encrypter_test.cc +++ b/quic/core/crypto/chacha20_poly1305_encrypter_test.cc
@@ -101,14 +101,14 @@ QuicString plaintext = "plaintext"; char encrypted[1024]; size_t len; - ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number, - associated_data, plaintext, encrypted, - &len, QUIC_ARRAYSIZE(encrypted))); + ASSERT_TRUE(encrypter.EncryptPacket(packet_number, associated_data, plaintext, + encrypted, &len, + QUIC_ARRAYSIZE(encrypted))); QuicStringPiece ciphertext(encrypted, len); char decrypted[1024]; - ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number, - associated_data, ciphertext, decrypted, - &len, QUIC_ARRAYSIZE(decrypted))); + ASSERT_TRUE(decrypter.DecryptPacket(packet_number, associated_data, + ciphertext, decrypted, &len, + QUIC_ARRAYSIZE(decrypted))); } TEST_F(ChaCha20Poly1305EncrypterTest, Encrypt) {
diff --git a/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc index 824c2dd..dd74539 100644 --- a/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc +++ b/quic/core/crypto/chacha20_poly1305_tls_decrypter_test.cc
@@ -119,9 +119,9 @@ decrypter->SetIV(nonce); std::unique_ptr<char[]> output(new char[ciphertext.length()]); size_t output_length = 0; - const bool success = decrypter->DecryptPacket( - QuicTransportVersionMax(), 0, associated_data, ciphertext, output.get(), - &output_length, ciphertext.length()); + const bool success = + decrypter->DecryptPacket(0, associated_data, ciphertext, output.get(), + &output_length, ciphertext.length()); if (!success) { return nullptr; }
diff --git a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc index bc7c6c4..905472b 100644 --- a/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc +++ b/quic/core/crypto/chacha20_poly1305_tls_encrypter_test.cc
@@ -100,14 +100,14 @@ QuicString plaintext = "plaintext"; char encrypted[1024]; size_t len; - ASSERT_TRUE(encrypter.EncryptPacket(QuicTransportVersionMax(), packet_number, - associated_data, plaintext, encrypted, - &len, QUIC_ARRAYSIZE(encrypted))); + ASSERT_TRUE(encrypter.EncryptPacket(packet_number, associated_data, plaintext, + encrypted, &len, + QUIC_ARRAYSIZE(encrypted))); QuicStringPiece ciphertext(encrypted, len); char decrypted[1024]; - ASSERT_TRUE(decrypter.DecryptPacket(QuicTransportVersionMax(), packet_number, - associated_data, ciphertext, decrypted, - &len, QUIC_ARRAYSIZE(decrypted))); + ASSERT_TRUE(decrypter.DecryptPacket(packet_number, associated_data, + ciphertext, decrypted, &len, + QUIC_ARRAYSIZE(decrypted))); } TEST_F(ChaCha20Poly1305TlsEncrypterTest, Encrypt) {
diff --git a/quic/core/crypto/crypto_message_printer_bin.cc b/quic/core/crypto/crypto_message_printer_bin.cc index f70c1c2..f14abb0 100644 --- a/quic/core/crypto/crypto_message_printer_bin.cc +++ b/quic/core/crypto/crypto_message_printer_bin.cc
@@ -1,3 +1,7 @@ +// 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. + // Dumps the contents of a QUIC crypto handshake message in a human readable // format. //
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index 5795119..b6a1e90 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -261,9 +261,6 @@ // Universal tags const QuicTag kPAD = TAG('P', 'A', 'D', '\0'); // Padding -// Server push tags -const QuicTag kSPSH = TAG('S', 'P', 'S', 'H'); // Support server push. - // Stats collection tags const QuicTag kEPID = TAG('E', 'P', 'I', 'D'); // Endpoint identifier.
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc index c2c4041..4ed169e 100644 --- a/quic/core/crypto/crypto_server_test.cc +++ b/quic/core/crypto/crypto_server_test.cc
@@ -236,7 +236,7 @@ void ShouldSucceed(const CryptoHandshakeMessage& message) { bool called = false; - QuicSocketAddress server_address; + QuicSocketAddress server_address(QuicIpAddress::Any4(), 5); config_.ValidateClientHello( message, client_address_.host(), server_address, supported_versions_.front().transport_version, &clock_, signed_config_, @@ -254,7 +254,7 @@ void ShouldFailMentioning(const char* error_substr, const CryptoHandshakeMessage& message, bool* called) { - QuicSocketAddress server_address; + QuicSocketAddress server_address(QuicIpAddress::Any4(), 5); config_.ValidateClientHello( message, client_address_.host(), server_address, supported_versions_.front().transport_version, &clock_, signed_config_, @@ -312,7 +312,7 @@ QuicReferenceCountedPointer<ValidateCallback::Result> result, bool should_succeed, const char* error_substr) { - QuicSocketAddress server_address; + QuicSocketAddress server_address(QuicIpAddress::Any4(), 5); QuicConnectionId server_designated_connection_id = TestConnectionId(rand_for_id_generation_.RandUint64()); bool called; @@ -415,9 +415,8 @@ std::unique_ptr<CryptoHandshakeMessage> server_config_; }; -INSTANTIATE_TEST_CASE_P(CryptoServerTests, - CryptoServerTest, - ::testing::ValuesIn(GetTestParams())); +INSTANTIATE_TEST_SUITE_P(CryptoServerTests, CryptoServerTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(CryptoServerTest, BadSNI) { // clang-format off
diff --git a/quic/core/crypto/crypto_utils.cc b/quic/core/crypto/crypto_utils.cc index 46d172f..4f6a61d 100644 --- a/quic/core/crypto/crypto_utils.cc +++ b/quic/core/crypto/crypto_utils.cc
@@ -107,24 +107,10 @@ std::vector<uint8_t> handshake_secret; handshake_secret.resize(EVP_MAX_MD_SIZE); size_t handshake_secret_len; - bool hkdf_extract_success; - if (!QuicConnectionIdSupportsVariableLength(perspective)) { - uint64_t connection_id64 = QuicConnectionIdToUInt64(connection_id); - uint8_t connection_id_bytes[sizeof(connection_id64)]; - for (size_t i = 0; i < sizeof(connection_id64); ++i) { - connection_id_bytes[i] = - (connection_id64 >> ((sizeof(connection_id64) - i - 1) * 8)) & 0xff; - } - hkdf_extract_success = - HKDF_extract(handshake_secret.data(), &handshake_secret_len, hash, - connection_id_bytes, QUIC_ARRAYSIZE(connection_id_bytes), - kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt)); - } else { - hkdf_extract_success = HKDF_extract( - handshake_secret.data(), &handshake_secret_len, hash, - reinterpret_cast<const uint8_t*>(connection_id.data()), - connection_id.length(), kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt)); - } + const bool hkdf_extract_success = HKDF_extract( + handshake_secret.data(), &handshake_secret_len, hash, + reinterpret_cast<const uint8_t*>(connection_id.data()), + connection_id.length(), kInitialSalt, QUIC_ARRAYSIZE(kInitialSalt)); QUIC_BUG_IF(!hkdf_extract_success) << "HKDF_extract failed when creating initial crypters"; handshake_secret.resize(handshake_secret_len);
diff --git a/quic/core/crypto/null_decrypter.cc b/quic/core/crypto/null_decrypter.cc index 0c108b6..288d3c4 100644 --- a/quic/core/crypto/null_decrypter.cc +++ b/quic/core/crypto/null_decrypter.cc
@@ -38,8 +38,7 @@ return true; } -bool NullDecrypter::DecryptPacket(QuicTransportVersion version, - uint64_t /*packet_number*/, +bool NullDecrypter::DecryptPacket(uint64_t /*packet_number*/, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output, @@ -58,7 +57,7 @@ QUIC_BUG << "Output buffer must be larger than the plaintext."; return false; } - if (hash != ComputeHash(version, associated_data, plaintext)) { + if (hash != ComputeHash(associated_data, plaintext)) { return false; } // Copy the plaintext to output. @@ -97,21 +96,15 @@ return true; } -QuicUint128 NullDecrypter::ComputeHash(QuicTransportVersion version, - const QuicStringPiece data1, +QuicUint128 NullDecrypter::ComputeHash(const QuicStringPiece data1, const QuicStringPiece data2) const { QuicUint128 correct_hash; - if (version > QUIC_VERSION_35) { - if (perspective_ == Perspective::IS_CLIENT) { - // Peer is a server. - correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Server"); - - } else { - // Peer is a client. - correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Client"); - } + if (perspective_ == Perspective::IS_CLIENT) { + // Peer is a server. + correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Server"); } else { - correct_hash = QuicUtils::FNV1a_128_Hash_Two(data1, data2); + // Peer is a client. + correct_hash = QuicUtils::FNV1a_128_Hash_Three(data1, data2, "Client"); } QuicUint128 mask = MakeQuicUint128(UINT64_C(0x0), UINT64_C(0xffffffff)); mask <<= 96;
diff --git a/quic/core/crypto/null_decrypter.h b/quic/core/crypto/null_decrypter.h index 3996eb7..8381987 100644 --- a/quic/core/crypto/null_decrypter.h +++ b/quic/core/crypto/null_decrypter.h
@@ -35,8 +35,7 @@ bool SetIV(QuicStringPiece iv) override; bool SetPreliminaryKey(QuicStringPiece key) override; bool SetDiversificationNonce(const DiversificationNonce& nonce) override; - bool DecryptPacket(QuicTransportVersion version, - uint64_t packet_number, + bool DecryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output, @@ -51,9 +50,7 @@ private: bool ReadHash(QuicDataReader* reader, QuicUint128* hash); - QuicUint128 ComputeHash(QuicTransportVersion version, - QuicStringPiece data1, - QuicStringPiece data2) const; + QuicUint128 ComputeHash(QuicStringPiece data1, QuicStringPiece data2) const; Perspective perspective_; };
diff --git a/quic/core/crypto/null_decrypter_test.cc b/quic/core/crypto/null_decrypter_test.cc index dd62a5c..09b1aaf 100644 --- a/quic/core/crypto/null_decrypter_test.cc +++ b/quic/core/crypto/null_decrypter_test.cc
@@ -15,18 +15,35 @@ TEST_F(NullDecrypterTest, DecryptClient) { unsigned char expected[] = { // fnv hash - 0x97, 0xdc, 0x27, 0x2f, 0x18, 0xa8, 0x56, 0x73, 0xdf, 0x8d, 0x1d, 0xd0, + 0x97, + 0xdc, + 0x27, + 0x2f, + 0x18, + 0xa8, + 0x56, + 0x73, + 0xdf, + 0x8d, + 0x1d, + 0xd0, // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + 'g', + 'o', + 'o', + 'd', + 'b', + 'y', + 'e', + '!', }; const char* data = reinterpret_cast<const char*>(expected); size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_SERVER); char buffer[256]; size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_39, 0, "hello world!", - QuicStringPiece(data, len), buffer, - &length, 256)); + ASSERT_TRUE(decrypter.DecryptPacket( + 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256)); EXPECT_LT(0u, length); EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); } @@ -34,56 +51,35 @@ TEST_F(NullDecrypterTest, DecryptServer) { unsigned char expected[] = { // fnv hash - 0x63, 0x5e, 0x08, 0x03, 0x32, 0x80, 0x8f, 0x73, 0xdf, 0x8d, 0x1d, 0x1a, + 0x63, + 0x5e, + 0x08, + 0x03, + 0x32, + 0x80, + 0x8f, + 0x73, + 0xdf, + 0x8d, + 0x1d, + 0x1a, // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + 'g', + 'o', + 'o', + 'd', + 'b', + 'y', + 'e', + '!', }; const char* data = reinterpret_cast<const char*>(expected); size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_39, 0, "hello world!", - QuicStringPiece(data, len), buffer, - &length, 256)); - EXPECT_LT(0u, length); - EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); -} - -TEST_F(NullDecrypterTest, DecryptClientPre37) { - unsigned char expected[] = { - // fnv hash - 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, - // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', - }; - const char* data = reinterpret_cast<const char*>(expected); - size_t len = QUIC_ARRAYSIZE(expected); - NullDecrypter decrypter(Perspective::IS_CLIENT); - char buffer[256]; - size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", - QuicStringPiece(data, len), buffer, - &length, 256)); - EXPECT_LT(0u, length); - EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); -} - -TEST_F(NullDecrypterTest, DecryptServerPre37) { - unsigned char expected[] = { - // fnv hash - 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, - // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', - }; - const char* data = reinterpret_cast<const char*>(expected); - size_t len = QUIC_ARRAYSIZE(expected); - NullDecrypter decrypter(Perspective::IS_SERVER); - char buffer[256]; - size_t length = 0; - ASSERT_TRUE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", - QuicStringPiece(data, len), buffer, - &length, 256)); + ASSERT_TRUE(decrypter.DecryptPacket( + 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256)); EXPECT_LT(0u, length); EXPECT_EQ("goodbye!", QuicStringPiece(buffer, length)); } @@ -91,18 +87,35 @@ TEST_F(NullDecrypterTest, BadHash) { unsigned char expected[] = { // fnv hash - 0x46, 0x11, 0xea, 0x5f, 0xcf, 0x1d, 0x66, 0x5b, 0xba, 0xf0, 0xbc, 0xfd, + 0x46, + 0x11, + 0xea, + 0x5f, + 0xcf, + 0x1d, + 0x66, + 0x5b, + 0xba, + 0xf0, + 0xbc, + 0xfd, // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + 'g', + 'o', + 'o', + 'd', + 'b', + 'y', + 'e', + '!', }; const char* data = reinterpret_cast<const char*>(expected); size_t len = QUIC_ARRAYSIZE(expected); NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; - ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", - QuicStringPiece(data, len), buffer, - &length, 256)); + ASSERT_FALSE(decrypter.DecryptPacket( + 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256)); } TEST_F(NullDecrypterTest, ShortInput) { @@ -115,9 +128,8 @@ NullDecrypter decrypter(Perspective::IS_CLIENT); char buffer[256]; size_t length = 0; - ASSERT_FALSE(decrypter.DecryptPacket(QUIC_VERSION_35, 0, "hello world!", - QuicStringPiece(data, len), buffer, - &length, 256)); + ASSERT_FALSE(decrypter.DecryptPacket( + 0, "hello world!", QuicStringPiece(data, len), buffer, &length, 256)); } } // namespace test
diff --git a/quic/core/crypto/null_encrypter.cc b/quic/core/crypto/null_encrypter.cc index e4a165f..9819a31 100644 --- a/quic/core/crypto/null_encrypter.cc +++ b/quic/core/crypto/null_encrypter.cc
@@ -26,8 +26,7 @@ return iv.empty(); } -bool NullEncrypter::EncryptPacket(QuicTransportVersion version, - uint64_t /*packet_number*/, +bool NullEncrypter::EncryptPacket(uint64_t /*packet_number*/, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output, @@ -38,16 +37,12 @@ return false; } QuicUint128 hash; - if (version > QUIC_VERSION_35) { - if (perspective_ == Perspective::IS_SERVER) { - hash = - QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Server"); - } else { - hash = - QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Client"); - } + if (perspective_ == Perspective::IS_SERVER) { + hash = + QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Server"); } else { - hash = QuicUtils::FNV1a_128_Hash_Two(associated_data, plaintext); + hash = + QuicUtils::FNV1a_128_Hash_Three(associated_data, plaintext, "Client"); } // TODO(ianswett): memmove required for in place encryption. Placing the // hash at the end would allow use of memcpy, doing nothing for in place.
diff --git a/quic/core/crypto/null_encrypter.h b/quic/core/crypto/null_encrypter.h index 01ecd45..fe4487d 100644 --- a/quic/core/crypto/null_encrypter.h +++ b/quic/core/crypto/null_encrypter.h
@@ -29,8 +29,7 @@ bool SetKey(QuicStringPiece key) override; bool SetNoncePrefix(QuicStringPiece nonce_prefix) override; bool SetIV(QuicStringPiece iv) override; - bool EncryptPacket(QuicTransportVersion version, - uint64_t packet_number, + bool EncryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/quic/core/crypto/null_encrypter_test.cc b/quic/core/crypto/null_encrypter_test.cc index 6dd4c98..fd95cc6 100644 --- a/quic/core/crypto/null_encrypter_test.cc +++ b/quic/core/crypto/null_encrypter_test.cc
@@ -15,16 +15,33 @@ TEST_F(NullEncrypterTest, EncryptClient) { unsigned char expected[] = { // fnv hash - 0x97, 0xdc, 0x27, 0x2f, 0x18, 0xa8, 0x56, 0x73, 0xdf, 0x8d, 0x1d, 0xd0, + 0x97, + 0xdc, + 0x27, + 0x2f, + 0x18, + 0xa8, + 0x56, + 0x73, + 0xdf, + 0x8d, + 0x1d, + 0xd0, // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + 'g', + 'o', + 'o', + 'd', + 'b', + 'y', + 'e', + '!', }; char encrypted[256]; size_t encrypted_len = 0; NullEncrypter encrypter(Perspective::IS_CLIENT); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_39, 0, "hello world!", - "goodbye!", encrypted, &encrypted_len, - 256)); + ASSERT_TRUE(encrypter.EncryptPacket(0, "hello world!", "goodbye!", encrypted, + &encrypted_len, 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); @@ -33,52 +50,33 @@ TEST_F(NullEncrypterTest, EncryptServer) { unsigned char expected[] = { // fnv hash - 0x63, 0x5e, 0x08, 0x03, 0x32, 0x80, 0x8f, 0x73, 0xdf, 0x8d, 0x1d, 0x1a, + 0x63, + 0x5e, + 0x08, + 0x03, + 0x32, + 0x80, + 0x8f, + 0x73, + 0xdf, + 0x8d, + 0x1d, + 0x1a, // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', + 'g', + 'o', + 'o', + 'd', + 'b', + 'y', + 'e', + '!', }; char encrypted[256]; size_t encrypted_len = 0; NullEncrypter encrypter(Perspective::IS_SERVER); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_39, 0, "hello world!", - "goodbye!", encrypted, &encrypted_len, - 256)); - test::CompareCharArraysWithHexError( - "encrypted data", encrypted, encrypted_len, - reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); -} - -TEST_F(NullEncrypterTest, EncryptClientPre37) { - unsigned char expected[] = { - // fnv hash - 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, - // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', - }; - char encrypted[256]; - size_t encrypted_len = 0; - NullEncrypter encrypter(Perspective::IS_CLIENT); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_35, 0, "hello world!", - "goodbye!", encrypted, &encrypted_len, - 256)); - test::CompareCharArraysWithHexError( - "encrypted data", encrypted, encrypted_len, - reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected)); -} - -TEST_F(NullEncrypterTest, EncryptServerPre37) { - unsigned char expected[] = { - // fnv hash - 0xa0, 0x6f, 0x44, 0x8a, 0x44, 0xf8, 0x18, 0x3b, 0x47, 0x91, 0xb2, 0x13, - // payload - 'g', 'o', 'o', 'd', 'b', 'y', 'e', '!', - }; - char encrypted[256]; - size_t encrypted_len = 0; - NullEncrypter encrypter(Perspective::IS_SERVER); - ASSERT_TRUE(encrypter.EncryptPacket(QUIC_VERSION_35, 0, "hello world!", - "goodbye!", encrypted, &encrypted_len, - 256)); + ASSERT_TRUE(encrypter.EncryptPacket(0, "hello world!", "goodbye!", encrypted, + &encrypted_len, 256)); test::CompareCharArraysWithHexError( "encrypted data", encrypted, encrypted_len, reinterpret_cast<const char*>(expected), QUIC_ARRAYSIZE(expected));
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc index 56447bb..0bf1b41 100644 --- a/quic/core/crypto/quic_crypto_client_config.cc +++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -657,14 +657,7 @@ const QuicData& client_hello_serialized = out->GetSerialized(); hkdf_input.append(QuicCryptoConfig::kCETVLabel, strlen(QuicCryptoConfig::kCETVLabel) + 1); - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) { - const uint64_t connection_id64_net = - QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)); - hkdf_input.append(reinterpret_cast<const char*>(&connection_id64_net), - sizeof(connection_id64_net)); - } else { hkdf_input.append(connection_id.data(), connection_id.length()); - } hkdf_input.append(client_hello_serialized.data(), client_hello_serialized.length()); hkdf_input.append(cached->server_config()); @@ -696,8 +689,7 @@ std::unique_ptr<char[]> output(new char[encrypted_len]); size_t output_size = 0; if (!crypters.encrypter->EncryptPacket( - preferred_version.transport_version, 0 /* packet number */, - QuicStringPiece() /* associated data */, + 0 /* packet number */, QuicStringPiece() /* associated data */, cetv_plaintext.AsStringPiece(), output.get(), &output_size, encrypted_len)) { *error_details = "Packet encryption failed"; @@ -715,16 +707,8 @@ // out_params->hkdf_input_suffix // out_params->initial_crypters out_params->hkdf_input_suffix.clear(); - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) { - const uint64_t connection_id64_net = - QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)); - out_params->hkdf_input_suffix.append( - reinterpret_cast<const char*>(&connection_id64_net), - sizeof(connection_id64_net)); - } else { out_params->hkdf_input_suffix.append(connection_id.data(), connection_id.length()); - } const QuicData& client_hello_serialized = out->GetSerialized(); out_params->hkdf_input_suffix.append(client_hello_serialized.data(), client_hello_serialized.length()); @@ -857,15 +841,7 @@ if (rej.tag() == kSREJ) { QuicConnectionId connection_id; - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) { - uint64_t connection_id64; - if (rej.GetUint64(kRCID, &connection_id64) != QUIC_NO_ERROR) { - *error_details = "Missing kRCID"; - return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND; - } - connection_id64 = QuicEndian::NetToHost64(connection_id64); - connection_id = QuicConnectionIdFromUInt64(connection_id64); - } else { + QuicStringPiece connection_id_bytes; if (!rej.GetStringPiece(kRCID, &connection_id_bytes)) { *error_details = "Missing kRCID"; @@ -880,7 +856,6 @@ *error_details = "Bad kRCID length"; return QUIC_CRYPTO_INTERNAL_ERROR; } - } cached->add_server_designated_connection_id(connection_id); if (!nonce.empty()) { cached->add_server_nonce(QuicString(nonce));
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc index 851f8e3..af67166 100644 --- a/quic/core/crypto/quic_crypto_server_config.cc +++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -77,7 +77,7 @@ std::unique_ptr<KeyExchange> Create(QuicString /*server_config_id*/, QuicTag type, - QuicStringPiece private_key) { + QuicStringPiece private_key) override { if (private_key.empty()) { QUIC_LOG(WARNING) << "Server config contains key exchange method without " "corresponding private key: " @@ -876,10 +876,6 @@ << "ProcessClientHelloAfterGetProof: attempted to use connection ID " << connection_id << " which is invalid with version " << QuicVersionToString(version.transport_version); - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { - connection_id = QuicConnectionIdFromUInt64( - QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id))); - } ProcessClientHelloHelper helper(&done_cb); if (found_error) { @@ -1020,21 +1016,10 @@ QuicString hkdf_suffix; const QuicData& client_hello_serialized = client_hello.GetSerialized(); - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { - // connection_id is already passed in in network byte order. - const uint64_t connection_id64_net = - QuicConnectionIdToUInt64(connection_id); - hkdf_suffix.reserve(sizeof(connection_id64_net) + - client_hello_serialized.length() + - requested_config->serialized.size()); - hkdf_suffix.append(reinterpret_cast<const char*>(&connection_id64_net), - sizeof(connection_id64_net)); - } else { hkdf_suffix.reserve(connection_id.length() + client_hello_serialized.length() + requested_config->serialized.size()); hkdf_suffix.append(connection_id.data(), connection_id.length()); - } hkdf_suffix.append(client_hello_serialized.data(), client_hello_serialized.length()); hkdf_suffix.append(requested_config->serialized); @@ -1057,15 +1042,7 @@ QuicString hkdf_input; hkdf_input.append(QuicCryptoConfig::kCETVLabel, strlen(QuicCryptoConfig::kCETVLabel) + 1); - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { - // connection_id is already passed in in network byte order. - const uint64_t connection_id64_net = - QuicConnectionIdToUInt64(connection_id); - hkdf_input.append(reinterpret_cast<const char*>(&connection_id64_net), - sizeof(connection_id64_net)); - } else { - hkdf_input.append(connection_id.data(), connection_id.length()); - } + hkdf_input.append(connection_id.data(), connection_id.length()); hkdf_input.append(client_hello_copy_serialized.data(), client_hello_copy_serialized.length()); hkdf_input.append(requested_config->serialized); @@ -1084,9 +1061,8 @@ char plaintext[kMaxPacketSize]; size_t plaintext_length = 0; const bool success = crypters.decrypter->DecryptPacket( - QUIC_VERSION_35, 0 /* packet number */, - QuicStringPiece() /* associated data */, cetv_ciphertext, plaintext, - &plaintext_length, kMaxPacketSize); + 0 /* packet number */, QuicStringPiece() /* associated data */, + cetv_ciphertext, plaintext, &plaintext_length, kMaxPacketSize); if (!success) { helper.Fail(QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER, "CETV decryption failure"); @@ -1613,10 +1589,6 @@ << "with server-designated connection ID " << server_designated_connection_id; out->set_tag(kSREJ); - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { - out->SetValue(kRCID, QuicEndian::HostToNet64(QuicConnectionIdToUInt64( - server_designated_connection_id))); - } else { if (!QuicUtils::IsConnectionIdValidForVersion( server_designated_connection_id, version)) { QUIC_BUG << "Tried to send server designated connection ID " @@ -1628,7 +1600,6 @@ out->SetStringPiece( kRCID, QuicStringPiece(server_designated_connection_id.data(), server_designated_connection_id.length())); - } } else { out->set_tag(kREJ); } @@ -2078,6 +2049,7 @@ bool QuicCryptoServerConfig::IsNextConfigReady(QuicWallTime now) const { if (GetQuicReloadableFlag(quic_fix_config_rotation)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_fix_config_rotation); return !next_config_promotion_time_.IsZero() && !next_config_promotion_time_.IsAfter(now); }
diff --git a/quic/core/crypto/quic_decrypter.h b/quic/core/crypto/quic_decrypter.h index 892504c..c7c2ccc 100644 --- a/quic/core/crypto/quic_decrypter.h +++ b/quic/core/crypto/quic_decrypter.h
@@ -53,8 +53,7 @@ // to form the nonce. // TODO(wtc): add a way for DecryptPacket to report decryption failure due // to non-authentic inputs, as opposed to other reasons for failure. - virtual bool DecryptPacket(QuicTransportVersion version, - uint64_t packet_number, + virtual bool DecryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output,
diff --git a/quic/core/crypto/quic_encrypter.h b/quic/core/crypto/quic_encrypter.h index 591021e..cb53e33 100644 --- a/quic/core/crypto/quic_encrypter.h +++ b/quic/core/crypto/quic_encrypter.h
@@ -34,8 +34,7 @@ // SetNoncePrefix() to form the nonce. |output| must not overlap with // |associated_data|. If |output| overlaps with |plaintext| then // |plaintext| must be <= |output|. - virtual bool EncryptPacket(QuicTransportVersion version, - uint64_t packet_number, + virtual bool EncryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output,
diff --git a/quic/core/frames/quic_ack_frame.cc b/quic/core/frames/quic_ack_frame.cc index 5f47b3f..389f1c0 100644 --- a/quic/core/frames/quic_ack_frame.cc +++ b/quic/core/frames/quic_ack_frame.cc
@@ -5,9 +5,9 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_ack_frame.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" namespace quic {
diff --git a/quic/core/frames/quic_ack_frame.h b/quic/core/frames/quic_ack_frame.h index 4dcfc3d..771d93e 100644 --- a/quic/core/frames/quic_ack_frame.h +++ b/quic/core/frames/quic_ack_frame.h
@@ -7,11 +7,11 @@ #include <ostream> +#include "net/third_party/quiche/src/quic/core/quic_interval.h" #include "net/third_party/quiche/src/quic/core/quic_types.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_interval.h" namespace quic {
diff --git a/quic/core/frames/quic_frames_test.cc b/quic/core/frames/quic_frames_test.cc index af9c40b..8099ccc 100644 --- a/quic/core/frames/quic_frames_test.cc +++ b/quic/core/frames/quic_frames_test.cc
@@ -14,8 +14,8 @@ #include "net/third_party/quiche/src/quic/core/frames/quic_stop_waiting_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" #include "net/third_party/quiche/src/quic/core/frames/quic_window_update_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
diff --git a/quic/core/frames/quic_message_frame.cc b/quic/core/frames/quic_message_frame.cc index 79a23fe..c0de272 100644 --- a/quic/core/frames/quic_message_frame.cc +++ b/quic/core/frames/quic_message_frame.cc
@@ -9,17 +9,20 @@ namespace quic { -QuicMessageFrame::QuicMessageFrame() : message_id(0) {} +QuicMessageFrame::QuicMessageFrame() + : message_id(0), data(nullptr), message_length(0) {} -QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id, - QuicStringPiece message_data) - : message_id(message_id), message_data(message_data) {} +QuicMessageFrame::QuicMessageFrame(QuicMessageId message_id) + : message_id(message_id), data(nullptr), message_length(0) {} + +QuicMessageFrame::QuicMessageFrame(const char* data, QuicPacketLength length) + : message_id(0), data(data), message_length(length) {} QuicMessageFrame::~QuicMessageFrame() {} std::ostream& operator<<(std::ostream& os, const QuicMessageFrame& s) { os << " message_id: " << s.message_id - << ", message_length: " << s.message_data.length() << " }\n"; + << ", message_length: " << s.message_length << " }\n"; return os; }
diff --git a/quic/core/frames/quic_message_frame.h b/quic/core/frames/quic_message_frame.h index 6458a11..4accff2 100644 --- a/quic/core/frames/quic_message_frame.h +++ b/quic/core/frames/quic_message_frame.h
@@ -6,14 +6,26 @@ #define QUICHE_QUIC_CORE_FRAMES_QUIC_MESSAGE_FRAME_H_ #include "net/third_party/quiche/src/quic/core/quic_types.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_mem_slice.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" namespace quic { +typedef QuicInlinedVector<QuicMemSlice, 1> QuicMessageData; + struct QUIC_EXPORT_PRIVATE QuicMessageFrame { QuicMessageFrame(); - QuicMessageFrame(QuicMessageId message_id, QuicStringPiece message_data); + explicit QuicMessageFrame(QuicMessageId message_id); + QuicMessageFrame(const char* data, QuicPacketLength length); + + QuicMessageFrame(const QuicMessageFrame& other) = delete; + QuicMessageFrame& operator=(const QuicMessageFrame& other) = delete; + + QuicMessageFrame(QuicMessageFrame&& other) = default; + QuicMessageFrame& operator=(QuicMessageFrame&& other) = default; + ~QuicMessageFrame(); friend QUIC_EXPORT_PRIVATE std::ostream& operator<<( @@ -23,8 +35,13 @@ // message_id is only used on the sender side and does not get serialized on // wire. QuicMessageId message_id; - // The actual data. - QuicString message_data; + // Not owned, only used on read path. + const char* data; + // Total length of message_data, must be fit into one packet. + QuicPacketLength message_length; + + // The actual message data which is reference counted, used on write path. + QuicMessageData message_data; }; } // namespace quic
diff --git a/quic/core/frames/quic_retire_connection_id_frame.cc b/quic/core/frames/quic_retire_connection_id_frame.cc index a507269..6828ce4 100644 --- a/quic/core/frames/quic_retire_connection_id_frame.cc +++ b/quic/core/frames/quic_retire_connection_id_frame.cc
@@ -1,3 +1,7 @@ +// 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. + #include "net/third_party/quiche/src/quic/core/frames/quic_retire_connection_id_frame.h" #include "net/third_party/quiche/src/quic/core/quic_constants.h"
diff --git a/quic/core/frames/quic_retire_connection_id_frame.h b/quic/core/frames/quic_retire_connection_id_frame.h index 7bce51c..79521f6 100644 --- a/quic/core/frames/quic_retire_connection_id_frame.h +++ b/quic/core/frames/quic_retire_connection_id_frame.h
@@ -1,3 +1,7 @@ +// 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_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_ #define QUICHE_QUIC_CORE_FRAMES_QUIC_RETIRE_CONNECTION_ID_FRAME_H_
diff --git a/quic/core/http/end_to_end_test.cc b/quic/core/http/end_to_end_test.cc index 132da8e..adf82c9 100644 --- a/quic/core/http/end_to_end_test.cc +++ b/quic/core/http/end_to_end_test.cc
@@ -10,8 +10,6 @@ #include <utility> #include <vector> -#include "gfe/gfe2/base/epoll_server.h" -#include "net/util/netutil.h" #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h" @@ -26,6 +24,7 @@ #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" +#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_sleep.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" @@ -139,18 +138,21 @@ ParsedQuicVersionVector all_supported_versions = FilterSupportedVersions(AllSupportedVersions()); - // Buckets are separated by the handshake protocol (QUIC crypto or TLS) in - // use, since if the handshake protocol changes, the ClientHello/CHLO must be + // Buckets are separated by versions: versions prior to QUIC_VERSION_47 use + // STREAM frames for the handshake, and only have QUIC crypto as the handshake + // protocol. Version 47 and greater use CRYPTO frames for the handshake, and + // must also be split based on the handshake protocol. If the handshake + // protocol (QUIC crypto or TLS) changes, the ClientHello/CHLO must be // reconstructed for the correct protocol. - ParsedQuicVersionVector version_buckets[2]; + ParsedQuicVersionVector version_buckets[3]; for (const ParsedQuicVersion& version : all_supported_versions) { - // Versions: 35+ - // QUIC_VERSION_35 allows endpoints to independently set stream limit. - if (version.handshake_protocol == PROTOCOL_TLS1_3) { + if (version.transport_version < QUIC_VERSION_47) { + version_buckets[0].push_back(version); + } else if (version.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { version_buckets[1].push_back(version); } else { - version_buckets[0].push_back(version); + version_buckets[2].push_back(version); } } @@ -273,7 +275,7 @@ : initialized_(false), connect_to_server_on_initialize_(true), server_address_( - QuicSocketAddress(TestLoopback(), net_util::PickUnusedPortOrDie())), + QuicSocketAddress(TestLoopback(), QuicPickUnusedPortOrDie())), server_hostname_("test.example.com"), client_writer_(nullptr), server_writer_(nullptr), @@ -313,9 +315,7 @@ AddToCache("/bar", 200, kBarResponseBody); } - ~EndToEndTest() override { - net_util::RecycleUnusedPort(server_address_.port()); - } + ~EndToEndTest() override { QuicRecyclePort(server_address_.port()); } virtual void CreateClientWithWriter() { client_.reset(CreateQuicClient(client_writer_)); @@ -404,9 +404,6 @@ copt.push_back(kTPCC); } - if (support_server_push_) { - copt.push_back(kSPSH); - } if (GetParam().client_supports_stateless_rejects) { copt.push_back(kSREJ); } @@ -602,13 +599,15 @@ } QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - *client_->client()->client_session(), n); + return GetNthClientInitiatedBidirectionalStreamId( + client_->client()->client_session()->connection()->transport_version(), + n); } QuicStreamId GetNthServerInitiatedBidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId( - *client_->client()->client_session(), n); + return GetNthServerInitiatedBidirectionalStreamId( + client_->client()->client_session()->connection()->transport_version(), + n); } ScopedEnvironmentForThreads environment_; @@ -639,21 +638,21 @@ }; // Run all end to end tests with all supported versions. -INSTANTIATE_TEST_CASE_P(EndToEndTests, - EndToEndTest, - ::testing::ValuesIn(GetTestParams(false, false))); +INSTANTIATE_TEST_SUITE_P(EndToEndTests, + EndToEndTest, + ::testing::ValuesIn(GetTestParams(false, false))); class EndToEndTestWithTls : public EndToEndTest {}; -INSTANTIATE_TEST_CASE_P(EndToEndTestsWithTls, - EndToEndTestWithTls, - ::testing::ValuesIn(GetTestParams(true, false))); +INSTANTIATE_TEST_SUITE_P(EndToEndTestsWithTls, + EndToEndTestWithTls, + ::testing::ValuesIn(GetTestParams(true, false))); class EndToEndTestWithStatelessReject : public EndToEndTest {}; -INSTANTIATE_TEST_CASE_P(WithStatelessReject, - EndToEndTestWithStatelessReject, - ::testing::ValuesIn(GetTestParams(false, true))); +INSTANTIATE_TEST_SUITE_P(WithStatelessReject, + EndToEndTestWithStatelessReject, + ::testing::ValuesIn(GetTestParams(false, true))); TEST_P(EndToEndTestWithTls, HandshakeSuccessful) { ASSERT_TRUE(Initialize()); @@ -709,25 +708,6 @@ client_->client()->GetNumSentClientHellos()); } -// TODO(dschinazi) remove this test once the flags are deprecated -TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDClient) { - SetQuicRestartFlag(quic_variable_length_connection_ids_client, true); - SetQuicRestartFlag(quic_variable_length_connection_ids_server, false); - ASSERT_TRUE(Initialize()); - - EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); - EXPECT_EQ("200", client_->response_headers()->find(":status")->second); - int expected_num_client_hellos = 2; - if (ServerSendsVersionNegotiation()) { - ++expected_num_client_hellos; - if (BothSidesSupportStatelessRejects()) { - ++expected_num_client_hellos; - } - } - EXPECT_EQ(expected_num_client_hellos, - client_->client()->GetNumSentClientHellos()); -} - TEST_P(EndToEndTest, SimpleRequestResponseZeroConnectionID) { QuicConnectionId connection_id = QuicUtils::CreateZeroConnectionId( GetParam().negotiated_version.transport_version); @@ -750,25 +730,6 @@ GetParam().negotiated_version.transport_version)); } -// TODO(dschinazi) remove this test once the flags are deprecated -TEST_P(EndToEndTest, SimpleRequestResponseVariableLengthConnectionIDServer) { - SetQuicRestartFlag(quic_variable_length_connection_ids_client, false); - SetQuicRestartFlag(quic_variable_length_connection_ids_server, true); - ASSERT_TRUE(Initialize()); - - EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); - EXPECT_EQ("200", client_->response_headers()->find(":status")->second); - int expected_num_client_hellos = 2; - if (ServerSendsVersionNegotiation()) { - ++expected_num_client_hellos; - if (BothSidesSupportStatelessRejects()) { - ++expected_num_client_hellos; - } - } - EXPECT_EQ(expected_num_client_hellos, - client_->client()->GetNumSentClientHellos()); -} - TEST_P(EndToEndTest, SimpleRequestResponseWithLargeReject) { chlo_multiplier_ = 1; ASSERT_TRUE(Initialize()); @@ -1360,7 +1321,7 @@ // Make sure that the stream has data pending so that it will be marked as // write blocked when it receives a stream level WINDOW_UPDATE. - stream->WriteOrBufferBody("hello", false, nullptr); + stream->WriteOrBufferBody("hello", false); // The stream now attempts to write, fails because it is still connection // level flow control blocked, and is added to the write blocked list. @@ -1949,7 +1910,7 @@ // Open a data stream to make sure the stream level flow control is updated. QuicSpdyClientStream* stream = client_->GetOrCreateStream(); - stream->WriteOrBufferBody("hello", false, nullptr); + stream->WriteOrBufferBody("hello", false); // Client should have the right values for server's receive window. EXPECT_EQ(kServerStreamIFCW, @@ -2005,7 +1966,7 @@ // Open a data stream to make sure the stream level flow control is updated. QuicSpdyClientStream* stream = client_->GetOrCreateStream(); - stream->WriteOrBufferBody("hello", false, nullptr); + stream->WriteOrBufferBody("hello", false); // Client should have the right values for server's receive window. EXPECT_EQ(kExpectedStreamIFCW, @@ -2045,9 +2006,14 @@ QuicCryptoStream* crypto_stream = QuicSessionPeer::GetMutableCryptoStream( client_->client()->client_session()); - EXPECT_LT( - QuicFlowControllerPeer::SendWindowSize(crypto_stream->flow_controller()), - kStreamIFCW); + // In v47 and later, the crypto handshake (sent in CRYPTO frames) is not + // subject to flow control. + if (client_->client()->client_session()->connection()->transport_version() < + QUIC_VERSION_47) { + EXPECT_LT(QuicFlowControllerPeer::SendWindowSize( + crypto_stream->flow_controller()), + kStreamIFCW); + } EXPECT_EQ(kSessionIFCW, QuicFlowControllerPeer::SendWindowSize( client_->client()->client_session()->flow_controller())); @@ -2223,20 +2189,9 @@ QuicString request_string = "a request body bigger than one packet" + QuicString(kMaxPacketSize, '.'); - // Calculate header length for version 99, so that the ack listener know how - // many actual bytes will be acked. - QuicByteCount header_length = 0; - if (client_->client()->client_session()->connection()->transport_version() == - QUIC_VERSION_99) { - HttpEncoder encoder; - std::unique_ptr<char[]> buf; - header_length = - encoder.SerializeDataFrameHeader(request_string.length(), &buf); - } - // The TestAckListener will cause a failure if not notified. QuicReferenceCountedPointer<TestAckListener> ack_listener( - new TestAckListener(request_string.length() + header_length)); + new TestAckListener(request_string.length())); // Send the request, and register the delegate for ACKs. client_->SendData(request_string, true, ack_listener); @@ -2875,9 +2830,9 @@ }; // Run all server push end to end tests with all supported versions. -INSTANTIATE_TEST_CASE_P(EndToEndTestsServerPush, - EndToEndTestServerPush, - ::testing::ValuesIn(GetTestParams(false, false))); +INSTANTIATE_TEST_SUITE_P(EndToEndTestsServerPush, + EndToEndTestServerPush, + ::testing::ValuesIn(GetTestParams(false, false))); TEST_P(EndToEndTestServerPush, ServerPush) { ASSERT_TRUE(Initialize()); @@ -3266,7 +3221,6 @@ QuicConnection* client_connection = client_->client()->client_session()->connection(); client_connection->set_debug_visitor(&observer); - QuicTransportVersion version = client_connection->transport_version(); // 100KB body. QuicString body(100 * 1024, 'a'); SpdyHeaderBlock headers; @@ -3278,12 +3232,8 @@ EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(headers, body)); client_->Disconnect(); - if (version != QUIC_VERSION_35) { - EXPECT_LT(0u, observer.num_window_update_frames()); - EXPECT_EQ(0u, observer.num_ping_frames()); - } else { - EXPECT_EQ(0u, observer.num_window_update_frames()); - } + EXPECT_LT(0u, observer.num_window_update_frames()); + EXPECT_EQ(0u, observer.num_ping_frames()); } TEST_P(EndToEndTest, SendStatelessResetTokenInShlo) { @@ -3506,13 +3456,12 @@ // 1 MB body. QuicString body(1024 * 1024, 'a'); - stream->WriteOrBufferBody(body, true, nullptr); + stream->WriteOrBufferBody(body, true); client_->WaitForResponse(); EXPECT_EQ(QUIC_STREAM_TTL_EXPIRED, client_->stream_error()); } TEST_P(EndToEndTest, SendMessages) { - SetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission, true); ASSERT_TRUE(Initialize()); EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed()); QuicSession* client_session = client_->client()->client_session(); @@ -3529,22 +3478,30 @@ QuicStringPiece message_buffer(message_string); QuicRandom* random = QuicConnectionPeer::GetHelper(client_connection)->GetRandomGenerator(); + QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); { QuicConnection::ScopedPacketFlusher flusher( client_session->connection(), QuicConnection::SEND_ACK_IF_PENDING); // Verify the largest message gets successfully sent. EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1), - client_session->SendMessage( + client_session->SendMessage(MakeSpan( + client_session->connection() + ->helper() + ->GetStreamSendBufferAllocator(), QuicStringPiece(message_buffer.data(), - client_session->GetLargestMessagePayload()))); + client_session->GetLargestMessagePayload()), + &storage))); // Send more messages with size (0, largest_payload] until connection is // write blocked. const int kTestMaxNumberOfMessages = 100; for (size_t i = 2; i <= kTestMaxNumberOfMessages; ++i) { size_t message_length = random->RandUint64() % client_session->GetLargestMessagePayload() + 1; - MessageResult result = client_session->SendMessage( - QuicStringPiece(message_buffer.data(), message_length)); + MessageResult result = client_session->SendMessage(MakeSpan( + client_session->connection() + ->helper() + ->GetStreamSendBufferAllocator(), + QuicStringPiece(message_buffer.data(), message_length), &storage)); if (result.status == MESSAGE_STATUS_BLOCKED) { // Connection is write blocked. break; @@ -3554,12 +3511,17 @@ } client_->WaitForDelayedAcks(); - EXPECT_EQ(MESSAGE_STATUS_TOO_LARGE, - client_session - ->SendMessage(QuicStringPiece( - message_buffer.data(), - client_session->GetLargestMessagePayload() + 1)) - .status); + EXPECT_EQ( + MESSAGE_STATUS_TOO_LARGE, + client_session + ->SendMessage(MakeSpan( + client_session->connection() + ->helper() + ->GetStreamSendBufferAllocator(), + QuicStringPiece(message_buffer.data(), + client_session->GetLargestMessagePayload() + 1), + &storage)) + .status); EXPECT_EQ(QUIC_NO_ERROR, client_->connection_error()); } @@ -3580,9 +3542,9 @@ PacketReorderingWriter* reorder_writer_; }; -INSTANTIATE_TEST_CASE_P(EndToEndPacketReorderingTests, - EndToEndPacketReorderingTest, - testing::ValuesIn(GetTestParams(false, false))); +INSTANTIATE_TEST_SUITE_P(EndToEndPacketReorderingTests, + EndToEndPacketReorderingTest, + testing::ValuesIn(GetTestParams(false, false))); TEST_P(EndToEndPacketReorderingTest, ReorderedConnectivityProbing) { ASSERT_TRUE(Initialize());
diff --git a/quic/core/http/http_decoder.cc b/quic/core/http/http_decoder.cc index 345f2cb..e697821 100644 --- a/quic/core/http/http_decoder.cc +++ b/quic/core/http/http_decoder.cc
@@ -22,7 +22,7 @@ } // Length of the type field of HTTP/3 frames. -static const size_t kFrameTypeLength = 1; +static const QuicByteCount kFrameTypeLength = 1; } // namespace @@ -40,9 +40,9 @@ HttpDecoder::~HttpDecoder() {} -size_t HttpDecoder::ProcessInput(const char* data, size_t len) { +QuicByteCount HttpDecoder::ProcessInput(const char* data, QuicByteCount len) { has_payload_ = false; - QuicDataReader reader(data, len, NETWORK_BYTE_ORDER); + QuicDataReader reader(data, len); while (error_ == QUIC_NO_ERROR && reader.BytesRemaining() != 0) { switch (state_) { case STATE_READING_FRAME_LENGTH: @@ -75,7 +75,7 @@ return; } QuicDataReader length_reader(length_buffer_.data(), - current_length_field_size_, NETWORK_BYTE_ORDER); + current_length_field_size_); if (!length_reader.ReadVarInt62(¤t_frame_length_)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame length"); visitor_->OnError(this); @@ -105,8 +105,8 @@ Http3FrameLengths(current_length_field_size_ + kFrameTypeLength, current_frame_length_)); } - size_t bytes_to_read = - std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicByteCount bytes_to_read = std::min<QuicByteCount>( + remaining_frame_length_, reader->BytesRemaining()); QuicStringPiece payload; if (!reader->ReadStringPiece(&payload, bytes_to_read)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data"); @@ -126,8 +126,8 @@ if (current_frame_length_ == remaining_frame_length_) { visitor_->OnHeadersFrameStart(); } - size_t bytes_to_read = - std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicByteCount bytes_to_read = std::min<QuicByteCount>( + remaining_frame_length_, reader->BytesRemaining()); QuicStringPiece payload; if (!reader->ReadStringPiece(&payload, bytes_to_read)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read data"); @@ -138,7 +138,7 @@ if (remaining_frame_length_ == 0) { state_ = STATE_READING_FRAME_LENGTH; current_length_field_size_ = 0; - visitor_->OnHeadersFrameEnd(); + visitor_->OnHeadersFrameEnd(current_frame_length_); } return; } @@ -148,8 +148,7 @@ BufferFramePayload(reader); if (remaining_frame_length_ == 0) { PriorityFrame frame; - QuicDataReader reader(buffer_.data(), current_frame_length_, - NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), current_frame_length_); if (!ParsePriorityFrame(&reader, &frame)) { return; } @@ -164,8 +163,7 @@ BufferFramePayload(reader); if (remaining_frame_length_ == 0) { CancelPushFrame frame; - QuicDataReader reader(buffer_.data(), current_frame_length_, - NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), current_frame_length_); if (!reader.ReadVarInt62(&frame.push_id)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id"); return; @@ -184,8 +182,7 @@ BufferFramePayload(reader); if (remaining_frame_length_ == 0) { SettingsFrame frame; - QuicDataReader reader(buffer_.data(), current_frame_length_, - NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), current_frame_length_); if (!ParseSettingsFrame(&reader, &frame)) { return; } @@ -197,7 +194,7 @@ } case 0x5: { // PUSH_PROMISE if (current_frame_length_ == remaining_frame_length_) { - size_t bytes_remaining = reader->BytesRemaining(); + QuicByteCount bytes_remaining = reader->BytesRemaining(); PushId push_id; // TODO(rch): Handle partial delivery of this field. if (!reader->ReadVarInt62(&push_id)) { @@ -207,8 +204,8 @@ remaining_frame_length_ -= bytes_remaining - reader->BytesRemaining(); visitor_->OnPushPromiseFrameStart(push_id); } - size_t bytes_to_read = - std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicByteCount bytes_to_read = std::min<QuicByteCount>( + remaining_frame_length_, reader->BytesRemaining()); if (bytes_to_read == 0) { return; } @@ -230,8 +227,7 @@ BufferFramePayload(reader); if (remaining_frame_length_ == 0) { GoAwayFrame frame; - QuicDataReader reader(buffer_.data(), current_frame_length_, - NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), current_frame_length_); uint64_t stream_id; if (!reader.ReadVarInt62(&stream_id)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read GOAWAY stream_id"); @@ -249,8 +245,7 @@ // TODO(rch): Handle partial delivery. BufferFramePayload(reader); if (remaining_frame_length_ == 0) { - QuicDataReader reader(buffer_.data(), current_frame_length_, - NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), current_frame_length_); MaxPushIdFrame frame; if (!reader.ReadVarInt62(&frame.push_id)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id"); @@ -268,8 +263,7 @@ if (remaining_frame_length_ != 0) { return; } - QuicDataReader reader(buffer_.data(), current_frame_length_, - NETWORK_BYTE_ORDER); + QuicDataReader reader(buffer_.data(), current_frame_length_); DuplicatePushFrame frame; if (!reader.ReadVarInt62(&frame.push_id)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read push_id"); @@ -305,8 +299,8 @@ } void HttpDecoder::DiscardFramePayload(QuicDataReader* reader) { - size_t bytes_to_read = - std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicByteCount bytes_to_read = std::min<QuicByteCount>( + remaining_frame_length_, reader->BytesRemaining()); QuicStringPiece payload; if (!reader->ReadStringPiece(&payload, bytes_to_read)) { RaiseError(QUIC_INTERNAL_ERROR, "Unable to read frame payload"); @@ -324,8 +318,8 @@ buffer_.erase(buffer_.size()); buffer_.reserve(current_frame_length_); } - size_t bytes_to_read = - std::min<size_t>(remaining_frame_length_, reader->BytesRemaining()); + QuicByteCount bytes_to_read = std::min<QuicByteCount>( + remaining_frame_length_, reader->BytesRemaining()); if (!reader->ReadBytes( &(buffer_[0]) + current_frame_length_ - remaining_frame_length_, bytes_to_read)) { @@ -349,8 +343,8 @@ length_buffer_.erase(length_buffer_.size()); length_buffer_.reserve(current_length_field_size_); } - size_t bytes_to_read = std::min<size_t>(remaining_length_field_length_, - reader->BytesRemaining()); + QuicByteCount bytes_to_read = std::min<QuicByteCount>( + remaining_length_field_length_, reader->BytesRemaining()); if (!reader->ReadBytes(&(length_buffer_[0]) + current_length_field_size_ - remaining_length_field_length_, bytes_to_read)) {
diff --git a/quic/core/http/http_decoder.h b/quic/core/http/http_decoder.h index a5f41b5..910d189 100644 --- a/quic/core/http/http_decoder.h +++ b/quic/core/http/http_decoder.h
@@ -9,6 +9,7 @@ #include "net/third_party/quiche/src/quic/core/http/http_frames.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/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" @@ -20,7 +21,7 @@ // |header_length| stores number of bytes header occupies. // |payload_length| stores number of bytes payload occupies. struct QUIC_EXPORT_PRIVATE Http3FrameLengths { - Http3FrameLengths(uint64_t header, uint64_t payload) + Http3FrameLengths(QuicByteCount header, QuicByteCount payload) : header_length(header), payload_length(payload) {} bool operator==(const Http3FrameLengths& other) const { @@ -76,7 +77,8 @@ // multiple times for a single frame. virtual void OnHeadersFramePayload(QuicStringPiece payload) = 0; // Called when a HEADERS frame has been completely processed. - virtual void OnHeadersFrameEnd() = 0; + // |frame_len| is the length of the HEADERS frame payload. + virtual void OnHeadersFrameEnd(QuicByteCount frame_len) = 0; // Called when a PUSH_PROMISE frame has been recevied for |push_id|. virtual void OnPushPromiseFrameStart(PushId push_id) = 0; @@ -104,7 +106,7 @@ // Processes the input and invokes the visitor for any frames. // Returns the number of bytes consumed, or 0 if there was an error, in which // case error() should be consulted. - size_t ProcessInput(const char* data, size_t len); + QuicByteCount ProcessInput(const char* data, QuicByteCount len); bool has_payload() { return has_payload_; } @@ -158,13 +160,13 @@ // Type of the frame currently being parsed. uint8_t current_frame_type_; // Size of the frame's length field. - uint64_t current_length_field_size_; + QuicByteCount current_length_field_size_; // Remaining length that's needed for the frame's length field. - uint64_t remaining_length_field_length_; + QuicByteCount remaining_length_field_length_; // Length of the payload of the frame currently being parsed. - uint64_t current_frame_length_; + QuicByteCount current_frame_length_; // Remaining payload bytes to be parsed. - uint64_t remaining_frame_length_; + QuicByteCount remaining_frame_length_; // Last error. QuicErrorCode error_; // The issue which caused |error_|
diff --git a/quic/core/http/http_decoder_test.cc b/quic/core/http/http_decoder_test.cc index c2b303c..c6d7d9f 100644 --- a/quic/core/http/http_decoder_test.cc +++ b/quic/core/http/http_decoder_test.cc
@@ -31,7 +31,7 @@ MOCK_METHOD0(OnHeadersFrameStart, void()); MOCK_METHOD1(OnHeadersFramePayload, void(QuicStringPiece payload)); - MOCK_METHOD0(OnHeadersFrameEnd, void()); + MOCK_METHOD1(OnHeadersFrameEnd, void(QuicByteCount frame_len)); MOCK_METHOD1(OnPushPromiseFrameStart, void(PushId push_id)); MOCK_METHOD1(OnPushPromiseFramePayload, void(QuicStringPiece payload)); @@ -84,7 +84,7 @@ TEST_F(HttpDecoderTest, ReservedFramesLargePayload) { for (int n = 0; n < 8; ++n) { const uint8_t type = 0xB + 0x1F * n; - const size_t payload_size = 256; + const QuicByteCount payload_size = 256; char input[payload_size + 3] = {// length 0x40 + 0x01, 0x00, // type @@ -383,7 +383,7 @@ InSequence s; EXPECT_CALL(visitor_, OnHeadersFrameStart()); EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("Headers"))); - EXPECT_CALL(visitor_, OnHeadersFrameEnd()); + EXPECT_CALL(visitor_, OnHeadersFrameEnd(7)); EXPECT_EQ(QUIC_ARRAYSIZE(input), decoder_.ProcessInput(input, QUIC_ARRAYSIZE(input))); EXPECT_EQ(QUIC_NO_ERROR, decoder_.error()); @@ -398,7 +398,7 @@ EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("e"))); EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("r"))); EXPECT_CALL(visitor_, OnHeadersFramePayload(QuicStringPiece("s"))); - EXPECT_CALL(visitor_, OnHeadersFrameEnd()); + EXPECT_CALL(visitor_, OnHeadersFrameEnd(7)); for (char c : input) { EXPECT_EQ(1u, decoder_.ProcessInput(&c, 1)); }
diff --git a/quic/core/http/http_encoder.cc b/quic/core/http/http_encoder.cc index 7c07838..d2d1699 100644 --- a/quic/core/http/http_encoder.cc +++ b/quic/core/http/http_encoder.cc
@@ -66,7 +66,7 @@ QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength; output->reset(new char[header_length]); - QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(header_length, output->get()); if (WriteFrameHeader(payload_length, HttpFrameType::DATA, &writer)) { return header_length; @@ -82,7 +82,7 @@ QuicDataWriter::GetVarInt62Len(payload_length) + kFrameTypeLength; output->reset(new char[header_length]); - QuicDataWriter writer(header_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(header_length, output->get()); if (WriteFrameHeader(payload_length, HttpFrameType::HEADERS, &writer)) { return header_length; @@ -101,7 +101,7 @@ QuicByteCount total_length = GetTotalLength(payload_length); output->reset(new char[total_length]); - QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(total_length, output->get()); if (!WriteFrameHeader(payload_length, HttpFrameType::PRIORITY, &writer)) { return 0; @@ -132,7 +132,7 @@ QuicByteCount total_length = GetTotalLength(payload_length); output->reset(new char[total_length]); - QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(total_length, output->get()); if (WriteFrameHeader(payload_length, HttpFrameType::CANCEL_PUSH, &writer) && writer.WriteVarInt62(cancel_push.push_id)) { @@ -154,7 +154,7 @@ QuicByteCount total_length = GetTotalLength(payload_length); output->reset(new char[total_length]); - QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(total_length, output->get()); if (!WriteFrameHeader(payload_length, HttpFrameType::SETTINGS, &writer)) { return 0; @@ -181,7 +181,7 @@ QuicDataWriter::GetVarInt62Len(push_promise.push_id); output->reset(new char[total_length]); - QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(total_length, output->get()); if (WriteFrameHeader(payload_length, HttpFrameType::PUSH_PROMISE, &writer) && writer.WriteVarInt62(push_promise.push_id)) { @@ -198,7 +198,7 @@ QuicByteCount total_length = GetTotalLength(payload_length); output->reset(new char[total_length]); - QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(total_length, output->get()); if (WriteFrameHeader(payload_length, HttpFrameType::GOAWAY, &writer) && writer.WriteVarInt62(goaway.stream_id)) { @@ -215,7 +215,7 @@ QuicByteCount total_length = GetTotalLength(payload_length); output->reset(new char[total_length]); - QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(total_length, output->get()); if (WriteFrameHeader(payload_length, HttpFrameType::MAX_PUSH_ID, &writer) && writer.WriteVarInt62(max_push_id.push_id)) { @@ -232,7 +232,7 @@ QuicByteCount total_length = GetTotalLength(payload_length); output->reset(new char[total_length]); - QuicDataWriter writer(total_length, output->get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(total_length, output->get()); if (WriteFrameHeader(payload_length, HttpFrameType::DUPLICATE_PUSH, &writer) &&
diff --git a/quic/core/http/quic_client_promised_info_test.cc b/quic/core/http/quic_client_promised_info_test.cc index 2cf3f76..2a7b1b0 100644 --- a/quic/core/http/quic_client_promised_info_test.cc +++ b/quic/core/http/quic_client_promised_info_test.cc
@@ -84,8 +84,8 @@ headers_["content-length"] = "11"; stream_ = QuicMakeUnique<QuicSpdyClientStream>( - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 0), + GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 0), &session_, BIDIRECTIONAL); stream_visitor_ = QuicMakeUnique<StreamVisitor>(); stream_->set_visitor(stream_visitor_.get()); @@ -99,9 +99,8 @@ promise_url_ = SpdyUtils::GetPromisedUrlFromHeaders(push_promise_); client_request_ = push_promise_.Clone(); - promise_id_ = - QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( - session_, 0); + promise_id_ = GetNthServerInitiatedUnidirectionalStreamId( + connection_->transport_version(), 0); } class StreamVisitor : public QuicSpdyClientStream::Visitor {
diff --git a/quic/core/http/quic_client_push_promise_index_test.cc b/quic/core/http/quic_client_push_promise_index_test.cc index 0ddde61..b68b41f 100644 --- a/quic/core/http/quic_client_push_promise_index_test.cc +++ b/quic/core/http/quic_client_push_promise_index_test.cc
@@ -54,12 +54,11 @@ &alarm_factory_, Perspective::IS_CLIENT)), session_(connection_->supported_versions(), connection_, &index_), - promised_( - &session_, - QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( - session_, - 0), - url_) { + promised_(&session_, + GetNthServerInitiatedUnidirectionalStreamId( + connection_->transport_version(), + 0), + url_) { request_[":path"] = "/bar"; request_[":authority"] = "www.google.com"; request_[":version"] = "HTTP/1.1";
diff --git a/quic/core/http/quic_headers_stream.cc b/quic/core/http/quic_headers_stream.cc index 09d8797..9c99ab7 100644 --- a/quic/core/http/quic_headers_stream.cc +++ b/quic/core/http/quic_headers_stream.cc
@@ -60,7 +60,8 @@ bool QuicHeadersStream::OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length, bool fin_acked, - QuicTime::Delta ack_delay_time) { + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length) { QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length); newly_acked.Difference(bytes_acked()); for (const auto& acked : newly_acked) { @@ -104,7 +105,7 @@ unacked_headers_.pop_front(); } return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked, - ack_delay_time); + ack_delay_time, newly_acked_length); } void QuicHeadersStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
diff --git a/quic/core/http/quic_headers_stream.h b/quic/core/http/quic_headers_stream.h index 4abfb01..abc0aeb 100644 --- a/quic/core/http/quic_headers_stream.h +++ b/quic/core/http/quic_headers_stream.h
@@ -43,7 +43,8 @@ bool OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length, bool fin_acked, - QuicTime::Delta ack_delay_time) override; + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length) override; void OnStreamFrameRetransmitted(QuicStreamOffset offset, QuicByteCount data_length,
diff --git a/quic/core/http/quic_headers_stream_test.cc b/quic/core/http/quic_headers_stream_test.cc index 1bbb9e4..b6409b1 100644 --- a/quic/core/http/quic_headers_stream_test.cc +++ b/quic/core/http/quic_headers_stream_test.cc
@@ -195,21 +195,19 @@ EXPECT_EQ(transport_version(), session_.connection()->transport_version()); EXPECT_TRUE(headers_stream_ != nullptr); connection_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); - client_id_1_ = - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 0); - client_id_2_ = - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 1); - client_id_3_ = - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 2); - next_stream_id_ = QuicSpdySessionPeer::StreamIdDelta(session_); + client_id_1_ = GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 0); + client_id_2_ = GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 1); + client_id_3_ = GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 2); + next_stream_id_ = + QuicUtils::StreamIdDelta(connection_->transport_version()); } QuicStreamId GetNthClientInitiatedId(int n) { - return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, n); + return GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), n); } QuicConsumedData SaveIov(size_t write_length) { @@ -278,9 +276,8 @@ connection_->transport_version()), _, _, NO_FIN)) .WillOnce(WithArgs<2>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); - QuicSpdySessionPeer::WriteHeadersImpl( - &session_, stream_id, headers_.Clone(), fin, - Spdy3PriorityToHttp2Weight(priority), 0, false, nullptr); + QuicSpdySessionPeer::WriteHeadersOnHeadersStream( + &session_, stream_id, headers_.Clone(), fin, priority, nullptr); // Parse the outgoing data and check that it matches was was written. if (is_request) { @@ -363,9 +360,8 @@ }; // Run all tests with each version and perspective (client or server). -INSTANTIATE_TEST_CASE_P(Tests, - QuicHeadersStreamTest, - ::testing::ValuesIn(GetTestParams())); +INSTANTIATE_TEST_SUITE_P(Tests, QuicHeadersStreamTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicHeadersStreamTest, StreamId) { EXPECT_EQ(QuicUtils::GetHeadersStreamId(connection_->transport_version()), @@ -833,27 +829,34 @@ headers_stream_->OnStreamFrameRetransmitted(28, 7, false); // Packets are acked in order: 2, 3, 1. + QuicByteCount newly_acked_length = 0; EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(21, 7, false, - QuicTime::Delta::Zero())); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(28, 7, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 21, 7, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(7u, newly_acked_length); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 28, 7, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(7u, newly_acked_length); EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(35, 7, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 35, 7, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(7u, newly_acked_length); EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); EXPECT_CALL(*ack_listener1, OnPacketAcked(7, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 7, false, - QuicTime::Delta::Zero())); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(7, 7, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 0, 7, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(7u, newly_acked_length); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 7, 7, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(7u, newly_acked_length); // Unsent data is acked. EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(14, 10, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 14, 10, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(7u, newly_acked_length); } TEST_P(QuicHeadersStreamTest, FrameContainsMultipleHeaders) { @@ -884,21 +887,25 @@ headers_stream_->OnStreamFrameRetransmitted(0, 17, false); // Frames are acked in order: 2, 3, 1. + QuicByteCount newly_acked_length = 0; EXPECT_CALL(*ack_listener2, OnPacketAcked(4, _)); EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); EXPECT_CALL(*ack_listener2, OnPacketAcked(2, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(17, 13, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 17, 13, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(13u, newly_acked_length); EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _)); EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(30, 12, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 30, 12, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(12u, newly_acked_length); EXPECT_CALL(*ack_listener1, OnPacketAcked(14, _)); EXPECT_CALL(*ack_listener2, OnPacketAcked(3, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 17, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 0, 17, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(17u, newly_acked_length); } TEST_P(QuicHeadersStreamTest, HeadersGetAckedMultipleTimes) { @@ -924,30 +931,36 @@ headers_stream_->WriteOrBufferData("Header9", false, ack_listener3); // Ack [15, 20), [5, 25), [10, 17), [0, 12) and [22, 42). + QuicByteCount newly_acked_length = 0; EXPECT_CALL(*ack_listener2, OnPacketAcked(5, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(15, 5, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 15, 5, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(5u, newly_acked_length); EXPECT_CALL(*ack_listener1, OnPacketAcked(9, _)); EXPECT_CALL(*ack_listener2, OnPacketAcked(1, _)); EXPECT_CALL(*ack_listener2, OnPacketAcked(1, _)); EXPECT_CALL(*ack_listener3, OnPacketAcked(4, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(5, 20, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 5, 20, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(15u, newly_acked_length); // Duplicate ack. - EXPECT_FALSE(headers_stream_->OnStreamFrameAcked(10, 7, false, - QuicTime::Delta::Zero())); + EXPECT_FALSE(headers_stream_->OnStreamFrameAcked( + 10, 7, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(0u, newly_acked_length); EXPECT_CALL(*ack_listener1, OnPacketAcked(5, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(0, 12, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 0, 12, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(5u, newly_acked_length); EXPECT_CALL(*ack_listener3, OnPacketAcked(3, _)); EXPECT_CALL(*ack_listener2, OnPacketAcked(7, _)); EXPECT_CALL(*ack_listener3, OnPacketAcked(7, _)); - EXPECT_TRUE(headers_stream_->OnStreamFrameAcked(22, 20, false, - QuicTime::Delta::Zero())); + EXPECT_TRUE(headers_stream_->OnStreamFrameAcked( + 22, 20, false, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(17u, newly_acked_length); } } // namespace
diff --git a/quic/core/http/quic_server_session_base.cc b/quic/core/http/quic_server_session_base.cc index 40b43dc..b18b1fa 100644 --- a/quic/core/http/quic_server_session_base.cc +++ b/quic/core/http/quic_server_session_base.cc
@@ -55,11 +55,6 @@ bandwidth_resumption_enabled_ = last_bandwidth_resumption || max_bandwidth_resumption; - if (connection()->transport_version() < QUIC_VERSION_35) { - set_server_push_enabled( - ContainsQuicTag(config()->ReceivedConnectionOptions(), kSPSH)); - } - // If the client has provided a bandwidth estimate from the same serving // region as this server, then decide whether to use the data for bandwidth // resumption.
diff --git a/quic/core/http/quic_server_session_base_test.cc b/quic/core/http/quic_server_session_base_test.cc index 9f36e37..2b75f70 100644 --- a/quic/core/http/quic_server_session_base_test.cc +++ b/quic/core/http/quic_server_session_base_test.cc
@@ -65,7 +65,7 @@ compressed_certs_cache), quic_simple_server_backend_(quic_simple_server_backend) {} - ~TestServerSession() override { delete connection(); }; + ~TestServerSession() override { delete connection(); } protected: QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override { @@ -157,13 +157,13 @@ } QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - *session_, n); + return GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), n); } QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( - *session_, n); + return quic::test::GetNthServerInitiatedUnidirectionalStreamId( + connection_->transport_version(), n); } QuicTransportVersion transport_version() const { @@ -188,6 +188,7 @@ 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)); session_->OnStopSendingFrame(stop_sending); } @@ -222,9 +223,8 @@ reference.previous_connection_state()); } -INSTANTIATE_TEST_CASE_P(Tests, - QuicServerSessionBaseTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, QuicServerSessionBaseTest, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicServerSessionBaseTest, CloseStreamDueToReset) { // Open a stream, then reset it. // Send two bytes of payload to open it. @@ -238,10 +238,14 @@ GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(GetNthClientInitiatedBidirectionalId(0), - QUIC_RST_ACKNOWLEDGEMENT)); + if (transport_version() != QUIC_VERSION_99) { + // For non-version 99, the RESET_STREAM will do the full close. + // Set up expects accordingly. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); + } visitor_->OnRstStream(rst1); // For version-99 will create and receive a stop-sending, completing @@ -265,10 +269,14 @@ GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(GetNthClientInitiatedBidirectionalId(0), - QUIC_RST_ACKNOWLEDGEMENT)); + if (transport_version() != QUIC_VERSION_99) { + // For non-version 99, the RESET_STREAM will do the full close. + // Set up expects accordingly. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); + } visitor_->OnRstStream(rst1); // For version-99 will create and receive a stop-sending, completing @@ -303,10 +311,14 @@ GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(GetNthClientInitiatedBidirectionalId(0), - QUIC_RST_ACKNOWLEDGEMENT)); + if (transport_version() != QUIC_VERSION_99) { + // For non-version 99, the RESET_STREAM will do the full close. + // Set up expects accordingly. + EXPECT_CALL(*connection_, SendControlFrame(_)); + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); + } visitor_->OnRstStream(rst); // For version-99 will create and receive a stop-sending, completing @@ -350,7 +362,7 @@ for (size_t i = 0; i < kMaxStreamsForTest; ++i) { EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( session_.get(), stream_id)); - stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_); + stream_id += QuicUtils::StreamIdDelta(connection_->transport_version()); } if (transport_version() != QUIC_VERSION_99) { @@ -359,11 +371,11 @@ for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) { EXPECT_TRUE(QuicServerSessionBasePeer::GetOrCreateDynamicStream( session_.get(), stream_id)); - stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_); + stream_id += QuicUtils::StreamIdDelta(connection_->transport_version()); } } // Now violate the server's internal stream limit. - stream_id += QuicSpdySessionPeer::StreamIdDelta(*session_); + stream_id += QuicUtils::StreamIdDelta(connection_->transport_version()); if (transport_version() != QUIC_VERSION_99) { // For non-version 99, QUIC responds to an attempt to exceed the stream @@ -395,7 +407,8 @@ session_.get(), GetNthClientInitiatedBidirectionalId(0))); // Establish available streams up to the server's limit. - QuicStreamId next_id = QuicSpdySessionPeer::StreamIdDelta(*session_); + QuicStreamId next_id = + QuicUtils::StreamIdDelta(connection_->transport_version()); const int kLimitingStreamId = GetNthClientInitiatedBidirectionalId(kAvailableStreamLimit + 1); if (transport_version() != QUIC_VERSION_99) { @@ -665,9 +678,8 @@ QuicCryptoServerConfigPeer crypto_config_peer_; }; -INSTANTIATE_TEST_CASE_P(StreamMemberLifetimeTests, - StreamMemberLifetimeTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(StreamMemberLifetimeTests, StreamMemberLifetimeTest, + ::testing::ValuesIn(AllSupportedVersions())); // Trigger an operation which causes an async invocation of // ProofSource::GetProof. Delay the completion of the operation until after the
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc index a9d6c62..84229fd 100644 --- a/quic/core/http/quic_spdy_client_session_test.cc +++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -108,12 +108,10 @@ push_promise_[":method"] = "GET"; push_promise_[":scheme"] = "https"; promise_url_ = SpdyUtils::GetPromisedUrlFromHeaders(push_promise_); - promised_stream_id_ = - QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( - *session_, 0); - associated_stream_id_ = - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - *session_, 0); + promised_stream_id_ = GetNthServerInitiatedUnidirectionalStreamId( + connection_->transport_version(), 0); + associated_stream_id_ = GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 0); } // The function ensures that A) the max stream id frames get properly deleted @@ -172,9 +170,8 @@ QuicStreamId associated_stream_id_; }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSpdyClientSessionTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyClientSessionTest, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSpdyClientSessionTest, CryptoConnect) { CompleteCryptoHandshake(); @@ -281,9 +278,8 @@ // Note that this is to be the second stream created, but GetNth... starts // numbering at 0 (the first stream is 0, second is 1...) - QuicMaxStreamIdFrame frame( - 0, QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - *session_, 1)); + QuicMaxStreamIdFrame frame(0, GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 1)); session_->OnMaxStreamIdFrame(frame); } stream = session_->CreateOutgoingBidirectionalStream(); @@ -350,9 +346,8 @@ if (GetParam().transport_version == QUIC_VERSION_99) { // Note that this is to be the second stream created, but GetNth... starts // numbering at 0 (the first stream is 0, second is 1...) - QuicMaxStreamIdFrame frame( - 0, QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - *session_, 1)); + QuicMaxStreamIdFrame frame(0, GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 1)); session_->OnMaxStreamIdFrame(frame); } stream = session_->CreateOutgoingBidirectionalStream(); @@ -454,7 +449,7 @@ QuicReceivedPacket valid_packet(buf, 2, QuicTime::Zero(), false); // Close connection shouldn't be called. EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); - if (connection_->transport_version() > QUIC_VERSION_46) { + if (connection_->transport_version() > QUIC_VERSION_44) { // Illegal fixed bit value. EXPECT_CALL(*connection_, OnError(_)).Times(1); } @@ -539,7 +534,8 @@ EXPECT_CALL(*stream, OnPromiseHeaderList(promised_stream_id_, _, _)); session_->OnPromiseHeaderList(associated_stream_id_, promised_stream_id_, 0, QuicHeaderList()); - associated_stream_id_ += QuicSpdySessionPeer::StreamIdDelta(*session_); + associated_stream_id_ += + QuicUtils::StreamIdDelta(connection_->transport_version()); EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, "Received push stream id lesser or equal to the" @@ -557,9 +553,8 @@ session_->CreateOutgoingBidirectionalStream()); // Promise an illegal (outgoing) stream id. - promised_stream_id_ = - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(*session_, - 0); + promised_stream_id_ = GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 0); EXPECT_CALL( *connection_, CloseConnection(QUIC_INVALID_STREAM_ID, @@ -615,7 +610,8 @@ EXPECT_NE(session_->GetPromisedById(promised_stream_id_), nullptr); EXPECT_NE(session_->GetPromisedByUrl(promise_url_), nullptr); - promised_stream_id_ += QuicSpdySessionPeer::StreamIdDelta(*session_); + promised_stream_id_ += + QuicUtils::StreamIdDelta(connection_->transport_version()); EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(promised_stream_id_, QUIC_DUPLICATE_PROMISE_URL)); @@ -632,7 +628,8 @@ push_promise_[":path"] = QuicStringPrintf("/bar%zu", i); QuicStreamId id = - promised_stream_id_ + i * QuicSpdySessionPeer::StreamIdDelta(*session_); + promised_stream_id_ + + i * QuicUtils::StreamIdDelta(connection_->transport_version()); EXPECT_TRUE( session_->HandlePromised(associated_stream_id_, id, push_promise_)); @@ -648,7 +645,8 @@ push_promise_[":path"] = QuicStringPrintf("/bar%d", i); QuicStreamId id = - promised_stream_id_ + i * QuicSpdySessionPeer::StreamIdDelta(*session_); + promised_stream_id_ + + i * QuicUtils::StreamIdDelta(connection_->transport_version()); EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL(*connection_, OnStreamReset(id, QUIC_REFUSED_STREAM)); EXPECT_FALSE( @@ -780,9 +778,8 @@ } else { EXPECT_CALL(*connection_, CloseConnection(_, _, _)).Times(0); } - session_->GetOrCreateStream( - QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId(*session_, - 0)); + session_->GetOrCreateStream(GetNthServerInitiatedBidirectionalStreamId( + connection_->transport_version(), 0)); } } // namespace
diff --git a/quic/core/http/quic_spdy_client_stream.cc b/quic/core/http/quic_spdy_client_stream.cc index 21a09d6..d4e8a69 100644 --- a/quic/core/http/quic_spdy_client_stream.cc +++ b/quic/core/http/quic_spdy_client_stream.cc
@@ -151,7 +151,7 @@ bytes_sent += header_bytes_written_; if (!body.empty()) { - WriteOrBufferBody(body, fin, nullptr); + WriteOrBufferBody(body, fin); } return bytes_sent;
diff --git a/quic/core/http/quic_spdy_client_stream_test.cc b/quic/core/http/quic_spdy_client_stream_test.cc index ded2d7d..059558b 100644 --- a/quic/core/http/quic_spdy_client_stream_test.cc +++ b/quic/core/http/quic_spdy_client_stream_test.cc
@@ -75,8 +75,8 @@ headers_["content-length"] = "11"; stream_ = QuicMakeUnique<QuicSpdyClientStream>( - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 0), + GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 0), &session_, BIDIRECTIONAL); stream_visitor_ = QuicMakeUnique<StreamVisitor>(); stream_->set_visitor(stream_visitor_.get()); @@ -101,9 +101,8 @@ HttpEncoder encoder_; }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSpdyClientStreamTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyClientStreamTest, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSpdyClientStreamTest, TestReceivingIllegalResponseStatusCode) { headers_[":status"] = "200 ok"; @@ -125,7 +124,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body_.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 + QuicString data = VersionHasDataFrameHeader(connection_->transport_version()) ? header + body_ : body_; stream_->OnStreamFrame( @@ -156,7 +155,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body_.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 + QuicString data = VersionHasDataFrameHeader(connection_->transport_version()) ? header + body_ : body_; stream_->OnStreamFrame( @@ -180,7 +179,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(large_body.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 + QuicString data = VersionHasDataFrameHeader(connection_->transport_version()) ? header + large_body : large_body; EXPECT_CALL(*connection_, SendControlFrame(_)); @@ -219,7 +218,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body_.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 + QuicString data = VersionHasDataFrameHeader(connection_->transport_version()) ? header + body_ : body_; stream_->OnStreamFrame(
diff --git a/quic/core/http/quic_spdy_server_stream_base_test.cc b/quic/core/http/quic_spdy_server_stream_base_test.cc index 51abf0c..4e1aa1b 100644 --- a/quic/core/http/quic_spdy_server_stream_base_test.cc +++ b/quic/core/http/quic_spdy_server_stream_base_test.cc
@@ -32,8 +32,8 @@ &alarm_factory_, Perspective::IS_SERVER)) { stream_ = new TestQuicSpdyServerStream( - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 0), + GetNthClientInitiatedBidirectionalStreamId( + session_.connection()->transport_version(), 0), &session_, BIDIRECTIONAL); session_.ActivateStream(QuicWrapUnique(stream_)); helper_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); @@ -58,7 +58,21 @@ EXPECT_FALSE(stream_->reading_stopped()); EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0); - EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)).Times(1); + + if (session_.connection()->transport_version() != QUIC_VERSION_99) { + EXPECT_CALL(session_, SendRstStream(_, QUIC_RST_ACKNOWLEDGEMENT, _)) + .Times(1); + } else { + // Intercept & check that the call to the QuicConnection's OnStreamReast + // has correct stream ID and error code -- for V99/IETF Quic, it should + // have the STREAM_CANCELLED error code, not RST_ACK... Capture + // OnStreamReset (rather than SendRstStream) because the V99 path bypasses + // SendRstStream, calling SendRstStreamInner directly. Mocking + // SendRstStreamInner is problematic since the test relies on it to perform + // the closing operations and getting the stream in the correct state. + EXPECT_CALL(*(static_cast<MockQuicConnection*>(session_.connection())), + OnStreamReset(stream_->id(), QUIC_STREAM_CANCELLED)); + } QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 1234); stream_->OnStreamReset(rst_frame);
diff --git a/quic/core/http/quic_spdy_session.cc b/quic/core/http/quic_spdy_session.cc index bc3cf5c..824ecfa 100644 --- a/quic/core/http/quic_spdy_session.cc +++ b/quic/core/http/quic_spdy_session.cc
@@ -347,6 +347,11 @@ QuicUtils::GetHeadersStreamId(connection()->transport_version())); } + if (VersionUsesQpack(connection()->transport_version())) { + qpack_encoder_ = QuicMakeUnique<QpackEncoder>(this, this); + qpack_decoder_ = QuicMakeUnique<QpackDecoder>(this, this); + } + headers_stream_ = QuicMakeUnique<QuicHeadersStream>((this)); DCHECK_EQ(QuicUtils::GetHeadersStreamId(connection()->transport_version()), headers_stream_->id()); @@ -360,6 +365,34 @@ set_max_decode_buffer_size_bytes(2 * max_inbound_header_list_size_); } +void QuicSpdySession::OnDecoderStreamError(QuicStringPiece error_message) { + DCHECK(VersionUsesQpack(connection()->transport_version())); + + // TODO(112770235): Signal connection error on decoder stream errors. + QUIC_NOTREACHED(); +} + +void QuicSpdySession::WriteEncoderStreamData(QuicStringPiece data) { + DCHECK(VersionUsesQpack(connection()->transport_version())); + + // TODO(112770235): Send encoder stream data on encoder stream. + QUIC_NOTREACHED(); +} + +void QuicSpdySession::OnEncoderStreamError(QuicStringPiece error_message) { + DCHECK(VersionUsesQpack(connection()->transport_version())); + + // TODO(112770235): Signal connection error on encoder stream errors. + QUIC_NOTREACHED(); +} + +void QuicSpdySession::WriteDecoderStreamData(QuicStringPiece data) { + DCHECK(VersionUsesQpack(connection()->transport_version())); + + // TODO(112770235): Send decoder stream data on decoder stream. + QUIC_NOTREACHED(); +} + void QuicSpdySession::OnStreamHeadersPriority(QuicStreamId stream_id, SpdyPriority priority) { QuicSpdyStream* stream = GetSpdyDataStream(stream_id); @@ -424,38 +457,16 @@ iov.iov_len); } -size_t QuicSpdySession::WriteHeaders( +size_t QuicSpdySession::WriteHeadersOnHeadersStream( QuicStreamId id, SpdyHeaderBlock headers, bool fin, SpdyPriority priority, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - return WriteHeadersImpl( - id, std::move(headers), fin, Spdy3PriorityToHttp2Weight(priority), - /*parent_stream_id=*/0, /*exclusive=*/false, std::move(ack_listener)); -} - -size_t QuicSpdySession::WriteHeadersImpl( - QuicStreamId id, - SpdyHeaderBlock headers, - bool fin, - int weight, - QuicStreamId parent_stream_id, - bool exclusive, - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - SpdyHeadersIR headers_frame(id, std::move(headers)); - headers_frame.set_fin(fin); - if (perspective() == Perspective::IS_CLIENT) { - headers_frame.set_has_priority(true); - headers_frame.set_weight(weight); - headers_frame.set_parent_stream_id(parent_stream_id); - headers_frame.set_exclusive(exclusive); - } - SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame)); - headers_stream_->WriteOrBufferData( - QuicStringPiece(frame.data(), frame.size()), false, - std::move(ack_listener)); - return frame.size(); + return WriteHeadersOnHeadersStreamImpl( + id, std::move(headers), fin, + /* parent_stream_id = */ 0, Spdy3PriorityToHttp2Weight(priority), + /* exclusive = */ false, std::move(ack_listener)); } size_t QuicSpdySession::WritePriority(QuicStreamId id, @@ -502,6 +513,18 @@ return frame.size(); } +QpackEncoder* QuicSpdySession::qpack_encoder() { + DCHECK(VersionUsesQpack(connection()->transport_version())); + + return qpack_encoder_.get(); +} + +QpackDecoder* QuicSpdySession::qpack_decoder() { + DCHECK(VersionUsesQpack(connection()->transport_version())); + + return qpack_decoder_.get(); +} + QuicSpdyStream* QuicSpdySession::GetSpdyDataStream( const QuicStreamId stream_id) { return static_cast<QuicSpdyStream*>(GetOrCreateDynamicStream(stream_id)); @@ -519,6 +542,29 @@ return !QuicUtils::IsBidirectionalStreamId(id); } +size_t QuicSpdySession::WriteHeadersOnHeadersStreamImpl( + QuicStreamId id, + spdy::SpdyHeaderBlock headers, + bool fin, + QuicStreamId parent_stream_id, + int weight, + bool exclusive, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + SpdyHeadersIR headers_frame(id, std::move(headers)); + headers_frame.set_fin(fin); + if (perspective() == Perspective::IS_CLIENT) { + headers_frame.set_has_priority(true); + headers_frame.set_parent_stream_id(parent_stream_id); + headers_frame.set_weight(weight); + headers_frame.set_exclusive(exclusive); + } + SpdySerializedFrame frame(spdy_framer_.SerializeFrame(headers_frame)); + headers_stream_->WriteOrBufferData( + QuicStringPiece(frame.data(), frame.size()), false, + std::move(ack_listener)); + return frame.size(); +} + void QuicSpdySession::OnPromiseHeaderList(QuicStreamId stream_id, QuicStreamId promised_stream_id, size_t frame_len,
diff --git a/quic/core/http/quic_spdy_session.h b/quic/core/http/quic_spdy_session.h index 2874e26..363edf3 100644 --- a/quic/core/http/quic_spdy_session.h +++ b/quic/core/http/quic_spdy_session.h
@@ -12,7 +12,12 @@ #include "net/third_party/quiche/src/quic/core/http/quic_header_list.h" #include "net/third_party/quiche/src/quic/core/http/quic_headers_stream.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_stream_sender.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_encoder_stream_sender.h" #include "net/third_party/quiche/src/quic/core/quic_session.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" @@ -44,7 +49,12 @@ }; // A QUIC session with a headers stream. -class QUIC_EXPORT_PRIVATE QuicSpdySession : public QuicSession { +class QUIC_EXPORT_PRIVATE QuicSpdySession + : public QuicSession, + public QpackEncoder::DecoderStreamErrorDelegate, + public QpackEncoderStreamSender::Delegate, + public QpackDecoder::EncoderStreamErrorDelegate, + public QpackDecoderStreamSender::Delegate { public: // Does not take ownership of |connection| or |visitor|. QuicSpdySession(QuicConnection* connection, @@ -58,6 +68,18 @@ void Initialize() override; + // QpackEncoder::DecoderStreamErrorDelegate implementation. + void OnDecoderStreamError(QuicStringPiece error_message) override; + + // QpackEncoderStreamSender::Delegate implemenation. + void WriteEncoderStreamData(QuicStringPiece data) override; + + // QpackDecoder::EncoderStreamErrorDelegate implementation. + void OnEncoderStreamError(QuicStringPiece error_message) override; + + // QpackDecoderStreamSender::Delegate implementation. + void WriteDecoderStreamData(QuicStringPiece data) override; + // Called by |headers_stream_| when headers with a priority have been // received for a stream. This method will only be called for server streams. virtual void OnStreamHeadersPriority(QuicStreamId stream_id, @@ -79,7 +101,7 @@ size_t frame_len, const QuicHeaderList& header_list); - // Callbed by |headers_stream_| when a PRIORITY frame has been received for a + // Called by |headers_stream_| when a PRIORITY frame has been received for a // stream. This method will only be called for server streams. virtual void OnPriorityFrame(QuicStreamId stream_id, spdy::SpdyPriority priority); @@ -91,7 +113,7 @@ // If |fin| is true, then no more data will be sent for the stream |id|. // If provided, |ack_notifier_delegate| will be registered to be notified when // we have seen ACKs for all packets resulting from this call. - virtual size_t WriteHeaders( + virtual size_t WriteHeadersOnHeadersStream( QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin, @@ -116,6 +138,8 @@ // Sends SETTINGS_MAX_HEADER_LIST_SIZE SETTINGS frame. size_t SendMaxHeaderListSize(size_t value); + QpackEncoder* qpack_encoder(); + QpackDecoder* qpack_decoder(); QuicHeadersStream* headers_stream() { return headers_stream_.get(); } bool server_push_enabled() const { return server_push_enabled_; } @@ -157,15 +181,12 @@ // Overridden to buffer incoming streams for version 99. bool ShouldBufferIncomingStream(QuicStreamId id) const override; - // This was formerly QuicHeadersStream::WriteHeaders. Needs to be - // separate from QuicSpdySession::WriteHeaders because tests call - // this but mock the latter. - size_t WriteHeadersImpl( + size_t WriteHeadersOnHeadersStreamImpl( QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin, - int weight, QuicStreamId parent_stream_id, + int weight, bool exclusive, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); @@ -226,6 +247,10 @@ // Called when the size of the compressed frame payload is available. void OnCompressedFrameSize(size_t frame_len); + std::unique_ptr<QpackEncoder> qpack_encoder_; + std::unique_ptr<QpackDecoder> qpack_decoder_; + + // TODO(123528590): Remove this member. std::unique_ptr<QuicHeadersStream> headers_stream_; // The maximum size of a header block that will be accepted from the peer,
diff --git a/quic/core/http/quic_spdy_session_test.cc b/quic/core/http/quic_spdy_session_test.cc index affa07a..d9c4ab1 100644 --- a/quic/core/http/quic_spdy_session_test.cc +++ b/quic/core/http/quic_spdy_session_test.cc
@@ -98,6 +98,8 @@ MOCK_METHOD0(OnCanWrite, void()); + bool HasPendingCryptoRetransmission() override { return false; } + MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); private: @@ -187,7 +189,8 @@ TestStream* stream = new TestStream( id, this, DetermineStreamType(id, connection()->transport_version(), - /*is_incoming=*/true, BIDIRECTIONAL)); + perspective(), /*is_incoming=*/true, + BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); return stream; } @@ -195,10 +198,11 @@ TestStream* CreateIncomingStream(PendingStream pending) override { QuicStreamId id = pending.id(); - TestStream* stream = new TestStream( - std::move(pending), this, - DetermineStreamType(id, connection()->transport_version(), - /*is_incoming=*/true, BIDIRECTIONAL)); + TestStream* stream = + new TestStream(std::move(pending), this, + DetermineStreamType( + id, connection()->transport_version(), perspective(), + /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); return stream; } @@ -342,7 +346,7 @@ } void CloseStream(QuicStreamId id) { - if (transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); } else { @@ -360,18 +364,19 @@ return connection_->transport_version(); } + bool IsVersion99() const { return transport_version() == QUIC_VERSION_99; } + QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, n); + return GetNthClientInitiatedBidirectionalStreamId(transport_version(), n); } QuicStreamId GetNthServerInitiatedBidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId( - session_, n); + return GetNthServerInitiatedBidirectionalStreamId( + connection_->transport_version(), n); } QuicStreamId IdDelta() { - return QuicSpdySessionPeer::StreamIdDelta(session_); + return QuicUtils::StreamIdDelta(connection_->transport_version()); } MockQuicConnectionHelper helper_; @@ -388,12 +393,12 @@ : QuicSpdySessionTestBase(Perspective::IS_SERVER) {} }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSpdySessionTestServer, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSpdySessionTestServer, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSpdySessionTestServer, ShouldBufferIncomingStreamUnidirectional) { - if (connection_->transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { return; } EXPECT_TRUE(session_.ShouldBufferIncomingStream( @@ -402,7 +407,7 @@ } TEST_P(QuicSpdySessionTestServer, ShouldBufferIncomingStreamBidirectional) { - if (connection_->transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { return; } EXPECT_FALSE(session_.ShouldBufferIncomingStream( @@ -416,7 +421,7 @@ } TEST_P(QuicSpdySessionTestServer, SelfAddress) { - EXPECT_EQ(QuicSocketAddress(), session_.self_address()); + EXPECT_TRUE(session_.self_address().IsInitialized()); } TEST_P(QuicSpdySessionTestServer, IsCryptoHandshakeConfirmed) { @@ -481,7 +486,7 @@ } TEST_P(QuicSpdySessionTestServer, MaximumAvailableOpenedStreams) { - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // For IETF QUIC, we should be able to obtain the max allowed // stream ID, the next ID should fail. Since the actual limit // is not the number of open streams, we allocate the max and the max+2. @@ -532,7 +537,7 @@ // A stream ID which is too large to create. stream_id2 = GetNthClientInitiatedBidirectionalId( 2 * session_.MaxAvailableBidirectionalStreams() + 4); - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_STREAM_ID, _, _)); } else { EXPECT_CALL(*connection_, @@ -670,7 +675,7 @@ } TEST_P(QuicSpdySessionTestServer, OnCanWriteBundlesStreams) { - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly(Invoke( this, &QuicSpdySessionTestServer::ClearMaxStreamIdControlFrame)); @@ -776,8 +781,6 @@ MockPacketWriter* writer = static_cast<MockPacketWriter*>( QuicConnectionPeer::GetWriter(session_.connection())); EXPECT_CALL(*writer, IsWriteBlocked()).WillRepeatedly(Return(true)); - EXPECT_CALL(*writer, IsWriteBlockedDataBuffered()) - .WillRepeatedly(Return(true)); EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)).Times(0); TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); @@ -908,7 +911,7 @@ } TEST_P(QuicSpdySessionTestServer, SendGoAway) { - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // GoAway frames are not in version 99 return; } @@ -932,7 +935,7 @@ } TEST_P(QuicSpdySessionTestServer, DoNotSendGoAwayTwice) { - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // TODO(b/118808809): Enable this test for version 99 when GOAWAY is // supported. return; @@ -945,7 +948,7 @@ } TEST_P(QuicSpdySessionTestServer, InvalidGoAway) { - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // TODO(b/118808809): Enable this test for version 99 when GOAWAY is // supported. return; @@ -967,7 +970,7 @@ EXPECT_CALL(*connection_, SendConnectivityProbingResponsePacket(new_peer_address)); - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // Need to explicitly do this to emulate the reception of a PathChallenge, // which stores its payload for use in generating the response. connection_->OnPathChallengeFrame( @@ -995,8 +998,12 @@ EXPECT_EQ(1u, session_.GetNumOpenIncomingStreams()); EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(GetNthClientInitiatedBidirectionalId(0), _)); + if (!IsVersion99()) { + // For version99, OnStreamReset gets called because of the STOP_SENDING, + // below. EXPECT the call there. + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), _)); + } QuicRstStreamFrame rst1(kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM, 0); @@ -1005,7 +1012,7 @@ // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a // one-way close. - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // Only needed for version 99/IETF QUIC. QuicStopSendingFrame stop_sending( kInvalidControlFrameId, GetNthClientInitiatedBidirectionalId(0), @@ -1088,7 +1095,7 @@ EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); EXPECT_CALL(*connection_, SendControlFrame(_)).Times(AtLeast(1)); - stream2->WriteOrBufferBody(body, false, nullptr); + stream2->WriteOrBufferBody(body, false); EXPECT_TRUE(stream2->flow_controller()->IsBlocked()); EXPECT_TRUE(session_.IsConnectionFlowControlBlocked()); EXPECT_TRUE(session_.IsStreamFlowControlBlocked()); @@ -1106,6 +1113,11 @@ TEST_P(QuicSpdySessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { + if (GetParam().transport_version >= QUIC_VERSION_47) { + // QUIC version 47 onwards uses CRYPTO frames for the handshake, so this + // test doesn't make sense for those versions. + return; + } // Test that if the crypto stream is flow control blocked, then if the SHLO // contains a larger send window offset, the stream becomes unblocked. session_.set_writev_consumes_all_data(true); @@ -1118,10 +1130,9 @@ EXPECT_FALSE(headers_stream->flow_controller()->IsBlocked()); EXPECT_FALSE(session_.IsConnectionFlowControlBlocked()); EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(1) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); } else { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); @@ -1190,12 +1201,14 @@ EXPECT_FALSE(session_.IsStreamFlowControlBlocked()); headers["header"] = QuicStrCat(random.RandUint64(), random.RandUint64(), random.RandUint64()); - session_.WriteHeaders(stream_id, headers.Clone(), true, 0, nullptr); + session_.WriteHeadersOnHeadersStream(stream_id, headers.Clone(), true, 0, + nullptr); stream_id += IdDelta(); } // Write once more to ensure that the headers stream has buffered data. The // random headers may have exactly filled the flow control window. - session_.WriteHeaders(stream_id, std::move(headers), true, 0, nullptr); + session_.WriteHeadersOnHeadersStream(stream_id, std::move(headers), true, 0, + nullptr); EXPECT_TRUE(headers_stream->HasBufferedData()); EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked()); @@ -1231,25 +1244,21 @@ const QuicStreamOffset kByteOffset = 1 + kInitialSessionFlowControlWindowForTest / 2; - if (transport_version() != QUIC_VERSION_99) { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); - } else { - // V99 has an additional, STOP_SENDING, frame and an additional RST_STREAM - // (the response to the STOP_SENDING) frame. - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(4) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + if (!IsVersion99()) { + // For version99 the call to OnStreamReset happens as a result of receiving + // the STOP_SENDING, so set up the EXPECT there. + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); } - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(), QUIC_STREAM_CANCELLED, kByteOffset); session_.OnRstStream(rst_frame); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes a // one-way close. - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // Only needed for version 99/IETF QUIC. QuicStopSendingFrame stop_sending( kInvalidControlFrameId, stream->id(), @@ -1457,12 +1466,13 @@ GetNthClientInitiatedBidirectionalId(kMaxStreams); // Create kMaxStreams data streams, and close them all without receiving a // FIN or a RST_STREAM from the client. - const QuicStreamId kNextId = QuicSpdySessionPeer::StreamIdDelta(session_); + const QuicStreamId kNextId = + QuicUtils::StreamIdDelta(connection_->transport_version()); for (QuicStreamId i = kFirstStreamId; i < kFinalStreamId; i += kNextId) { QuicStreamFrame data1(i, false, 0, QuicStringPiece("HT")); session_.OnStreamFrame(data1); // EXPECT_EQ(1u, session_.GetNumOpenStreams()); - if (transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); } else { @@ -1478,7 +1488,7 @@ session_.CloseStream(i); } // Try and open a stream that exceeds the limit. - if (transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { // On versions other than 99, opening such a stream results in a // RST_STREAM. EXPECT_CALL(*connection_, SendControlFrame(_)).Times(1); @@ -1499,7 +1509,7 @@ // Verify that a draining stream (which has received a FIN but not consumed // it) does not count against the open quota (because it is closed from the // protocol point of view). - if (transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // Version 99 will result in a MAX_STREAM_ID frame as streams are consumed // (via the OnStreamFrame call) and then released (via // StreamDraining). Eventually this node will believe that the peer is @@ -1532,9 +1542,9 @@ : QuicSpdySessionTestBase(Perspective::IS_CLIENT) {} }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSpdySessionTestClient, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSpdySessionTestClient, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSpdySessionTestClient, AvailableStreamsClient) { ASSERT_TRUE(session_.GetOrCreateDynamicStream( @@ -1658,11 +1668,18 @@ // Lost data on cryption stream, streams 2 and 4. EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true)); - EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) - .WillOnce(Return(true)); + if (connection_->transport_version() < QUIC_VERSION_47) { + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(true)); + } EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true)); session_.OnFrameLost(QuicFrame(frame3)); - session_.OnFrameLost(QuicFrame(frame1)); + if (connection_->transport_version() < QUIC_VERSION_47) { + session_.OnFrameLost(QuicFrame(frame1)); + } else { + QuicCryptoFrame crypto_frame(ENCRYPTION_NONE, 0, 1300); + session_.OnFrameLost(QuicFrame(&crypto_frame)); + } session_.OnFrameLost(QuicFrame(frame2)); EXPECT_TRUE(session_.WillingAndAbleToWrite()); @@ -1674,9 +1691,11 @@ // stream go first. // Do not check congestion window when crypto stream has lost data. EXPECT_CALL(*send_algorithm, CanSend(_)).Times(0); - EXPECT_CALL(*crypto_stream, OnCanWrite()); - EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) - .WillOnce(Return(false)); + if (connection_->transport_version() < QUIC_VERSION_47) { + EXPECT_CALL(*crypto_stream, OnCanWrite()); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(false)); + } // Check congestion window for non crypto streams. EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); EXPECT_CALL(*stream4, OnCanWrite());
diff --git a/quic/core/http/quic_spdy_stream.cc b/quic/core/http/quic_spdy_stream.cc index eb8135a..9e9f1b7 100644 --- a/quic/core/http/quic_spdy_stream.cc +++ b/quic/core/http/quic_spdy_stream.cc
@@ -81,7 +81,9 @@ CloseConnectionOnWrongFrame("Headers"); } - void OnHeadersFrameEnd() override { CloseConnectionOnWrongFrame("Headers"); } + void OnHeadersFrameEnd(QuicByteCount frame_len) override { + CloseConnectionOnWrongFrame("Headers"); + } void OnPushPromiseFrameStart(PushId push_id) override { CloseConnectionOnWrongFrame("Push Promise"); @@ -121,7 +123,7 @@ trailers_consumed_(false), http_decoder_visitor_(new HttpDecoderVisitor(this)), body_buffer_(sequencer()), - total_header_bytes_written_(0) { + ack_listener_(nullptr) { DCHECK_NE(QuicUtils::GetCryptoStreamId( spdy_session->connection()->transport_version()), id); @@ -129,7 +131,8 @@ // are complete. sequencer()->SetBlockedUntilFlush(); - if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99) { + if (VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version())) { sequencer()->set_level_triggered(true); } decoder_.set_visitor(http_decoder_visitor_.get()); @@ -146,7 +149,7 @@ trailers_consumed_(false), http_decoder_visitor_(new HttpDecoderVisitor(this)), body_buffer_(sequencer()), - total_header_bytes_written_(0) { + ack_listener_(nullptr) { DCHECK_NE(QuicUtils::GetCryptoStreamId( spdy_session->connection()->transport_version()), id()); @@ -154,7 +157,8 @@ // are complete. sequencer()->SetBlockedUntilFlush(); - if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99) { + if (VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version())) { sequencer()->set_level_triggered(true); } decoder_.set_visitor(http_decoder_visitor_.get()); @@ -166,8 +170,8 @@ SpdyHeaderBlock header_block, bool fin, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - size_t bytes_written = spdy_session_->WriteHeaders( - id(), std::move(header_block), fin, priority(), std::move(ack_listener)); + size_t bytes_written = + WriteHeadersImpl(std::move(header_block), fin, std::move(ack_listener)); if (fin) { // TODO(rch): Add test to ensure fin_sent_ is set whenever a fin is sent. set_fin_sent(true); @@ -176,28 +180,32 @@ return bytes_written; } -void QuicSpdyStream::WriteOrBufferBody( - QuicStringPiece data, - bool fin, - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99 || +void QuicSpdyStream::WriteOrBufferBody(QuicStringPiece data, bool fin) { + if (!VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version()) || data.length() == 0) { - WriteOrBufferData(data, fin, std::move(ack_listener)); + WriteOrBufferData(data, fin, nullptr); return; } QuicConnection::ScopedPacketFlusher flusher( spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); + + // Write frame header. std::unique_ptr<char[]> buffer; QuicByteCount header_length = encoder_.SerializeDataFrameHeader(data.length(), &buffer); - WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false, - nullptr); + unacked_frame_headers_offsets_.Add( + send_buffer().stream_offset(), + send_buffer().stream_offset() + header_length); QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length " << header_length; - total_header_bytes_written_ += header_length; - WriteOrBufferData(data, fin, std::move(ack_listener)); + WriteOrBufferData(QuicStringPiece(buffer.get(), header_length), false, + nullptr); + + // Write body. QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length " << data.length(); + WriteOrBufferData(data, fin, nullptr); } size_t QuicSpdyStream::WriteTrailers( @@ -221,8 +229,7 @@ // trailers are the last thing to be sent on a stream. const bool kFin = true; size_t bytes_written = - spdy_session_->WriteHeaders(id(), std::move(trailer_block), kFin, - priority(), std::move(ack_listener)); + WriteHeadersImpl(std::move(trailer_block), kFin, std::move(ack_listener)); set_fin_sent(kFin); // Trailers are the last thing to be sent on a stream, but if there is still @@ -250,7 +257,8 @@ QuicConsumedData QuicSpdyStream::WriteBodySlices(QuicMemSliceSpan slices, bool fin) { - if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99 || + if (!VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version()) || slices.empty()) { return WriteMemSlices(slices, fin); } @@ -264,23 +272,30 @@ QuicConnection::ScopedPacketFlusher flusher( spdy_session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); + + // Write frame header. struct iovec header_iov = {static_cast<void*>(buffer.get()), header_length}; QuicMemSliceStorage storage( &header_iov, 1, spdy_session_->connection()->helper()->GetStreamSendBufferAllocator(), GetQuicFlag(FLAGS_quic_send_buffer_max_data_slice_size)); - WriteMemSlices(storage.ToSpan(), false); + unacked_frame_headers_offsets_.Add( + send_buffer().stream_offset(), + send_buffer().stream_offset() + header_length); QUIC_DLOG(INFO) << "Stream " << id() << " is writing header of length " << header_length; - total_header_bytes_written_ += header_length; - QUIC_DLOG(INFO) << "Stream" << id() << " is writing body of length " + WriteMemSlices(storage.ToSpan(), false); + + // Write body. + QUIC_DLOG(INFO) << "Stream " << id() << " is writing body of length " << slices.total_length(); return WriteMemSlices(slices, fin); } size_t QuicSpdyStream::Readv(const struct iovec* iov, size_t iov_len) { DCHECK(FinishedReadingHeaders()); - if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) { + if (!VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version())) { return sequencer()->Readv(iov, iov_len); } return body_buffer_.ReadBody(iov, iov_len); @@ -288,7 +303,8 @@ int QuicSpdyStream::GetReadableRegions(iovec* iov, size_t iov_len) const { DCHECK(FinishedReadingHeaders()); - if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) { + if (!VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version())) { return sequencer()->GetReadableRegions(iov, iov_len); } return body_buffer_.PeekBody(iov, iov_len); @@ -296,8 +312,10 @@ void QuicSpdyStream::MarkConsumed(size_t num_bytes) { DCHECK(FinishedReadingHeaders()); - if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) { - return sequencer()->MarkConsumed(num_bytes); + if (!VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version())) { + sequencer()->MarkConsumed(num_bytes); + return; } body_buffer_.MarkBodyConsumed(num_bytes); } @@ -310,7 +328,8 @@ } bool QuicSpdyStream::HasBytesToRead() const { - if (spdy_session_->connection()->transport_version() != QUIC_VERSION_99) { + if (!VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version())) { return sequencer()->HasBytesToRead(); } return body_buffer_.HasBytesToRead(); @@ -321,7 +340,8 @@ } uint64_t QuicSpdyStream::total_body_bytes_read() const { - if (spdy_session_->connection()->transport_version() == QUIC_VERSION_99) { + if (VersionHasDataFrameHeader( + spdy_session_->connection()->transport_version())) { return body_buffer_.total_body_bytes_received(); } return sequencer()->NumBytesConsumed(); @@ -424,6 +444,14 @@ QuicStreamFrame(id(), fin, final_byte_offset, QuicStringPiece())); } +size_t QuicSpdyStream::WriteHeadersImpl( + spdy::SpdyHeaderBlock header_block, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + return spdy_session_->WriteHeadersOnHeadersStream( + id(), std::move(header_block), fin, priority(), std::move(ack_listener)); +} + void QuicSpdyStream::OnPriorityFrame(SpdyPriority priority) { DCHECK_EQ(Perspective::IS_SERVER, session()->connection()->perspective()); SetPriority(priority); @@ -442,7 +470,8 @@ } void QuicSpdyStream::OnDataAvailable() { - if (session()->connection()->transport_version() != QUIC_VERSION_99) { + if (!VersionHasDataFrameHeader( + session()->connection()->transport_version())) { OnBodyAvailable(); return; } @@ -543,5 +572,52 @@ << body_buffer_.total_body_bytes_received(); } +bool QuicSpdyStream::OnStreamFrameAcked(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_acked, + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length) { + const bool new_data_acked = QuicStream::OnStreamFrameAcked( + offset, data_length, fin_acked, ack_delay_time, newly_acked_length); + + const QuicByteCount newly_acked_header_length = + GetNumFrameHeadersInInterval(offset, data_length); + DCHECK_LE(newly_acked_header_length, *newly_acked_length); + unacked_frame_headers_offsets_.Difference(offset, offset + data_length); + if (ack_listener_ != nullptr && new_data_acked) { + ack_listener_->OnPacketAcked( + *newly_acked_length - newly_acked_header_length, ack_delay_time); + } + return new_data_acked; +} + +void QuicSpdyStream::OnStreamFrameRetransmitted(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_retransmitted) { + QuicStream::OnStreamFrameRetransmitted(offset, data_length, + fin_retransmitted); + + const QuicByteCount retransmitted_header_length = + GetNumFrameHeadersInInterval(offset, data_length); + DCHECK_LE(retransmitted_header_length, data_length); + + if (ack_listener_ != nullptr) { + ack_listener_->OnPacketRetransmitted(data_length - + retransmitted_header_length); + } +} + +QuicByteCount QuicSpdyStream::GetNumFrameHeadersInInterval( + QuicStreamOffset offset, + QuicByteCount data_length) const { + QuicByteCount header_acked_length = 0; + QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length); + newly_acked.Intersection(unacked_frame_headers_offsets_); + for (const auto& interval : newly_acked) { + header_acked_length += interval.Length(); + } + return header_acked_length; +} + #undef ENDPOINT // undef for jumbo builds } // namespace quic
diff --git a/quic/core/http/quic_spdy_stream.h b/quic/core/http/quic_spdy_stream.h index eccec56..2bad21a 100644 --- a/quic/core/http/quic_spdy_stream.h +++ b/quic/core/http/quic_spdy_stream.h
@@ -31,6 +31,7 @@ namespace quic { namespace test { +class QuicSpdyStreamPeer; class QuicStreamPeer; } // namespace test @@ -117,10 +118,7 @@ QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); // Sends |data| to the peer, or buffers if it can't be sent immediately. - void WriteOrBufferBody( - QuicStringPiece data, - bool fin, - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + void WriteOrBufferBody(QuicStringPiece data, bool fin); // Writes the trailers contained in |trailer_block| to the dedicated // headers stream. Trailers will always have the FIN set. @@ -128,6 +126,18 @@ spdy::SpdyHeaderBlock trailer_block, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + // Override to report newly acked bytes via ack_listener_. + bool OnStreamFrameAcked(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_acked, + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length) override; + + // Override to report bytes retransmitted via ack_listener_. + void OnStreamFrameRetransmitted(QuicStreamOffset offset, + QuicByteCount data_length, + bool fin_retransmitted) override; + // Does the same thing as WriteOrBufferBody except this method takes iovec // as the data input. Right now it only calls WritevData. // TODO(renjietang): Write data frame header before writing body. @@ -166,10 +176,6 @@ bool headers_decompressed() const { return headers_decompressed_; } - size_t total_header_bytes_written() const { - return total_header_bytes_written_; - } - // Returns total amount of body bytes that have been read. uint64_t total_body_bytes_read() const; @@ -210,16 +216,36 @@ virtual void OnTrailingHeadersComplete(bool fin, size_t frame_len, const QuicHeaderList& header_list); + virtual size_t WriteHeadersImpl( + spdy::SpdyHeaderBlock header_block, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + QuicSpdySession* spdy_session() const { return spdy_session_; } Visitor* visitor() { return visitor_; } void set_headers_decompressed(bool val) { headers_decompressed_ = val; } + void set_ack_listener( + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + ack_listener_ = std::move(ack_listener); + } + + const QuicIntervalSet<QuicStreamOffset>& unacked_frame_headers_offsets() { + return unacked_frame_headers_offsets_; + } + private: + friend class test::QuicSpdyStreamPeer; friend class test::QuicStreamPeer; friend class QuicStreamUtils; class HttpDecoderVisitor; + // Given the interval marked by [|offset|, |offset| + |data_length|), return + // the number of frame header bytes contained in it. + QuicByteCount GetNumFrameHeadersInInterval(QuicStreamOffset offset, + QuicByteCount data_length) const; + QuicSpdySession* spdy_session_; Visitor* visitor_; @@ -244,8 +270,13 @@ std::unique_ptr<HttpDecoderVisitor> http_decoder_visitor_; // Buffer that contains decoded data of the stream. QuicSpdyStreamBodyBuffer body_buffer_; - // Total bytes of header written to the stream. - size_t total_header_bytes_written_; + + // Ack listener of this stream, and it is notified when any of written bytes + // are acked or retransmitted. + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_; + + // Offset of unacked frame headers. + QuicIntervalSet<QuicStreamOffset> unacked_frame_headers_offsets_; }; } // namespace quic
diff --git a/quic/core/http/quic_spdy_stream_test.cc b/quic/core/http/quic_spdy_stream_test.cc index 07bb9ed..1aabe0e 100644 --- a/quic/core/http/quic_spdy_stream_test.cc +++ b/quic/core/http/quic_spdy_stream_test.cc
@@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/core/quic_connection.h" #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.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/core/quic_write_blocked_list.h" #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" @@ -24,6 +25,7 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_flow_controller_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_session_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_stream_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" @@ -32,7 +34,7 @@ using spdy::SpdyHeaderBlock; using spdy::SpdyPriority; using testing::_; -using testing::AnyNumber; +using testing::AtLeast; using testing::Invoke; using testing::Return; using testing::StrictMock; @@ -50,6 +52,11 @@ bool should_process_data) : QuicSpdyStream(id, session, BIDIRECTIONAL), should_process_data_(should_process_data) {} + ~TestStream() override = default; + + using QuicSpdyStream::set_ack_listener; + using QuicStream::CloseWriteSide; + using QuicStream::WriteOrBufferData; void OnBodyAvailable() override { if (!should_process_data_) { @@ -63,14 +70,23 @@ data_ += QuicString(buffer, bytes_read); } - using QuicSpdyStream::set_ack_listener; - using QuicStream::CloseWriteSide; - using QuicStream::WriteOrBufferData; + MOCK_METHOD1(WriteHeadersMock, void(bool fin)); + + size_t WriteHeadersImpl(spdy::SpdyHeaderBlock header_block, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> + ack_listener) override { + saved_headers_ = std::move(header_block); + WriteHeadersMock(fin); + return 0; + } const QuicString& data() const { return data_; } + const spdy::SpdyHeaderBlock& saved_headers() const { return saved_headers_; } private: bool should_process_data_; + spdy::SpdyHeaderBlock saved_headers_; QuicString data_; }; @@ -128,17 +144,21 @@ } void Initialize(bool stream_should_process_data) { - connection_ = new testing::StrictMock<MockQuicConnection>( + connection_ = new StrictMock<MockQuicConnection>( &helper_, &alarm_factory_, Perspective::IS_SERVER, SupportedVersions(GetParam())); - session_ = - QuicMakeUnique<testing::StrictMock<MockQuicSpdySession>>(connection_); + session_ = QuicMakeUnique<StrictMock<MockQuicSpdySession>>(connection_); session_->Initialize(); - stream_ = new TestStream(GetNthClientInitiatedBidirectionalId(0), - session_.get(), stream_should_process_data); + ON_CALL(*session_, WritevData(_, _, _, _, _)) + .WillByDefault(Invoke(MockQuicSession::ConsumeData)); + + stream_ = + new StrictMock<TestStream>(GetNthClientInitiatedBidirectionalId(0), + session_.get(), stream_should_process_data); session_->ActivateStream(QuicWrapUnique(stream_)); - stream2_ = new TestStream(GetNthClientInitiatedBidirectionalId(1), - session_.get(), stream_should_process_data); + stream2_ = + new StrictMock<TestStream>(GetNthClientInitiatedBidirectionalId(1), + session_.get(), stream_should_process_data); session_->ActivateStream(QuicWrapUnique(stream2_)); } @@ -149,8 +169,12 @@ } QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - *session_, n); + return GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), n); + } + + bool HasFrameHeader() const { + return VersionHasDataFrameHeader(connection_->transport_version()); } protected: @@ -168,9 +192,8 @@ HttpEncoder encoder_; }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSpdyStreamTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, QuicSpdyStreamTest, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSpdyStreamTest, ProcessHeaderList) { Initialize(kShouldProcessData); @@ -288,9 +311,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; EXPECT_EQ("", stream_->data()); QuicHeaderList headers = ProcessHeaders(false, headers_); @@ -310,9 +331,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; for (size_t fragment_size = 1; fragment_size < data.size(); ++fragment_size) { Initialize(kShouldProcessData); @@ -338,9 +357,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; for (size_t split_point = 1; split_point < data.size() - 1; ++split_point) { Initialize(kShouldProcessData); @@ -371,9 +388,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; ProcessHeaders(false, headers_); QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, @@ -399,9 +414,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; ProcessHeaders(false, headers_); QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, QuicStringPiece(data)); @@ -428,9 +441,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; ProcessHeaders(false, headers_); QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, @@ -456,13 +467,9 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body1.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data1 = connection_->transport_version() == QUIC_VERSION_99 - ? header + body1 - : body1; + QuicString data1 = HasFrameHeader() ? header + body1 : body1; header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buf); - QuicString data2 = connection_->transport_version() == QUIC_VERSION_99 - ? header + body2 - : body2; + QuicString data2 = HasFrameHeader() ? header + body2 : body2; ProcessHeaders(false, headers_); QuicStreamFrame frame1(GetNthClientInitiatedBidirectionalId(0), false, 0, @@ -486,9 +493,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; ProcessHeaders(false, headers_); QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, @@ -516,9 +521,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; ProcessHeaders(false, headers_); QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, @@ -558,17 +561,15 @@ // Try to send more data than the flow control limit allows. const uint64_t kOverflow = 15; QuicString body(kWindow + kOverflow, 'a'); - bool is_version_99 = connection_->transport_version() == QUIC_VERSION_99; - const uint64_t kHeaderLength = is_version_99 ? 2 : 0; - if (is_version_99) { - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(2, false))); + const uint64_t kHeaderLength = HasFrameHeader() ? 2 : 0; + if (HasFrameHeader()) { + EXPECT_CALL(*session_, WritevData(_, _, kHeaderLength, _, NO_FIN)); } EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kWindow - kHeaderLength, true))); EXPECT_CALL(*connection_, SendControlFrame(_)); - stream_->WriteOrBufferBody(body, false, nullptr); + stream_->WriteOrBufferBody(body, false); // Should have sent as much as possible, resulting in no send window left. EXPECT_EQ(0u, @@ -605,7 +606,7 @@ QuicByteCount header_length = 0; QuicString data; - if (connection_->transport_version() == QUIC_VERSION_99) { + if (HasFrameHeader()) { std::unique_ptr<char[]> buffer; header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); @@ -654,7 +655,7 @@ QuicByteCount header_length = 0; QuicString data; - if (connection_->transport_version() == QUIC_VERSION_99) { + if (HasFrameHeader()) { std::unique_ptr<char[]> buffer; header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); @@ -723,7 +724,7 @@ QuicString data2; QuicString body2(1, 'a'); - if (connection_->transport_version() == QUIC_VERSION_99) { + if (HasFrameHeader()) { body = QuicString(kWindow / 4 - 2, 'a'); std::unique_ptr<char[]> buffer; header_length = encoder_.SerializeDataFrameHeader(body.length(), &buffer); @@ -777,9 +778,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, QuicStringPiece(data)); EXPECT_CALL(*connection_, @@ -822,9 +821,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; EXPECT_LT(data.size(), kStreamWindow); QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), false, 0, @@ -853,10 +850,9 @@ EXPECT_CALL(*connection_, SendBlocked(GetNthClientInitiatedBidirectionalId(0))) .Times(0); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(0, fin))); + EXPECT_CALL(*session_, WritevData(_, _, 0, _, FIN)); - stream_->WriteOrBufferBody(body, fin, nullptr); + stream_->WriteOrBufferBody(body, fin); } TEST_P(QuicSpdyStreamTest, ReceivingTrailersViaHeaderList) { @@ -915,9 +911,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; // Receive trailing headers. SpdyHeaderBlock trailers_block; @@ -1052,9 +1046,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); QuicString header = QuicString(buf.get(), header_length); - QuicString data = connection_->transport_version() == QUIC_VERSION_99 - ? header + body - : body; + QuicString data = HasFrameHeader() ? header + body : body; QuicStreamFrame frame(GetNthClientInitiatedBidirectionalId(0), /*fin=*/true, 0, data); @@ -1067,18 +1059,15 @@ // Test that writing trailers will send a FIN, as Trailers are the last thing // to be sent on a stream. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers, without a FIN. - EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr); // Writing trailers implicitly sends a FIN. SpdyHeaderBlock trailers; trailers["trailer key"] = "trailer value"; - EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(true)); stream_->WriteTrailers(std::move(trailers), nullptr); EXPECT_TRUE(stream_->fin_sent()); } @@ -1087,23 +1076,21 @@ // Test that when writing trailers, the trailers that are actually sent to the // peer contain the final offset field indicating last byte of data. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers. - EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr); // Write non-zero body data to force a non-zero final offset. - QuicString body(1024, 'x'); // 1 MB + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); + QuicString body(1024, 'x'); // 1 kB QuicByteCount header_length = 0; - if (connection_->transport_version() == QUIC_VERSION_99) { + if (HasFrameHeader()) { std::unique_ptr<char[]> buf; header_length = encoder_.SerializeDataFrameHeader(body.length(), &buf); } - stream_->WriteOrBufferBody(body, false, nullptr); + stream_->WriteOrBufferBody(body, false); // The final offset field in the trailing headers is populated with the // number of body bytes written (including queued bytes). @@ -1112,31 +1099,29 @@ SpdyHeaderBlock trailers_with_offset(trailers.Clone()); trailers_with_offset[kFinalOffsetHeaderKey] = QuicTextUtils::Uint64ToString(body.length() + header_length); - EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(true)); stream_->WriteTrailers(std::move(trailers), nullptr); - EXPECT_EQ(trailers_with_offset, session_->GetWriteHeaders()); + EXPECT_EQ(trailers_with_offset, stream_->saved_headers()); } TEST_P(QuicSpdyStreamTest, WritingTrailersClosesWriteSide) { // Test that if trailers are written after all other data has been written // (headers and body), that this closes the stream for writing. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers. - EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr); // Write non-zero body data. - const int kBodySize = 1 * 1024; // 1 MB - stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false, nullptr); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); + const int kBodySize = 1 * 1024; // 1 kB + stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false); EXPECT_EQ(0u, stream_->BufferedDataBytes()); // Headers and body have been fully written, there is no queued data. Writing // trailers marks the end of this stream, and thus the write side is closed. - EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(true)); stream_->WriteTrailers(SpdyHeaderBlock(), nullptr); EXPECT_TRUE(stream_->write_side_closed()); } @@ -1146,35 +1131,30 @@ // while there are still body bytes queued. testing::InSequence seq; Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers. - EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/false, nullptr); // Write non-zero body data, but only consume partially, ensuring queueing. - const int kBodySize = 1 * 1024; // 1 KB - if (connection_->transport_version() == QUIC_VERSION_99) { - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(3, false))); + const int kBodySize = 1 * 1024; // 1 kB + if (HasFrameHeader()) { + EXPECT_CALL(*session_, WritevData(_, _, 3, _, NO_FIN)); } - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, kBodySize, _, NO_FIN)) .WillOnce(Return(QuicConsumedData(kBodySize - 1, false))); - stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false, nullptr); + stream_->WriteOrBufferBody(QuicString(kBodySize, 'x'), false); EXPECT_EQ(1u, stream_->BufferedDataBytes()); // Writing trailers will send a FIN, but not close the write side of the // stream as there are queued bytes. - EXPECT_CALL(*session_, WriteHeadersMock(_, _, true, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(true)); stream_->WriteTrailers(SpdyHeaderBlock(), nullptr); EXPECT_TRUE(stream_->fin_sent()); EXPECT_FALSE(stream_->write_side_closed()); // Writing the queued bytes will close the write side of the stream. - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(1, false))); + EXPECT_CALL(*session_, WritevData(_, _, 1, _, NO_FIN)); stream_->OnCanWrite(); EXPECT_TRUE(stream_->write_side_closed()); } @@ -1187,12 +1167,9 @@ // Test that it is not possible to write Trailers after a FIN has been sent. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Write the initial headers, with a FIN. - EXPECT_CALL(*session_, WriteHeadersMock(_, _, _, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(true)); stream_->WriteHeaders(SpdyHeaderBlock(), /*fin=*/true, nullptr); EXPECT_TRUE(stream_->fin_sent()); @@ -1204,9 +1181,7 @@ TEST_P(QuicSpdyStreamTest, HeaderStreamNotiferCorrespondingSpdyStream) { Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); testing::InSequence s; QuicReferenceCountedPointer<MockAckListener> ack_listener1( new MockAckListener()); @@ -1217,20 +1192,26 @@ session_->headers_stream()->WriteOrBufferData("Header1", false, ack_listener1); - stream_->WriteOrBufferBody("Test1", true, nullptr); + stream_->WriteOrBufferBody("Test1", true); session_->headers_stream()->WriteOrBufferData("Header2", false, ack_listener2); - stream2_->WriteOrBufferBody("Test2", false, nullptr); + stream2_->WriteOrBufferBody("Test2", false); QuicStreamFrame frame1( QuicUtils::GetHeadersStreamId(connection_->transport_version()), false, 0, "Header1"); - QuicStreamFrame frame2(stream_->id(), true, 0, "Test1"); + QuicString header = ""; + if (HasFrameHeader()) { + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = encoder_.SerializeDataFrameHeader(5, &buffer); + header = QuicString(buffer.get(), header_length); + } + QuicStreamFrame frame2(stream_->id(), true, 0, header + "Test1"); QuicStreamFrame frame3( QuicUtils::GetHeadersStreamId(connection_->transport_version()), false, 7, "Header2"); - QuicStreamFrame frame4(stream2_->id(), false, 0, "Test2"); + QuicStreamFrame frame4(stream2_->id(), false, 0, header + "Test2"); EXPECT_CALL(*ack_listener1, OnPacketRetransmitted(7)); session_->OnStreamFrameRetransmitted(frame1); @@ -1251,12 +1232,10 @@ TEST_P(QuicSpdyStreamTest, StreamBecomesZombieWithWriteThatCloses) { Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) - .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); QuicStreamPeer::CloseReadSide(stream_); // This write causes stream to be closed. - stream_->WriteOrBufferBody("Test1", true, nullptr); + stream_->WriteOrBufferBody("Test1", true); // stream_ has unacked data and should become zombie. EXPECT_TRUE(QuicContainsKey(QuicSessionPeer::zombie_streams(session_.get()), stream_->id())); @@ -1273,26 +1252,24 @@ testing::InSequence seq; Initialize(kShouldProcessData); - if (connection_->transport_version() == QUIC_VERSION_99) { - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(2, false))); + if (HasFrameHeader()) { + EXPECT_CALL(*session_, WritevData(_, _, 2, _, NO_FIN)); } - EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(4, true))); - stream_->WriteOrBufferBody("data", true, nullptr); + EXPECT_CALL(*session_, WritevData(_, _, 4, _, FIN)); + stream_->WriteOrBufferBody("data", true); stream_->OnPriorityFrame(kV3HighestPriority); EXPECT_EQ(kV3HighestPriority, stream_->priority()); } TEST_P(QuicSpdyStreamTest, SetPriorityBeforeUpdateStreamPriority) { - MockQuicConnection* connection = new testing::StrictMock<MockQuicConnection>( + MockQuicConnection* connection = new StrictMock<MockQuicConnection>( &helper_, &alarm_factory_, Perspective::IS_SERVER, SupportedVersions(GetParam())); std::unique_ptr<TestMockUpdateStreamSession> session( - new testing::StrictMock<TestMockUpdateStreamSession>(connection)); - TestStream* stream = new TestStream( - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(*session, - 0), + new StrictMock<TestMockUpdateStreamSession>(connection)); + auto stream = new StrictMock<TestStream>( + GetNthClientInitiatedBidirectionalStreamId( + session->connection()->transport_version(), 0), session.get(), /*should_process_data=*/true); session->ActivateStream(QuicWrapUnique(stream)); @@ -1309,6 +1286,233 @@ stream->SetPriority(kV3LowestPriority); } +TEST_P(QuicSpdyStreamTest, StreamWaitsForAcks) { + Initialize(kShouldProcessData); + QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( + new StrictMock<MockAckListener>); + stream_->set_ack_listener(mock_ack_listener); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); + // Stream is not waiting for acks initially. + EXPECT_FALSE(stream_->IsWaitingForAcks()); + EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); + + // Send kData1. + stream_->WriteOrBufferData("FooAndBar", false, nullptr); + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _)); + QuicByteCount newly_acked_length = 0; + EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + // Stream is not waiting for acks as all sent data is acked. + EXPECT_FALSE(stream_->IsWaitingForAcks()); + EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); + + // Send kData2. + stream_->WriteOrBufferData("FooAndBar", false, nullptr); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); + // Send FIN. + stream_->WriteOrBufferData("", true, nullptr); + // Fin only frame is not stored in send buffer. + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); + + // kData2 is retransmitted. + EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(9)); + stream_->OnStreamFrameRetransmitted(9, 9, false); + + // kData2 is acked. + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _)); + EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + // Stream is waiting for acks as FIN is not acked. + EXPECT_TRUE(stream_->IsWaitingForAcks()); + EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); + + // FIN is acked. + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _)); + EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 0, true, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_FALSE(stream_->IsWaitingForAcks()); + EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); +} + +TEST_P(QuicSpdyStreamTest, StreamDataGetAckedMultipleTimes) { + Initialize(kShouldProcessData); + QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( + new StrictMock<MockAckListener>); + stream_->set_ack_listener(mock_ack_listener); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); + // Send [0, 27) and fin. + stream_->WriteOrBufferData("FooAndBar", false, nullptr); + stream_->WriteOrBufferData("FooAndBar", false, nullptr); + stream_->WriteOrBufferData("FooAndBar", true, nullptr); + + // Ack [0, 9), [5, 22) and [18, 26) + // Verify [0, 9) 9 bytes are acked. + QuicByteCount newly_acked_length = 0; + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _)); + EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(2u, QuicStreamPeer::SendBuffer(stream_).size()); + // Verify [9, 22) 13 bytes are acked. + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(13, _)); + EXPECT_TRUE(stream_->OnStreamFrameAcked(5, 17, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); + // Verify [22, 26) 4 bytes are acked. + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(4, _)); + EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 8, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + + // Ack [0, 27). + // Verify [26, 27) 1 byte is acked. + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(1, _)); + EXPECT_TRUE(stream_->OnStreamFrameAcked(26, 1, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + + // Ack Fin. Verify OnPacketAcked is called. + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _)); + EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); + EXPECT_FALSE(stream_->IsWaitingForAcks()); + + // Ack [10, 27) and fin. + // No new data is acked, verify OnPacketAcked is not called. + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(_, _)).Times(0); + EXPECT_FALSE(stream_->OnStreamFrameAcked( + 10, 17, true, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); + EXPECT_FALSE(stream_->IsWaitingForAcks()); +} + +// HTTP/3 only. +TEST_P(QuicSpdyStreamTest, HeadersAckNotReportedWriteOrBufferBody) { + Initialize(kShouldProcessData); + if (!HasFrameHeader()) { + return; + } + QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( + new StrictMock<MockAckListener>); + stream_->set_ack_listener(mock_ack_listener); + QuicString body = "Test1"; + QuicString body2(100, 'x'); + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); + stream_->WriteOrBufferBody(body, false); + stream_->WriteOrBufferBody(body2, true); + + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = + encoder_.SerializeDataFrameHeader(body.length(), &buffer); + QuicString header = QuicString(buffer.get(), header_length); + + header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buffer); + QuicString header2 = QuicString(buffer.get(), header_length); + + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(body.length(), _)); + QuicStreamFrame frame(stream_->id(), false, 0, header + body); + EXPECT_TRUE( + session_->OnFrameAcked(QuicFrame(frame), QuicTime::Delta::Zero())); + + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _)); + QuicStreamFrame frame2(stream_->id(), false, (header + body).length(), + header2); + EXPECT_TRUE( + session_->OnFrameAcked(QuicFrame(frame2), QuicTime::Delta::Zero())); + + EXPECT_CALL(*mock_ack_listener, OnPacketAcked(body2.length(), _)); + QuicStreamFrame frame3(stream_->id(), true, + (header + body).length() + header2.length(), body2); + EXPECT_TRUE( + session_->OnFrameAcked(QuicFrame(frame3), QuicTime::Delta::Zero())); + + EXPECT_TRUE( + QuicSpdyStreamPeer::unacked_frame_headers_offsets(stream_).Empty()); +} + +// HTTP/3 only. +TEST_P(QuicSpdyStreamTest, HeadersAckNotReportedWriteBodySlices) { + Initialize(kShouldProcessData); + if (!HasFrameHeader()) { + return; + } + QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( + new StrictMock<MockAckListener>); + stream_->set_ack_listener(mock_ack_listener); + QuicString body = "Test1"; + QuicString body2(100, 'x'); + struct iovec body1_iov = {const_cast<char*>(body.data()), body.length()}; + struct iovec body2_iov = {const_cast<char*>(body2.data()), body2.length()}; + QuicMemSliceStorage storage(&body1_iov, 1, + helper_.GetStreamSendBufferAllocator(), 1024); + QuicMemSliceStorage storage2(&body2_iov, 1, + helper_.GetStreamSendBufferAllocator(), 1024); + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); + stream_->WriteBodySlices(storage.ToSpan(), false); + stream_->WriteBodySlices(storage2.ToSpan(), true); + + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = + encoder_.SerializeDataFrameHeader(body.length(), &buffer); + QuicString header = QuicString(buffer.get(), header_length); + + header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buffer); + QuicString header2 = QuicString(buffer.get(), header_length); + + EXPECT_CALL(*mock_ack_listener, + OnPacketAcked(body.length() + body2.length(), _)); + QuicStreamFrame frame(stream_->id(), true, 0, + header + body + header2 + body2); + EXPECT_TRUE( + session_->OnFrameAcked(QuicFrame(frame), QuicTime::Delta::Zero())); + + EXPECT_TRUE( + QuicSpdyStreamPeer::unacked_frame_headers_offsets(stream_).Empty()); +} + +// HTTP/3 only. +TEST_P(QuicSpdyStreamTest, HeaderBytesNotReportedOnRetransmission) { + Initialize(kShouldProcessData); + if (!HasFrameHeader()) { + return; + } + QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( + new StrictMock<MockAckListener>); + stream_->set_ack_listener(mock_ack_listener); + QuicString body = "Test1"; + QuicString body2(100, 'x'); + + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)).Times(AtLeast(1)); + stream_->WriteOrBufferBody(body, false); + stream_->WriteOrBufferBody(body2, true); + + std::unique_ptr<char[]> buffer; + QuicByteCount header_length = + encoder_.SerializeDataFrameHeader(body.length(), &buffer); + QuicString header = QuicString(buffer.get(), header_length); + + header_length = encoder_.SerializeDataFrameHeader(body2.length(), &buffer); + QuicString header2 = QuicString(buffer.get(), header_length); + + EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(body.length())); + QuicStreamFrame frame(stream_->id(), false, 0, header + body); + session_->OnStreamFrameRetransmitted(frame); + + EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(body2.length())); + QuicStreamFrame frame2(stream_->id(), true, (header + body).length(), + header2 + body2); + session_->OnStreamFrameRetransmitted(frame2); + + EXPECT_FALSE( + QuicSpdyStreamPeer::unacked_frame_headers_offsets(stream_).Empty()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/http/spdy_utils.cc b/quic/core/http/spdy_utils.cc index d8fc79d..aa6d6e7 100644 --- a/quic/core/http/spdy_utils.cc +++ b/quic/core/http/spdy_utils.cc
@@ -255,12 +255,12 @@ // Validate the scheme; this is to ensure a scheme of "foo://bar" is not // parsed as a URL of "foo://bar://baz" when combined with a host of "baz". std::string canonical_scheme; - url::StdStringCanonOutput canon_output(&canonical_scheme); + url::StdStringCanonOutput canon_scheme_output(&canonical_scheme); url::Component canon_component; url::Component scheme_component(0, scheme.size()); - if (!url::CanonicalizeScheme(scheme.data(), scheme_component, &canon_output, - &canon_component) || + if (!url::CanonicalizeScheme(scheme.data(), scheme_component, + &canon_scheme_output, &canon_component) || !canon_component.is_nonempty() || canon_component.begin != 0) { return QuicString(); } @@ -304,13 +304,13 @@ } } - // Validate the host by attempting to canoncalize it. Invalid characters + // Validate the host by attempting to canonicalize it. Invalid characters // will result in a canonicalization failure (e.g. '/') std::string canon_host; - canon_output = url::StdStringCanonOutput(&canon_host); + url::StdStringCanonOutput canon_host_output(&canon_host); canon_component.reset(); - if (!url::CanonicalizeHost(authority.data(), host_component, &canon_output, - &canon_component) || + if (!url::CanonicalizeHost(authority.data(), host_component, + &canon_host_output, &canon_component) || !canon_component.is_nonempty() || canon_component.begin != 0) { return QuicString(); }
diff --git a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc index 499c9fd..9d2be7c 100644 --- a/quic/core/qpack/offline/qpack_offline_decoder_bin.cc +++ b/quic/core/qpack/offline/qpack_offline_decoder_bin.cc
@@ -12,18 +12,21 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" int main(int argc, char* argv[]) { - InitGoogle(argv[0], &argc, &argv, false); + const char* usage = + "Usage: qpack_offline_decoder input_filename expected_headers_filename " + "...."; + std::vector<quic::QuicString> args = + quic::QuicParseCommandLineFlags(usage, argc, argv); - if (argc < 3 || argc % 2 != 1) { - QUIC_LOG(ERROR) << "Usage: " << argv[0] - << " input_filename expected_headers_filename ..."; + if (args.size() < 2 || args.size() % 2 != 0) { + quic::QuicPrintCommandLineFlagHelp(usage); return 1; } - int i; - for (i = 0; 2 * i + 1 < argc; ++i) { - const quic::QuicStringPiece input_filename(argv[2 * i + 1]); - const quic::QuicStringPiece expected_headers_filename(argv[2 * i + 2]); + size_t i; + for (i = 0; 2 * i < args.size(); ++i) { + const quic::QuicStringPiece input_filename(args[2 * i]); + const quic::QuicStringPiece expected_headers_filename(args[2 * i + 1]); // Every file represents a different connection, // therefore every file needs a fresh decoding context.
diff --git a/quic/core/qpack/qpack_decoded_headers_accumulator.cc b/quic/core/qpack/qpack_decoded_headers_accumulator.cc new file mode 100644 index 0000000..ac60fce --- /dev/null +++ b/quic/core/qpack/qpack_decoded_headers_accumulator.cc
@@ -0,0 +1,70 @@ +// 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. + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h" + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" + +namespace quic { + +QpackDecodedHeadersAccumulator::QpackDecodedHeadersAccumulator( + QuicStreamId id, + QpackDecoder* qpack_decoder) + : decoder_(qpack_decoder->DecodeHeaderBlock(id, this)), + uncompressed_header_bytes_(0), + compressed_header_bytes_(0), + error_detected_(false) { + quic_header_list_.OnHeaderBlockStart(); +} + +void QpackDecodedHeadersAccumulator::OnHeaderDecoded(QuicStringPiece name, + QuicStringPiece value) { + DCHECK(!error_detected_); + + uncompressed_header_bytes_ += name.size() + value.size(); + quic_header_list_.OnHeader(name, value); +} + +void QpackDecodedHeadersAccumulator::OnDecodingCompleted() {} + +void QpackDecodedHeadersAccumulator::OnDecodingErrorDetected( + QuicStringPiece error_message) { + DCHECK(!error_detected_); + + error_detected_ = true; + // Copy error message to ensure it remains valid for the lifetime of |this|. + error_message_.assign(error_message.data(), error_message.size()); +} + +bool QpackDecodedHeadersAccumulator::Decode(QuicStringPiece data) { + DCHECK(!error_detected_); + + compressed_header_bytes_ += data.size(); + decoder_->Decode(data); + + return !error_detected_; +} + +bool QpackDecodedHeadersAccumulator::EndHeaderBlock() { + DCHECK(!error_detected_); + + decoder_->EndHeaderBlock(); + + quic_header_list_.OnHeaderBlockEnd(uncompressed_header_bytes_, + compressed_header_bytes_); + + return !error_detected_; +} + +const QuicHeaderList& QpackDecodedHeadersAccumulator::quic_header_list() const { + DCHECK(!error_detected_); + return quic_header_list_; +} + +QuicStringPiece QpackDecodedHeadersAccumulator::error_message() const { + DCHECK(error_detected_); + return error_message_; +} + +} // namespace quic
diff --git a/quic/core/qpack/qpack_decoded_headers_accumulator.h b/quic/core/qpack/qpack_decoded_headers_accumulator.h new file mode 100644 index 0000000..47d4f63 --- /dev/null +++ b/quic/core/qpack/qpack_decoded_headers_accumulator.h
@@ -0,0 +1,64 @@ +// 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_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_ +#define QUICHE_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_ + +#include <cstddef> + +#include "net/third_party/quiche/src/quic/core/http/quic_header_list.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_progressive_decoder.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_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +class QpackDecoder; + +// A class that creates and owns a QpackProgressiveDecoder instance, accumulates +// decoded headers in a QuicHeaderList, and keeps track of uncompressed and +// compressed size so that it can be passed to QuicHeaderList::EndHeaderBlock(). +class QUIC_EXPORT_PRIVATE QpackDecodedHeadersAccumulator + : public QpackProgressiveDecoder::HeadersHandlerInterface { + public: + QpackDecodedHeadersAccumulator(QuicStreamId id, QpackDecoder* qpack_decoder); + virtual ~QpackDecodedHeadersAccumulator() = default; + + // QpackProgressiveDecoder::HeadersHandlerInterface implementation. + // These methods should only be called by |decoder_|. + void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override; + void OnDecodingCompleted() override; + void OnDecodingErrorDetected(QuicStringPiece error_message) override; + + // Decode payload data. Returns true on success, false on error. + // Must not be called if an error has been detected. + // Must not be called after EndHeaderBlock(). + bool Decode(QuicStringPiece data); + + // Signal end of HEADERS frame. Returns true on success, false on error. + // Must not be called if an error has been detected. + // Must not be called more that once. + bool EndHeaderBlock(); + + // Returns accumulated header list. + const QuicHeaderList& quic_header_list() const; + + // Returns error message. + // Must not be called unless an error has been detected. + QuicStringPiece error_message() const; + + private: + std::unique_ptr<QpackProgressiveDecoder> decoder_; + QuicHeaderList quic_header_list_; + size_t uncompressed_header_bytes_; + size_t compressed_header_bytes_; + bool error_detected_; + QuicString error_message_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QPACK_QPACK_DECODED_HEADERS_ACCUMULATOR_H_
diff --git a/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc b/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc new file mode 100644 index 0000000..0c71b19 --- /dev/null +++ b/quic/core/qpack/qpack_decoded_headers_accumulator_test.cc
@@ -0,0 +1,100 @@ +// 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. + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoded_headers_accumulator.h" + +#include <cstring> + +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder.h" +#include "net/third_party/quiche/src/quic/core/qpack/qpack_decoder_test_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" + +using ::testing::Eq; +using ::testing::StrictMock; + +namespace quic { +namespace test { +namespace { + +QuicStreamId kTestStreamId = 1; + +// Header Acknowledgement decoder stream instruction with stream_id = 1. +const char* const kHeaderAcknowledgement = "\x81"; + +} // anonymous namespace + +class QpackDecodedHeadersAccumulatorTest : public QuicTest { + protected: + QpackDecodedHeadersAccumulatorTest() + : qpack_decoder_(&encoder_stream_error_delegate_, + &decoder_stream_sender_delegate_), + accumulator_(kTestStreamId, &qpack_decoder_) {} + + NoopEncoderStreamErrorDelegate encoder_stream_error_delegate_; + StrictMock<MockDecoderStreamSenderDelegate> decoder_stream_sender_delegate_; + QpackDecoder qpack_decoder_; + QpackDecodedHeadersAccumulator accumulator_; +}; + +// HEADERS frame payload must have a complete Header Block Prefix. +TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyPayload) { + EXPECT_FALSE(accumulator_.EndHeaderBlock()); + EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message()); +} + +// HEADERS frame payload must have a complete Header Block Prefix. +TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedHeaderBlockPrefix) { + EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00"))); + EXPECT_FALSE(accumulator_.EndHeaderBlock()); + EXPECT_EQ("Incomplete header data prefix.", accumulator_.error_message()); +} + +TEST_F(QpackDecodedHeadersAccumulatorTest, EmptyHeaderList) { + EXPECT_CALL(decoder_stream_sender_delegate_, + WriteDecoderStreamData(Eq(kHeaderAcknowledgement))); + + EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("0000"))); + EXPECT_TRUE(accumulator_.EndHeaderBlock()); + + EXPECT_TRUE(accumulator_.quic_header_list().empty()); +} + +// This payload is the prefix of a valid payload, but EndHeaderBlock() is called +// before it can be completely decoded. +TEST_F(QpackDecodedHeadersAccumulatorTest, TruncatedPayload) { + EXPECT_TRUE(accumulator_.Decode(QuicTextUtils::HexDecode("00002366"))); + EXPECT_FALSE(accumulator_.EndHeaderBlock()); + EXPECT_EQ("Incomplete header block.", accumulator_.error_message()); +} + +// This payload is invalid because it refers to a non-existing static entry. +TEST_F(QpackDecodedHeadersAccumulatorTest, InvalidPayload) { + EXPECT_FALSE(accumulator_.Decode(QuicTextUtils::HexDecode("0000ff23ff24"))); + EXPECT_EQ("Static table entry not found.", accumulator_.error_message()); +} + +TEST_F(QpackDecodedHeadersAccumulatorTest, Success) { + EXPECT_CALL(decoder_stream_sender_delegate_, + WriteDecoderStreamData(Eq(kHeaderAcknowledgement))); + + QuicString encoded_data(QuicTextUtils::HexDecode("000023666f6f03626172")); + EXPECT_TRUE(accumulator_.Decode(encoded_data)); + EXPECT_TRUE(accumulator_.EndHeaderBlock()); + + auto header_list = accumulator_.quic_header_list(); + auto it = header_list.begin(); + EXPECT_TRUE(it != header_list.end()); + EXPECT_EQ("foo", it->first); + EXPECT_EQ("bar", it->second); + ++it; + EXPECT_TRUE(it == header_list.end()); + + EXPECT_EQ(strlen("foo") + strlen("bar"), + header_list.uncompressed_header_bytes()); + EXPECT_EQ(encoded_data.size(), header_list.compressed_header_bytes()); +} + +} // namespace test +} // namespace quic
diff --git a/quic/core/qpack/qpack_decoder_test.cc b/quic/core/qpack/qpack_decoder_test.cc index 52f739c..7292c50 100644 --- a/quic/core/qpack/qpack_decoder_test.cc +++ b/quic/core/qpack/qpack_decoder_test.cc
@@ -62,10 +62,8 @@ const FragmentMode fragment_mode_; }; -INSTANTIATE_TEST_CASE_P(, - QpackDecoderTest, - Values(FragmentMode::kSingleChunk, - FragmentMode::kOctetByOctet)); +INSTANTIATE_TEST_SUITE_P(, QpackDecoderTest, Values(FragmentMode::kSingleChunk, + FragmentMode::kOctetByOctet)); TEST_P(QpackDecoderTest, NoPrefix) { EXPECT_CALL(handler_,
diff --git a/quic/core/qpack/qpack_decoder_test_utils.h b/quic/core/qpack/qpack_decoder_test_utils.h index 937ecfc..ca5b608 100644 --- a/quic/core/qpack/qpack_decoder_test_utils.h +++ b/quic/core/qpack/qpack_decoder_test_utils.h
@@ -96,9 +96,9 @@ public: ~NoOpHeadersHandler() override = default; - void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override{}; - void OnDecodingCompleted() override{}; - void OnDecodingErrorDetected(QuicStringPiece error_message) override{}; + void OnHeaderDecoded(QuicStringPiece name, QuicStringPiece value) override {} + void OnDecodingCompleted() override {} + void OnDecodingErrorDetected(QuicStringPiece error_message) override {} }; void QpackDecode(
diff --git a/quic/core/qpack/qpack_encoder_test.cc b/quic/core/qpack/qpack_encoder_test.cc index e3dba00..6dea968 100644 --- a/quic/core/qpack/qpack_encoder_test.cc +++ b/quic/core/qpack/qpack_encoder_test.cc
@@ -37,10 +37,10 @@ const FragmentMode fragment_mode_; }; -INSTANTIATE_TEST_CASE_P(, - QpackEncoderTest, - Values(FragmentMode::kSingleChunk, - FragmentMode::kOctetByOctet)); +INSTANTIATE_TEST_SUITE_P(, + QpackEncoderTest, + Values(FragmentMode::kSingleChunk, + FragmentMode::kOctetByOctet)); TEST_P(QpackEncoderTest, Empty) { spdy::SpdyHeaderBlock header_list;
diff --git a/quic/core/qpack/qpack_instruction_decoder_test.cc b/quic/core/qpack/qpack_instruction_decoder_test.cc index d1fe9b5..08557ec 100644 --- a/quic/core/qpack/qpack_instruction_decoder_test.cc +++ b/quic/core/qpack/qpack_instruction_decoder_test.cc
@@ -101,10 +101,10 @@ const FragmentMode fragment_mode_; }; -INSTANTIATE_TEST_CASE_P(, - QpackInstructionDecoderTest, - Values(FragmentMode::kSingleChunk, - FragmentMode::kOctetByOctet)); +INSTANTIATE_TEST_SUITE_P(, + QpackInstructionDecoderTest, + Values(FragmentMode::kSingleChunk, + FragmentMode::kOctetByOctet)); TEST_P(QpackInstructionDecoderTest, SBitAndVarint2) { EXPECT_CALL(delegate_, OnInstructionDecoded(TestInstruction1()));
diff --git a/quic/core/qpack/qpack_instruction_encoder_test.cc b/quic/core/qpack/qpack_instruction_encoder_test.cc index 255520e..006476f 100644 --- a/quic/core/qpack/qpack_instruction_encoder_test.cc +++ b/quic/core/qpack/qpack_instruction_encoder_test.cc
@@ -43,10 +43,10 @@ const FragmentMode fragment_mode_; }; -INSTANTIATE_TEST_CASE_P(, - QpackInstructionEncoderTest, - Values(FragmentMode::kSingleChunk, - FragmentMode::kOctetByOctet)); +INSTANTIATE_TEST_SUITE_P(, + QpackInstructionEncoderTest, + Values(FragmentMode::kSingleChunk, + FragmentMode::kOctetByOctet)); TEST_P(QpackInstructionEncoderTest, Varint) { const QpackInstruction instruction{QpackInstructionOpcode{0x00, 0x80},
diff --git a/quic/core/qpack/qpack_round_trip_test.cc b/quic/core/qpack/qpack_round_trip_test.cc index b9c6300..700ff85 100644 --- a/quic/core/qpack/qpack_round_trip_test.cc +++ b/quic/core/qpack/qpack_round_trip_test.cc
@@ -56,7 +56,7 @@ const FragmentMode decoding_fragment_mode_; }; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( , QpackRoundTripTest, Combine(Values(FragmentMode::kSingleChunk, FragmentMode::kOctetByOctet),
diff --git a/quic/core/quic_arena_scoped_ptr_test.cc b/quic/core/quic_arena_scoped_ptr_test.cc index 52a8ae2..109fd37 100644 --- a/quic/core/quic_arena_scoped_ptr_test.cc +++ b/quic/core/quic_arena_scoped_ptr_test.cc
@@ -42,10 +42,10 @@ QuicOneBlockArena<1024> arena_; }; -INSTANTIATE_TEST_CASE_P(QuicArenaScopedPtrParamTest, - QuicArenaScopedPtrParamTest, - testing::Values(TestParam::kFromHeap, - TestParam::kFromArena)); +INSTANTIATE_TEST_SUITE_P(QuicArenaScopedPtrParamTest, + QuicArenaScopedPtrParamTest, + testing::Values(TestParam::kFromHeap, + TestParam::kFromArena)); TEST_P(QuicArenaScopedPtrParamTest, NullObjects) { QuicArenaScopedPtr<TestObject> def;
diff --git a/quic/core/quic_config.cc b/quic/core/quic_config.cc index ce6f9ea..e53719c 100644 --- a/quic/core/quic_config.cc +++ b/quic/core/quic_config.cc
@@ -14,6 +14,7 @@ #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" +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" @@ -492,7 +493,7 @@ } // TODO(ianswett) Use this for silent close on mobile, or delete. -ABSL_ATTRIBUTE_UNUSED void QuicConfig::SetSilentClose(bool silent_close) { +QUIC_UNUSED void QuicConfig::SetSilentClose(bool silent_close) { silent_close_.set(silent_close ? 1 : 0, silent_close ? 1 : 0); }
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index d4c13c4..6346ae0 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -26,6 +26,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/platform/api/quic_bug_tracker.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_exported_stats.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" @@ -43,10 +44,6 @@ namespace { -// Maximum number of acks received before sending an ack in response. -// TODO(fayang): Remove this constant when deprecating QUIC_VERSION_35. -const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20; - // Maximum number of consecutive sent nonretransmittable packets. const QuicPacketCount kMaxConsecutiveNonRetransmittablePackets = 19; @@ -63,10 +60,6 @@ // One eighth RTT delay when doing ack decimation. const float kShortAckDecimationDelay = 0.125; -// Error code used in WriteResult to indicate that the packet writer rejected -// the message as being too big. -const int kMessageTooBigErrorCode = EMSGSIZE; - // The minimum release time into future in ms. const int kMinReleaseTimeIntoFutureMs = 1; @@ -338,9 +331,7 @@ processing_ack_frame_(false), supports_release_time_(false), release_time_into_future_(QuicTime::Delta::Zero()), - no_version_negotiation_(supported_versions.size() == 1), - clear_probing_mark_after_packet_processing_(GetQuicReloadableFlag( - quic_clear_probing_mark_after_packet_processing)) { + no_version_negotiation_(supported_versions.size() == 1) { if (ack_mode_ == ACK_DECIMATION) { QUIC_RELOADABLE_FLAG_COUNT(quic_enable_ack_decimation); } @@ -466,8 +457,7 @@ if (config.HasClientSentConnectionOption(k5RTO, perspective_)) { close_connection_after_five_rtos_ = true; } - if (transport_version() != QUIC_VERSION_35 && - config.HasClientSentConnectionOption(kNSTP, perspective_)) { + if (config.HasClientSentConnectionOption(kNSTP, perspective_)) { no_stop_waiting_frames_ = true; } if (config.HasReceivedStatelessResetToken()) { @@ -688,6 +678,7 @@ server_supported_versions_ = packet.versions; if (GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_no_client_conn_ver_negotiation); CloseConnection( QUIC_INVALID_VERSION, QuicStrCat( @@ -815,6 +806,10 @@ if (level == ENCRYPTION_FORWARD_SECURE && perspective_ == Perspective::IS_SERVER) { sent_packet_manager_.SetHandshakeConfirmed(); + if (sent_packet_manager_.unacked_packets().use_uber_loss_algorithm()) { + // This may have changed the retransmission timer, so re-arm it. + SetRetransmissionAlarm(); + } } } @@ -909,11 +904,11 @@ return false; } - QUIC_BUG << ENDPOINT - << "Received an unencrypted data frame: closing connection" - << " packet_number:" << last_header_.packet_number - << " stream_id:" << frame.stream_id - << " received_packets:" << received_packet_manager_.ack_frame(); + QUIC_PEER_BUG << ENDPOINT + << "Received an unencrypted data frame: closing connection" + << " packet_number:" << last_header_.packet_number + << " stream_id:" << frame.stream_id << " received_packets:" + << received_packet_manager_.ack_frame(); CloseConnection(QUIC_UNENCRYPTED_STREAM_DATA, "Unencrypted stream data seen.", ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); @@ -926,8 +921,15 @@ } bool QuicConnection::OnCryptoFrame(const QuicCryptoFrame& frame) { - // TODO(nharper): Implement. - return false; + DCHECK(connected_); + + // Since a CRYPTO frame was received, this is not a connectivity probe. + // A probe only contains a PING and full padding. + UpdatePacketContent(NOT_PADDED_PING); + + visitor_->OnCryptoFrame(frame); + should_last_packet_instigate_acks_ = true; + return connected_; } bool QuicConnection::OnAckFrameStart(QuicPacketNumber largest_acked, @@ -1335,7 +1337,8 @@ if (debug_visitor_ != nullptr) { debug_visitor_->OnMessageFrame(frame); } - visitor_->OnMessageReceived(frame.message_data); + visitor_->OnMessageReceived( + QuicStringPiece(frame.data, frame.message_length)); should_last_packet_instigate_acks_ = true; return connected_; } @@ -1454,14 +1457,6 @@ void QuicConnection::MaybeQueueAck(bool was_missing) { ++num_packets_received_since_last_ack_sent_; - // Always send an ack every 20 packets in order to allow the peer to discard - // information from the SentPacketManager and provide an RTT measurement. - if (transport_version() == QUIC_VERSION_35 && - num_packets_received_since_last_ack_sent_ >= - kMaxPacketsReceivedBeforeAckSend) { - ack_queued_ = true; - } - // Determine whether the newly received packet was missing before recording // the received packet. if (was_missing) { @@ -1478,10 +1473,9 @@ if (should_last_packet_instigate_acks_ && !ack_queued_) { ++num_retransmittable_packets_received_since_last_ack_sent_; if (ack_mode_ != TCP_ACKING && - // TODO(fayang): Fix this as this check assumes the first received - // packet is 1. - last_header_.packet_number > - QuicPacketNumber(min_received_before_ack_decimation_)) { + last_header_.packet_number >= + received_packet_manager_.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_ >= @@ -1566,7 +1560,9 @@ sent_packet_manager_.GetLeastUnacked() + max_tracked_packets_) { CloseConnection( QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS, - QuicStrCat("More than ", max_tracked_packets_, " outstanding."), + QuicStrCat("More than ", max_tracked_packets_, + " outstanding, least_unacked: ", + sent_packet_manager_.GetLeastUnacked().ToUint64()), ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET); } } @@ -1648,6 +1644,18 @@ pending_version_negotiation_packet_ = false; } +size_t QuicConnection::SendCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset) { + if (write_length == 0) { + QUIC_BUG << "Attempt to send empty crypto frame"; + return 0; + } + + ScopedPacketFlusher flusher(this, SEND_ACK_IF_PENDING); + return packet_generator_.ConsumeCryptoData(level, write_length, offset); +} + QuicConsumedData QuicConnection::SendStreamData(QuicStreamId id, size_t write_length, QuicStreamOffset offset, @@ -1746,6 +1754,10 @@ return stats_; } +void QuicConnection::OnCoalescedPacket(const QuicEncryptedPacket& packet) { + QueueCoalescedPacket(packet); +} + void QuicConnection::ProcessUdpPacket(const QuicSocketAddress& self_address, const QuicSocketAddress& peer_address, const QuicReceivedPacket& packet) { @@ -1813,13 +1825,9 @@ << "Unable to process packet. Last packet processed: " << last_header_.packet_number; current_packet_data_ = nullptr; - if (clear_probing_mark_after_packet_processing_) { - if (is_current_packet_connectivity_probing_) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_clear_probing_mark_after_packet_processing, 1, 2); - } - is_current_packet_connectivity_probing_ = false; - } + is_current_packet_connectivity_probing_ = false; + + MaybeProcessCoalescedPackets(); return; } @@ -1840,17 +1848,12 @@ } } + MaybeProcessCoalescedPackets(); MaybeProcessUndecryptablePackets(); MaybeSendInResponseToPacket(); SetPingAlarm(); current_packet_data_ = nullptr; - if (clear_probing_mark_after_packet_processing_) { - if (is_current_packet_connectivity_probing_) { - QUIC_RELOADABLE_FLAG_COUNT_N( - quic_clear_probing_mark_after_packet_processing, 2, 2); - } - is_current_packet_connectivity_probing_ = false; - } + is_current_packet_connectivity_probing_ = false; } void QuicConnection::OnBlockedWriterCanWrite() { @@ -1965,16 +1968,17 @@ // Count those that would have been accepted if FLAGS..random_ipn // were true -- to detect/diagnose potential issues prior to // enabling the flag. - if ((header.packet_number > QuicPacketNumber(1)) && - (header.packet_number <= MaxRandomInitialPacketNumber())) { + if (header.packet_number > + received_packet_manager_.PeerFirstSendingPacketNumber() && + header.packet_number <= MaxRandomInitialPacketNumber()) { QUIC_CODE_COUNT_N(had_possibly_random_ipn, 2, 2); } bool out_of_bound = last_header_.packet_number.IsInitialized() ? !Near(header.packet_number, last_header_.packet_number) - // TODO(fayang): Fix this as this check assume the first received - // packet is 1. - : header.packet_number > QuicPacketNumber(kMaxPacketGap); + : header.packet_number >= + (received_packet_manager_.PeerFirstSendingPacketNumber() + + kMaxPacketGap); if (out_of_bound) { QUIC_DLOG(INFO) << ENDPOINT << "Packet " << header.packet_number << " out of bounds. Discarding"; @@ -2390,8 +2394,7 @@ bool QuicConnection::IsMsgTooBig(const WriteResult& result) { return (result.status == WRITE_STATUS_MSG_TOO_BIG) || - (IsWriteError(result.status) && - result.error_code == kMessageTooBigErrorCode); + (IsWriteError(result.status) && result.error_code == QUIC_EMSGSIZE); } bool QuicConnection::ShouldDiscardPacket(const SerializedPacket& packet) { @@ -2426,7 +2429,7 @@ "Write failed with error: ", error_code, " (", strerror(error_code), ")"); QUIC_LOG_FIRST_N(ERROR, 2) << ENDPOINT << error_details; switch (error_code) { - case kMessageTooBigErrorCode: + case QUIC_EMSGSIZE: CloseConnection( QUIC_PACKET_WRITE_ERROR, error_details, ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK); @@ -2469,15 +2472,13 @@ return; } - if (transport_version() != QUIC_VERSION_35) { - if (serialized_packet->retransmittable_frames.empty() && - !serialized_packet->original_packet_number.IsInitialized()) { - // Increment consecutive_num_packets_with_no_retransmittable_frames_ if - // this packet is a new transmission with no retransmittable frames. - ++consecutive_num_packets_with_no_retransmittable_frames_; - } else { - consecutive_num_packets_with_no_retransmittable_frames_ = 0; - } + if (serialized_packet->retransmittable_frames.empty() && + !serialized_packet->original_packet_number.IsInitialized()) { + // Increment consecutive_num_packets_with_no_retransmittable_frames_ if + // this packet is a new transmission with no retransmittable frames. + ++consecutive_num_packets_with_no_retransmittable_frames_; + } else { + consecutive_num_packets_with_no_retransmittable_frames_ = 0; } SendOrQueuePacket(serialized_packet); } @@ -2519,6 +2520,10 @@ void QuicConnection::OnHandshakeComplete() { sent_packet_manager_.SetHandshakeConfirmed(); + if (sent_packet_manager_.unacked_packets().use_uber_loss_algorithm()) { + // This may have changed the retransmission timer, so re-arm it. + SetRetransmissionAlarm(); + } // The client should immediately ack the SHLO to confirm the handshake is // complete with the server. if (perspective_ == Perspective::IS_CLIENT && !ack_queued_ && @@ -2712,6 +2717,44 @@ } } +void QuicConnection::QueueCoalescedPacket(const QuicEncryptedPacket& packet) { + QUIC_DVLOG(1) << ENDPOINT << "Queueing coalesced packet."; + coalesced_packets_.push_back(packet.Clone()); +} + +void QuicConnection::MaybeProcessCoalescedPackets() { + bool processed = false; + for (const auto& packet : coalesced_packets_) { + if (!connected_) { + return; + } + + // } + // while (connected_ && !coalesced_packets_.empty()) { + QUIC_DVLOG(1) << ENDPOINT << "Processing coalesced packet"; + // QuicEncryptedPacket* packet = coalesced_packets_.front().get(); + if (framer_.ProcessPacket(*packet)) { + processed = true; + } else { + // If we are unable to decrypt this packet, it might be + // because the CHLO or SHLO packet was lost. + if (framer_.error() == QUIC_DECRYPTION_FAILURE) { + if (encryption_level_ != ENCRYPTION_FORWARD_SECURE && + undecryptable_packets_.size() < max_undecryptable_packets_) { + QueueUndecryptablePacket(*packet); + } else if (debug_visitor_ != nullptr) { + debug_visitor_->OnUndecryptablePacket(); + } + } + } + // coalesced_packets_.pop_front(); + } + coalesced_packets_.clear(); + if (processed) { + MaybeProcessUndecryptablePackets(); + } +} + void QuicConnection::CloseConnection( QuicErrorCode error, const QuicString& error_details, @@ -3088,9 +3131,7 @@ return true; } if (save_crypto_packets_as_termination_packets_ && - frame.type == STREAM_FRAME && - frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(transport_version())) { + QuicUtils::IsHandshakeFrame(frame, transport_version())) { return true; } } @@ -3535,13 +3576,13 @@ } MessageStatus QuicConnection::SendMessage(QuicMessageId message_id, - QuicStringPiece message) { + QuicMemSliceSpan message) { if (transport_version() <= QUIC_VERSION_44) { QUIC_BUG << "MESSAGE frame is not supported for version " << transport_version(); return MESSAGE_STATUS_UNSUPPORTED; } - if (message.length() > GetLargestMessagePayload()) { + if (message.total_length() > GetLargestMessagePayload()) { return MESSAGE_STATUS_TOO_LARGE; } if (!CanWrite(HAS_RETRANSMITTABLE_DATA)) {
diff --git a/quic/core/quic_connection.h b/quic/core/quic_connection.h index 221754f..d27d0b7 100644 --- a/quic/core/quic_connection.h +++ b/quic/core/quic_connection.h
@@ -96,6 +96,9 @@ // A simple visitor interface for dealing with a data frame. virtual void OnStreamFrame(const QuicStreamFrame& frame) = 0; + // Called when a CRYPTO frame containing handshake data is received. + virtual void OnCryptoFrame(const QuicCryptoFrame& frame) = 0; + // The session should process the WINDOW_UPDATE frame, adjusting both stream // and connection level flow control windows. virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) = 0; @@ -231,9 +234,6 @@ // Called when a StreamFrame has been parsed. virtual void OnStreamFrame(const QuicStreamFrame& frame) {} - // Called when a AckFrame has been parsed. - virtual void OnAckFrame(const QuicAckFrame& frame) {} - // Called when a StopWaitingFrame has been parsed. virtual void OnStopWaitingFrame(const QuicStopWaitingFrame& frame) {} @@ -380,6 +380,13 @@ // Sets the number of active streams on the connection for congestion control. void SetNumOpenStreams(size_t num_streams); + // Sends crypto handshake messages of length |write_length| to the peer in as + // few packets as possible. Returns the number of bytes consumed from the + // data. + virtual size_t SendCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset); + // Send the data of length |write_length| to the peer in as few packets as // possible. Returns the number of bytes consumed from data, and a boolean // indicating if the fin bit was consumed. This does not indicate the data @@ -479,6 +486,7 @@ bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override; bool OnPacketHeader(const QuicPacketHeader& header) override; + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override; bool OnStreamFrame(const QuicStreamFrame& frame) override; bool OnCryptoFrame(const QuicCryptoFrame& frame) override; bool OnAckFrameStart(QuicPacketNumber largest_acked, @@ -748,7 +756,7 @@ // Tries to send |message| and returns the message status. virtual MessageStatus SendMessage(QuicMessageId message_id, - QuicStringPiece message); + QuicMemSliceSpan message); // Returns the largest payload that will fit into a single MESSAGE frame. QuicPacketLength GetLargestMessagePayload() const; @@ -847,6 +855,12 @@ // Attempts to process any queued undecryptable packets. void MaybeProcessUndecryptablePackets(); + // Queue a coalesced packet. + void QueueCoalescedPacket(const QuicEncryptedPacket& packet); + + // Process previously queued coalesced packets. + void MaybeProcessCoalescedPackets(); + enum PacketContent : uint8_t { NO_FRAMES_RECEIVED, // TODO(fkastenholz): Change name when we get rid of padded ping/ @@ -1156,6 +1170,10 @@ // sent with the INITIAL encryption and the CHLO message was lost. QuicDeque<std::unique_ptr<QuicEncryptedPacket>> undecryptable_packets_; + // Collection of coalesced packets which were received while processing + // the current packet. + QuicDeque<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_; + // Maximum number of undecryptable packets the connection will store. size_t max_undecryptable_packets_; @@ -1400,9 +1418,6 @@ // provided in constructor. const bool no_version_negotiation_; - // Latched value of --quic_clear_probing_mark_after_packet_processing. - const bool clear_probing_mark_after_packet_processing_; - // Payload of most recently transmitted QUIC_VERSION_99 connectivity // probe packet (the PATH_CHALLENGE payload). This implementation transmits // only one PATH_CHALLENGE per connectivity probe, so only one
diff --git a/quic/core/quic_connection_id.cc b/quic/core/quic_connection_id.cc index a86a5dd..25c5b1f 100644 --- a/quic/core/quic_connection_id.cc +++ b/quic/core/quic_connection_id.cc
@@ -19,18 +19,9 @@ namespace quic { -QuicConnectionId::QuicConnectionId() { - if (!QuicConnectionIdUseNetworkByteOrder()) { - id64_ = 0; - length_ = sizeof(uint64_t); - return; - } - length_ = 0; -} +QuicConnectionId::QuicConnectionId() : length_(0) {} QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) { - QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder()) - << "new constructor called when flag disabled"; if (length > kQuicMaxConnectionIdLength) { QUIC_BUG << "Attempted to create connection ID of length " << length; length = kQuicMaxConnectionIdLength; @@ -39,48 +30,15 @@ if (length_ > 0) { memcpy(data_, data, length_); } - QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 2, 3); -} - -QuicConnectionId::QuicConnectionId(uint64_t connection_id64) - : length_(sizeof(uint64_t)) { - if (!QuicConnectionIdUseNetworkByteOrder()) { - id64_ = connection_id64; - return; - } - QUIC_BUG_IF(QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT) && - QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) - << "old constructor called when flag enabled"; - const uint64_t connection_id64_net = QuicEndian::HostToNet64(connection_id64); - memcpy(&data_, &connection_id64_net, sizeof(connection_id64_net)); } QuicConnectionId::~QuicConnectionId() {} -uint64_t QuicConnectionId::ToUInt64() const { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return id64_; - } - QUIC_BUG_IF(QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT) && - QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) - << "ToUInt64 called when flag enabled"; - uint64_t connection_id64_net = 0; - memcpy(&connection_id64_net, &data_, - std::min<size_t>(static_cast<size_t>(length_), - sizeof(connection_id64_net))); - return QuicEndian::NetToHost64(connection_id64_net); -} - const char* QuicConnectionId::data() const { - QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder()) - << "data called when flag disabled"; - QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 3, 3); return data_; } char* QuicConnectionId::mutable_data() { - QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder()) - << "mutable_data called when flag disabled"; return data_; } @@ -89,35 +47,24 @@ } void QuicConnectionId::set_length(uint8_t length) { - QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder()) - << "set_length called when flag disabled"; length_ = length; } bool QuicConnectionId::IsEmpty() const { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return id64_ == 0; - } return length_ == 0; } size_t QuicConnectionId::Hash() const { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return id64_; - } uint64_t data_bytes[3] = {0, 0, 0}; static_assert(sizeof(data_bytes) >= sizeof(data_), "sizeof(data_) changed"); memcpy(data_bytes, data_, length_); - // This Hash function is designed to return the same value - // as ToUInt64() when the connection ID length is 64 bits. + // This Hash function is designed to return the same value as the host byte + // order representation when the connection ID length is 64 bits. return QuicEndian::NetToHost64(kQuicDefaultConnectionIdLength ^ length_ ^ data_bytes[0] ^ data_bytes[1] ^ data_bytes[2]); } QuicString QuicConnectionId::ToString() const { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return QuicTextUtils::Uint64ToString(id64_); - } if (IsEmpty()) { return QuicString("0"); } @@ -130,9 +77,6 @@ } bool QuicConnectionId::operator==(const QuicConnectionId& v) const { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return id64_ == v.id64_; - } return length_ == v.length_ && memcmp(data_, v.data_, length_) == 0; } @@ -141,9 +85,6 @@ } bool QuicConnectionId::operator<(const QuicConnectionId& v) const { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return id64_ < v.id64_; - } if (length_ < v.length_) { return true; } @@ -157,42 +98,6 @@ return QuicConnectionId(); } -QuicConnectionId QuicConnectionIdFromUInt64(uint64_t connection_id64) { - return QuicConnectionId(connection_id64); -} - -uint64_t QuicConnectionIdToUInt64(QuicConnectionId connection_id) { - return connection_id.ToUInt64(); -} - -bool QuicConnectionIdUseNetworkByteOrder() { - const bool res = GetQuicRestartFlag(quic_connection_ids_network_byte_order); - if (res) { - QUIC_RESTART_FLAG_COUNT(quic_connection_ids_network_byte_order); - } - return res; -} - -bool QuicConnectionIdSupportsVariableLength(Perspective perspective) { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return false; - } - bool res; - if (perspective == Perspective::IS_SERVER) { - res = GetQuicRestartFlag(quic_variable_length_connection_ids_server); - if (res) { - QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 1, - 3); - } - } else { - res = GetQuicRestartFlag(quic_variable_length_connection_ids_client); - if (res) { - QUIC_RESTART_FLAG_COUNT(quic_variable_length_connection_ids_client); - } - } - return res; -} - static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t), "kQuicDefaultConnectionIdLength changed"); static_assert(kQuicDefaultConnectionIdLength == PACKET_8BYTE_CONNECTION_ID,
diff --git a/quic/core/quic_connection_id.h b/quic/core/quic_connection_id.h index 5df72ec..06fecfb 100644 --- a/quic/core/quic_connection_id.h +++ b/quic/core/quic_connection_id.h
@@ -25,17 +25,12 @@ class QUIC_EXPORT_PRIVATE QuicConnectionId { public: - // Creates a connection ID of length zero, unless the restart flag - // quic_connection_ids_network_byte_order is false in which case - // it returns an 8-byte all-zeroes connection ID. + // Creates a connection ID of length zero. QuicConnectionId(); // Creates a connection ID from network order bytes. QuicConnectionId(const char* data, uint8_t length); - // Creator from host byte order uint64_t. - explicit QuicConnectionId(uint64_t connection_id64); - ~QuicConnectionId(); // Returns the length of the connection ID, in bytes. @@ -51,14 +46,9 @@ // in network byte order. char* mutable_data(); - // Returns whether the connection ID has length zero, unless the restart flag - // quic_connection_ids_network_byte_order is false in which case - // it checks if it is all zeroes. + // Returns whether the connection ID has length zero. bool IsEmpty() const; - // Converts to host byte order uint64_t. - uint64_t ToUInt64() const; - // Hash() is required to use connection IDs as keys in hash tables. size_t Hash() const; @@ -77,11 +67,10 @@ bool operator<(const QuicConnectionId& v) const; private: - // The connection ID is currently represented in host byte order in |id64_|. - // In the future, it will be saved in the first |length_| bytes of |data_|. + // The connection ID is represented in network byte order + // in the first |length_| bytes of |data_|. char data_[kQuicMaxConnectionIdLength]; uint8_t length_; - uint64_t id64_; // host byte order }; // Creates a connection ID of length zero, unless the restart flag @@ -89,16 +78,6 @@ // it returns an 8-byte all-zeroes connection ID. QUIC_EXPORT_PRIVATE QuicConnectionId EmptyQuicConnectionId(); -// Converts connection ID from host-byte-order uint64_t to QuicConnectionId. -// This is currently the identity function. -QUIC_EXPORT_PRIVATE QuicConnectionId -QuicConnectionIdFromUInt64(uint64_t connection_id64); - -// Converts connection ID from QuicConnectionId to host-byte-order uint64_t. -// This is currently the identity function. -QUIC_EXPORT_PRIVATE uint64_t -QuicConnectionIdToUInt64(QuicConnectionId connection_id); - // QuicConnectionIdHash can be passed as hash argument to hash tables. class QuicConnectionIdHash { public: @@ -107,16 +86,6 @@ } }; -// Governs how connection IDs are represented in memory. -// Checks gfe_restart_flag_quic_connection_ids_network_byte_order. -QUIC_EXPORT_PRIVATE bool QuicConnectionIdUseNetworkByteOrder(); - -enum class Perspective : uint8_t; -// Governs how connection IDs are created. -// Checks gfe_restart_flag_quic_variable_length_connection_ids_(client|server). -QUIC_EXPORT_PRIVATE bool QuicConnectionIdSupportsVariableLength( - Perspective perspective); - } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_CONNECTION_ID_H_
diff --git a/quic/core/quic_connection_id_test.cc b/quic/core/quic_connection_id_test.cc index 017e59e..1c7c761 100644 --- a/quic/core/quic_connection_id_test.cc +++ b/quic/core/quic_connection_id_test.cc
@@ -37,18 +37,10 @@ TEST_F(QuicConnectionIdTest, ZeroIsNotEmpty) { QuicConnectionId connection_id = test::TestConnectionId(0); - if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) { - // Zero is empty when connection IDs are represented in host byte order. - return; - } EXPECT_FALSE(connection_id.IsEmpty()); } TEST_F(QuicConnectionIdTest, Data) { - if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) { - // These methods are not allowed when the flag is off. - return; - } char connection_id_data[kQuicDefaultConnectionIdLength]; memset(connection_id_data, 0x42, sizeof(connection_id_data)); QuicConnectionId connection_id1 =
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index fe851fd..c56d2c1 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -19,6 +19,7 @@ #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_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" @@ -102,8 +103,7 @@ bool SetIV(QuicStringPiece iv) override { return true; } - bool EncryptPacket(QuicTransportVersion /*version*/, - uint64_t packet_number, + bool EncryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output, @@ -167,8 +167,7 @@ return true; } - bool DecryptPacket(QuicTransportVersion /*version*/, - uint64_t packet_number, + bool DecryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output, @@ -332,10 +331,10 @@ } if (next_packet_too_large_) { next_packet_too_large_ = false; - return WriteResult(WRITE_STATUS_ERROR, EMSGSIZE); + return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE); } if (always_get_packet_too_large_) { - return WriteResult(WRITE_STATUS_ERROR, EMSGSIZE); + return WriteResult(WRITE_STATUS_ERROR, QUIC_EMSGSIZE); } if (IsWriteBlocked()) { return WriteResult(is_write_blocked_data_buffered_ @@ -357,10 +356,6 @@ return WriteResult(WRITE_STATUS_OK, last_packet_size_); } - bool IsWriteBlockedDataBuffered() const override { - return is_write_blocked_data_buffered_; - } - bool ShouldWriteFail() { return write_should_fail_; } bool IsWriteBlocked() const override { return write_blocked_; } @@ -433,6 +428,10 @@ 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(); } @@ -643,8 +642,23 @@ // split needlessly across packet boundaries). As a result, we have separate // tests for some cases for this stream. QuicConsumedData SendCryptoStreamData() { - return SendStreamDataWithString( - QuicUtils::GetCryptoStreamId(transport_version()), "chlo", 0, NO_FIN); + QuicStreamOffset offset = 0; + QuicStringPiece data("chlo"); + if (transport_version() < QUIC_VERSION_47) { + return SendStreamDataWithString( + QuicUtils::GetCryptoStreamId(transport_version()), data, offset, + NO_FIN); + } + producer_.SaveCryptoData(ENCRYPTION_NONE, offset, data); + size_t bytes_written; + if (notifier_) { + bytes_written = + notifier_->WriteCryptoData(ENCRYPTION_NONE, data.length(), offset); + } else { + bytes_written = QuicConnection::SendCryptoData(ENCRYPTION_NONE, + data.length(), offset); + } + return QuicConsumedData(bytes_written, /*fin_consumed*/ false); } void set_version(ParsedQuicVersion version) { @@ -987,7 +1001,7 @@ QuicPacketCreatorPeer::FillPacketHeader(&peer_creator_, &header); char encrypted_buffer[kMaxPacketSize]; size_t length = peer_framer_.BuildDataPacket( - header, frames, encrypted_buffer, kMaxPacketSize); + header, frames, encrypted_buffer, kMaxPacketSize, ENCRYPTION_NONE); DCHECK_GT(length, 0u); const size_t encrypted_length = peer_framer_.EncryptInPlace( @@ -1135,7 +1149,7 @@ QuicStopWaitingFrame* frame, EncryptionLevel level) { return ProcessFramePacketAtLevel(number, QuicFrame(frame), - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } void ProcessGoAwayPacket(QuicGoAwayFrame* frame) { @@ -1336,9 +1350,9 @@ }; // Run all end to end tests with all supported versions. -INSTANTIATE_TEST_CASE_P(SupportedVersion, - QuicConnectionTest, - ::testing::ValuesIn(GetTestParams())); +INSTANTIATE_TEST_SUITE_P(SupportedVersion, + QuicConnectionTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicConnectionTest, SelfAddressChangeAtClient) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -1621,9 +1635,6 @@ connection_.GetStats().num_connectivity_probing_received; ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received); - if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) { - EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing()); - } EXPECT_EQ(num_probing_received, connection_.GetStats().num_connectivity_probing_received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); @@ -1723,9 +1734,6 @@ connection_.GetStats().num_connectivity_probing_received; ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received); - if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) { - EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing()); - } EXPECT_EQ(num_probing_received + 1, connection_.GetStats().num_connectivity_probing_received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); @@ -1786,9 +1794,6 @@ connection_.GetStats().num_connectivity_probing_received; ProcessReceivedPacket(kSelfAddress, kNewPeerAddress, *received); - if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) { - EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing()); - } EXPECT_EQ(num_probing_received + 1, connection_.GetStats().num_connectivity_probing_received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); @@ -1881,9 +1886,6 @@ connection_.GetStats().num_connectivity_probing_received; ProcessReceivedPacket(kSelfAddress, kPeerAddress, *received); - if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) { - EXPECT_FALSE(connection_.IsCurrentPacketConnectivityProbing()); - } EXPECT_EQ(num_probing_received, connection_.GetStats().num_connectivity_probing_received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); @@ -1929,9 +1931,6 @@ connection_.GetStats().num_connectivity_probing_received; ProcessReceivedPacket(kNewSelfAddress, kPeerAddress, *received); - if (!GetQuicReloadableFlag(quic_clear_probing_mark_after_packet_processing)) { - EXPECT_TRUE(connection_.IsCurrentPacketConnectivityProbing()); - } EXPECT_EQ(num_probing_received + 1, connection_.GetStats().num_connectivity_probing_received); EXPECT_EQ(kPeerAddress, connection_.peer_address()); @@ -1995,6 +1994,13 @@ header.version_flag = true; header.packet_number = QuicPacketNumber(1); + if (QuicVersionHasLongHeaderLengths( + peer_framer_.version().transport_version)) { + header.long_packet_type = INITIAL; + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + QuicFrames frames; QuicPaddingFrame padding; frames.push_back(QuicFrame(frame1_)); @@ -2028,6 +2034,13 @@ header.version_flag = true; header.packet_number = QuicPacketNumber(1); + if (QuicVersionHasLongHeaderLengths( + peer_framer_.version().transport_version)) { + header.long_packet_type = INITIAL; + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + QuicFrames frames; QuicPaddingFrame padding; frames.push_back(QuicFrame(frame1_)); @@ -2192,20 +2205,38 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(3); - // Should ack immediately since we have missing packets. - EXPECT_EQ(1u, writer_->packets_write_attempts()); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + // Should not cause an ack. + EXPECT_EQ(0u, writer_->packets_write_attempts()); + } else { + // Should ack immediately since we have missing packets. + EXPECT_EQ(1u, writer_->packets_write_attempts()); + } ProcessPacket(2); - // Should ack immediately since we have missing packets. - EXPECT_EQ(2u, writer_->packets_write_attempts()); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + // Should ack immediately, since this fills the last hole. + EXPECT_EQ(1u, writer_->packets_write_attempts()); + } else { + // Should ack immediately since we have missing packets. + EXPECT_EQ(2u, writer_->packets_write_attempts()); + } ProcessPacket(1); // Should ack immediately, since this fills the last hole. - EXPECT_EQ(3u, writer_->packets_write_attempts()); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_EQ(2u, writer_->packets_write_attempts()); + } else { + EXPECT_EQ(3u, writer_->packets_write_attempts()); + } ProcessPacket(4); // Should not cause an ack. - EXPECT_EQ(3u, writer_->packets_write_attempts()); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_EQ(2u, writer_->packets_write_attempts()); + } else { + EXPECT_EQ(3u, writer_->packets_write_attempts()); + } } TEST_P(QuicConnectionTest, OutOfOrderAckReceiptCausesNoAck) { @@ -2293,33 +2324,7 @@ ProcessAckPacket(&frame2); } -TEST_P(QuicConnectionTest, 20AcksCausesAckSend) { - if (connection_.version().transport_version != QUIC_VERSION_35) { - return; - } - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - SendStreamDataToPeer(1, "foo", 0, NO_FIN, nullptr); - - QuicAlarm* ack_alarm = QuicConnectionPeer::GetAckAlarm(&connection_); - // But an ack with no missing packets will not send an ack. - QuicAckFrame frame = InitAckFrame(1); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _)); - for (int i = 0; i < 19; ++i) { - ProcessAckPacket(&frame); - EXPECT_FALSE(ack_alarm->IsSet()); - } - EXPECT_EQ(1u, writer_->packets_write_attempts()); - // The 20th ack packet will cause an ack to be sent. - ProcessAckPacket(&frame); - EXPECT_EQ(2u, writer_->packets_write_attempts()); -} - TEST_P(QuicConnectionTest, AckSentEveryNthPacket) { - if (connection_.version().transport_version == QUIC_VERSION_35) { - return; - } - connection_.set_ack_frequency_before_ack_decimation(3); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); @@ -2363,10 +2368,6 @@ } TEST_P(QuicConnectionTest, AckNeedsRetransmittableFrames) { - if (connection_.version().transport_version == QUIC_VERSION_35) { - return; - } - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(99); @@ -2676,10 +2677,14 @@ // Parse the last packet and ensure it's the crypto stream frame. EXPECT_EQ(2u, writer_->frame_count()); - ASSERT_EQ(1u, writer_->stream_frames().size()); ASSERT_EQ(1u, writer_->padding_frames().size()); - EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()), - writer_->stream_frames()[0]->stream_id); + if (connection_.transport_version() < QUIC_VERSION_47) { + ASSERT_EQ(1u, writer_->stream_frames().size()); + EXPECT_EQ(QuicUtils::GetCryptoStreamId(connection_.transport_version()), + writer_->stream_frames()[0]->stream_id); + } else { + EXPECT_EQ(1u, writer_->crypto_frames().size()); + } } TEST_P(QuicConnectionTest, FramePackingCryptoThenNonCrypto) { @@ -3574,9 +3579,9 @@ NO_FIN, nullptr); EXPECT_EQ(0x01010101u, writer_->final_bytes_of_last_packet()); - connection_.SetEncrypter(ENCRYPTION_INITIAL, + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); SendStreamDataToPeer(3, "foo", 0, NO_FIN, nullptr); EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); @@ -3594,7 +3599,7 @@ // Packet should have been sent with ENCRYPTION_NONE. EXPECT_EQ(0x01010101u, writer_->final_bytes_of_previous_packet()); - // Packet should have been sent with ENCRYPTION_INITIAL. + // Packet should have been sent with ENCRYPTION_ZERO_RTT. EXPECT_EQ(0x02020202u, writer_->final_bytes_of_last_packet()); } @@ -3615,9 +3620,9 @@ EXPECT_EQ(1u, connection_.NumQueuedPackets()); // Switch to the new encrypter. - connection_.SetEncrypter(ENCRYPTION_INITIAL, + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); // Now become writeable and flush the packets. writer_->SetWritable(); @@ -3635,9 +3640,7 @@ connection_.SetEncrypter(ENCRYPTION_NONE, QuicMakeUnique<TaggingEncrypter>(0x01)); QuicPacketNumber packet_number; - SendStreamDataToPeer( - QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, - NO_FIN, &packet_number); + connection_.SendCryptoStreamData(); // Simulate the retransmission alarm firing and the socket blocking. BlockOnNextWrite(); @@ -3668,9 +3671,9 @@ QuicUtils::GetCryptoStreamId(connection_.transport_version()), "foo", 0, NO_FIN, nullptr); - connection_.SetEncrypter(ENCRYPTION_INITIAL, + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(0x02)); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); SendStreamDataToPeer(2, "bar", 0, NO_FIN, nullptr); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); @@ -3687,27 +3690,27 @@ use_tagging_decrypter(); const uint8_t tag = 0x07; - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. - ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Transition to the new encryption state and process another encrypted packet // which should result in the original packet being processed. - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - connection_.SetEncrypter(ENCRYPTION_INITIAL, + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2); - ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Finally, process a third packet and note that we do not reprocess the // buffered packet. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } TEST_P(QuicConnectionTest, TestRetransmitOrder) { @@ -3752,23 +3755,23 @@ use_tagging_decrypter(); const uint8_t tag = 0x07; - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. for (uint64_t i = 1; i <= 100; ++i) { - ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } // Transition to the new encryption state and process another encrypted packet // which should result in the original packets being processed. EXPECT_FALSE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); EXPECT_TRUE(connection_.GetProcessUndecryptablePacketsAlarm()->IsSet()); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - connection_.SetEncrypter(ENCRYPTION_INITIAL, + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + connection_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(100); @@ -3777,7 +3780,7 @@ // Finally, process a third packet and note that we do not reprocess the // buffered packet. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(102, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(102, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } TEST_P(QuicConnectionTest, SetRTOAfterWritingToSocket) { @@ -4932,7 +4935,9 @@ connection_.version().transport_version, kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_), &payload_length); + QuicPacketCreatorPeer::GetPacketNumberLength(creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), + QuicPacketCreatorPeer::GetLengthLength(creator_), &payload_length); connection_.SetMaxPacketLength(length); // Queue the first packet. @@ -4959,7 +4964,9 @@ connection_.version().transport_version, kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_), &payload_length); + QuicPacketCreatorPeer::GetPacketNumberLength(creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), + QuicPacketCreatorPeer::GetLengthLength(creator_), &payload_length); // GetPacketLengthForOneStream() assumes a stream offset of 0 in determining // packet length. The size of the offset field in a stream frame is // 0 for offset 0, and 2 for non-zero offsets up through 16K (for @@ -5049,17 +5056,17 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5087,17 +5094,17 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5119,7 +5126,7 @@ // 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_INITIAL); + ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5141,7 +5148,7 @@ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5163,9 +5170,9 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -5174,14 +5181,14 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5192,7 +5199,7 @@ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { @@ -5222,17 +5229,17 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5254,7 +5261,7 @@ // 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_INITIAL); + ProcessDataPacketAtLevel(2, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5276,7 +5283,7 @@ clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(3, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5290,14 +5297,14 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 4; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(4 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5308,7 +5315,7 @@ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { @@ -5326,7 +5333,7 @@ ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(1); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5355,9 +5362,9 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -5366,14 +5373,14 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5385,7 +5392,7 @@ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } // The delayed ack timer should still be set to the expected deadline. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5408,9 +5415,9 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -5419,14 +5426,14 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5437,7 +5444,7 @@ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { @@ -5471,9 +5478,9 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -5482,7 +5489,7 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); @@ -5492,7 +5499,7 @@ // 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_INITIAL); + !kHasStopWaiting, ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -5505,7 +5512,7 @@ // 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_INITIAL); + !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { @@ -5540,9 +5547,9 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -5551,14 +5558,14 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5567,7 +5574,7 @@ // Process packet 10 first and ensure the alarm is one eighth min_rtt. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -5577,7 +5584,7 @@ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { @@ -5595,7 +5602,7 @@ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { EXPECT_EQ(1u, writer_->frame_count()); @@ -5629,9 +5636,9 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -5640,14 +5647,14 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5656,7 +5663,7 @@ // Process packet 10 first and ensure the alarm is one eighth min_rtt. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 9, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -5666,7 +5673,7 @@ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { @@ -5702,9 +5709,9 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); const uint8_t tag = 0x07; - connection_.SetDecrypter(ENCRYPTION_INITIAL, + connection_.SetDecrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<StrictTaggingDecrypter>(tag)); - peer_framer_.SetEncrypter(ENCRYPTION_INITIAL, + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<TaggingEncrypter>(tag)); // Process a packet from the non-crypto stream. frame1_.stream_id = 3; @@ -5713,14 +5720,14 @@ uint64_t kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(1 + i, !kHasStopWaiting, ENCRYPTION_ZERO_RTT); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); - // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // The same as ProcessPacket(1) except that ENCRYPTION_ZERO_RTT is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -5729,7 +5736,7 @@ // Process packet 10 first and ensure the alarm is one eighth min_rtt. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 19, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); ack_time = clock_.ApproximateNow() + QuicTime::Delta::FromMilliseconds(5); EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); @@ -5739,7 +5746,7 @@ EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 1 + i, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); } // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { @@ -5757,7 +5764,7 @@ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); ProcessDataPacketAtLevel(kFirstDecimatedPacket + 10, !kHasStopWaiting, - ENCRYPTION_INITIAL); + ENCRYPTION_ZERO_RTT); // Check that ack is sent and that delayed ack alarm is reset. if (GetParam().no_stop_waiting) { EXPECT_EQ(1u, writer_->frame_count()); @@ -5810,23 +5817,46 @@ TEST_P(QuicConnectionTest, NoAckOnOldNacks) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Drop one packet, triggering a sequence of acks. + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + } else { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + } ProcessPacket(2); size_t frames_per_ack = GetParam().no_stop_waiting ? 1 : 2; - EXPECT_EQ(frames_per_ack, writer_->frame_count()); - EXPECT_FALSE(writer_->ack_frames().empty()); - writer_->Reset(); + if (!GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_EQ(frames_per_ack, writer_->frame_count()); + EXPECT_FALSE(writer_->ack_frames().empty()); + writer_->Reset(); + } + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessPacket(3); EXPECT_EQ(frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); + + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + } else { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + } ProcessPacket(4); - EXPECT_EQ(frames_per_ack, writer_->frame_count()); - EXPECT_FALSE(writer_->ack_frames().empty()); - writer_->Reset(); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_EQ(0u, writer_->frame_count()); + } else { + EXPECT_EQ(frames_per_ack, writer_->frame_count()); + EXPECT_FALSE(writer_->ack_frames().empty()); + writer_->Reset(); + } + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); ProcessPacket(5); EXPECT_EQ(frames_per_ack, writer_->frame_count()); EXPECT_FALSE(writer_->ack_frames().empty()); writer_->Reset(); + + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); // Now only set the timer on the 6th packet, instead of sending another ack. ProcessPacket(6); EXPECT_EQ(0u, writer_->frame_count()); @@ -5904,7 +5934,11 @@ EXPECT_EQ(4u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } - EXPECT_EQ(1u, writer_->stream_frames().size()); + if (connection_.transport_version() < QUIC_VERSION_47) { + EXPECT_EQ(1u, writer_->stream_frames().size()); + } else { + EXPECT_EQ(1u, writer_->crypto_frames().size()); + } EXPECT_EQ(1u, writer_->padding_frames().size()); ASSERT_FALSE(writer_->ack_frames().empty()); EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front())); @@ -5933,7 +5967,11 @@ EXPECT_EQ(4u, writer_->frame_count()); EXPECT_FALSE(writer_->stop_waiting_frames().empty()); } - EXPECT_EQ(1u, writer_->stream_frames().size()); + if (connection_.transport_version() < QUIC_VERSION_47) { + EXPECT_EQ(1u, writer_->stream_frames().size()); + } else { + EXPECT_EQ(1u, writer_->crypto_frames().size()); + } EXPECT_EQ(1u, writer_->padding_frames().size()); ASSERT_FALSE(writer_->ack_frames().empty()); EXPECT_EQ(QuicPacketNumber(2u), LargestAcked(writer_->ack_frames().front())); @@ -6214,6 +6252,13 @@ header.version_flag = true; header.packet_number = QuicPacketNumber(12); + if (QuicVersionHasLongHeaderLengths( + peer_framer_.version().transport_version)) { + header.long_packet_type = INITIAL; + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + QuicFrames frames; frames.push_back(QuicFrame(frame1_)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); @@ -6259,6 +6304,13 @@ header.version_flag = true; header.packet_number = QuicPacketNumber(12); + if (QuicVersionHasLongHeaderLengths( + peer_framer_.version().transport_version)) { + header.long_packet_type = INITIAL; + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + QuicFrames frames; frames.push_back(QuicFrame(frame1_)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); @@ -6311,6 +6363,13 @@ header.version_flag = true; header.packet_number = QuicPacketNumber(12); + if (QuicVersionHasLongHeaderLengths( + peer_framer_.version().transport_version)) { + header.long_packet_type = INITIAL; + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + QuicFrames frames; frames.push_back(QuicFrame(frame1_)); std::unique_ptr<QuicPacket> packet(ConstructPacket(header, frames)); @@ -7586,6 +7645,7 @@ } QuicString message(connection_.GetLargestMessagePayload() * 2, 'a'); QuicStringPiece message_data(message); + QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); { QuicConnection::ScopedPacketFlusher flusher(&connection_, QuicConnection::SEND_ACK); @@ -7594,22 +7654,32 @@ // get sent, one contains stream frame, and the other only contains the // message frame. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2); - EXPECT_EQ(MESSAGE_STATUS_SUCCESS, - connection_.SendMessage( - 1, QuicStringPiece(message_data.data(), - connection_.GetLargestMessagePayload()))); + EXPECT_EQ( + MESSAGE_STATUS_SUCCESS, + connection_.SendMessage( + 1, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + QuicStringPiece(message_data.data(), + connection_.GetLargestMessagePayload()), + &storage))); } // Fail to send a message if connection is congestion control blocked. EXPECT_CALL(*send_algorithm_, CanSend(_)).WillOnce(Return(false)); - EXPECT_EQ(MESSAGE_STATUS_BLOCKED, connection_.SendMessage(2, "message")); + EXPECT_EQ( + MESSAGE_STATUS_BLOCKED, + connection_.SendMessage( + 2, MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + "message", &storage))); // Always fail to send a message which cannot fit into one packet. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); EXPECT_EQ( MESSAGE_STATUS_TOO_LARGE, connection_.SendMessage( - 3, QuicStringPiece(message_data.data(), - connection_.GetLargestMessagePayload() + 1))); + 3, + MakeSpan(connection_.helper()->GetStreamSendBufferAllocator(), + QuicStringPiece(message_data.data(), + connection_.GetLargestMessagePayload() + 1), + &storage))); } // Test to check that the path challenge/path response logic works
diff --git a/quic/core/quic_control_frame_manager.cc b/quic/core/quic_control_frame_manager.cc index c2b5192..8d4ba53 100644 --- a/quic/core/quic_control_frame_manager.cc +++ b/quic/core/quic_control_frame_manager.cc
@@ -88,25 +88,6 @@ new QuicStopSendingFrame(++last_control_frame_id_, stream_id, code))); } -void QuicControlFrameManager::WriteOrBufferRstStreamStopSending( - QuicStreamId stream_id, - QuicRstStreamErrorCode error_code, - QuicStreamOffset bytes_written) { - const bool had_buffered_frames = HasBufferedFrames(); - QUIC_DVLOG(1) << "Queuing RST_STREAM_FRAME"; - control_frames_.emplace_back(QuicFrame(new QuicRstStreamFrame( - ++last_control_frame_id_, stream_id, error_code, bytes_written))); - if (session_->connection()->transport_version() == QUIC_VERSION_99) { - QUIC_DVLOG(1) << "Version 99, Queuing STOP_SENDING"; - control_frames_.emplace_back(QuicFrame(new QuicStopSendingFrame( - ++last_control_frame_id_, stream_id, error_code))); - } - if (had_buffered_frames) { - return; - } - WriteBufferedFrames(); -} - void QuicControlFrameManager::WritePing() { QUIC_DVLOG(1) << "Writing PING_FRAME"; if (HasBufferedFrames()) {
diff --git a/quic/core/quic_control_frame_manager.h b/quic/core/quic_control_frame_manager.h index ace08c6..618f3f9 100644 --- a/quic/core/quic_control_frame_manager.h +++ b/quic/core/quic_control_frame_manager.h
@@ -61,13 +61,6 @@ // immediately. void WriteOrBufferMaxStreamId(QuicStreamId id); - // Tries to send a packet with both a RST_STREAM and, if version 99, an - // IETF-QUIC STOP_SENDING frame. The frames are buffered if they can not - // be sent immediately. - void WriteOrBufferRstStreamStopSending(QuicControlFrameId stream_id, - QuicRstStreamErrorCode error_code, - QuicStreamOffset bytes_written); - // 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);
diff --git a/quic/core/quic_crypto_client_handshaker.cc b/quic/core/quic_crypto_client_handshaker.cc index 81487df..43948c2 100644 --- a/quic/core/quic_crypto_client_handshaker.cc +++ b/quic/core/quic_crypto_client_handshaker.cc
@@ -95,7 +95,7 @@ proof_handler_(proof_handler), verify_ok_(false), stateless_reject_received_(false), - proof_verify_start_time_(QuicWallTime::Zero()), + proof_verify_start_time_(QuicTime::Zero()), num_scup_messages_received_(0), encryption_established_(false), handshake_confirmed_(false), @@ -272,7 +272,7 @@ // the proof. DCHECK(crypto_config_->proof_verifier()); // Track proof verification time when cached server config is used. - proof_verify_start_time_ = session()->connection()->clock()->WallNow(); + proof_verify_start_time_ = session()->connection()->clock()->Now(); chlo_hash_ = cached->chlo_hash(); // If the cached state needs to be verified, do it now. next_state_ = STATE_VERIFY_PROOF; @@ -381,15 +381,15 @@ SendHandshakeMessage(out); // Be prepared to decrypt with the new server write key. session()->connection()->SetAlternativeDecrypter( - ENCRYPTION_INITIAL, + ENCRYPTION_ZERO_RTT, std::move(crypto_negotiated_params_->initial_crypters.decrypter), true /* latch once used */); // Send subsequent packets under encryption on the assumption that the // server will accept the handshake. session()->connection()->SetEncrypter( - ENCRYPTION_INITIAL, + ENCRYPTION_ZERO_RTT, std::move(crypto_negotiated_params_->initial_crypters.encrypter)); - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); // TODO(ianswett): Merge ENCRYPTION_REESTABLISHED and // ENCRYPTION_FIRST_ESTABLSIHED @@ -498,12 +498,10 @@ void QuicCryptoClientHandshaker::DoVerifyProofComplete( QuicCryptoClientConfig::CachedState* cached) { - if (!proof_verify_start_time_.IsZero()) { + if (proof_verify_start_time_.IsInitialized()) { QUIC_CLIENT_HISTOGRAM_TIMES( "QuicSession.VerifyProofTime.CachedServerConfig", - QuicTime::Delta::FromMicroseconds( - session()->connection()->clock()->WallNow().ToUNIXMicroseconds() - - proof_verify_start_time_.ToUNIXMicroseconds()), + (session()->connection()->clock()->Now() - proof_verify_start_time_), QuicTime::Delta::FromMilliseconds(1), QuicTime::Delta::FromSeconds(10), 50, ""); }
diff --git a/quic/core/quic_crypto_client_handshaker.h b/quic/core/quic_crypto_client_handshaker.h index 14fe0a8..c84c2cd 100644 --- a/quic/core/quic_crypto_client_handshaker.h +++ b/quic/core/quic_crypto_client_handshaker.h
@@ -222,7 +222,7 @@ // STATE_VERIFY_PROOF*, and subsequent STATE_SEND_CHLO state. bool stateless_reject_received_; - QuicWallTime proof_verify_start_time_; + QuicTime proof_verify_start_time_; int num_scup_messages_received_;
diff --git a/quic/core/quic_crypto_handshaker.cc b/quic/core/quic_crypto_handshaker.cc index dab2741..fa0f78a 100644 --- a/quic/core/quic_crypto_handshaker.cc +++ b/quic/core/quic_crypto_handshaker.cc
@@ -26,8 +26,8 @@ session()->OnCryptoHandshakeMessageSent(message); last_sent_handshake_message_tag_ = message.tag(); const QuicData& data = message.GetSerialized(); - stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false, - nullptr); + stream_->WriteCryptoData(session_->connection()->encryption_level(), + data.AsStringPiece()); } void QuicCryptoHandshaker::OnError(CryptoFramer* framer) {
diff --git a/quic/core/quic_crypto_server_handshaker.cc b/quic/core/quic_crypto_server_handshaker.cc index e79a60c..08ef18b 100644 --- a/quic/core/quic_crypto_server_handshaker.cc +++ b/quic/core/quic_crypto_server_handshaker.cc
@@ -225,13 +225,13 @@ // // NOTE: the SHLO will be encrypted with the new server write key. session()->connection()->SetEncrypter( - ENCRYPTION_INITIAL, + ENCRYPTION_ZERO_RTT, std::move(crypto_negotiated_params_->initial_crypters.encrypter)); - session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); // Set the decrypter immediately so that we no longer accept unencrypted // packets. session()->connection()->SetDecrypter( - ENCRYPTION_INITIAL, + ENCRYPTION_ZERO_RTT, std::move(crypto_negotiated_params_->initial_crypters.decrypter)); session()->connection()->SetDiversificationNonce(*diversification_nonce); @@ -310,9 +310,13 @@ QUIC_DVLOG(1) << "Server: Sending server config update: " << message.DebugString(); - const QuicData& data = message.GetSerialized(); - stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), false, - nullptr); + if (transport_version() < QUIC_VERSION_47) { + const QuicData& data = message.GetSerialized(); + stream_->WriteOrBufferData(QuicStringPiece(data.data(), data.length()), + false, nullptr); + } else { + SendHandshakeMessage(message); + } ++num_server_config_update_messages_sent_; } @@ -352,6 +356,11 @@ QuicLongHeaderType QuicCryptoServerHandshaker::GetLongHeaderType( QuicStreamOffset /*offset*/) const { if (last_sent_handshake_message_tag() == kSREJ) { + if (QuicVersionHasLongHeaderLengths( + session()->connection()->transport_version())) { + return HANDSHAKE; + } + // TODO(b/123493765): we should probably not be sending RETRY here. return RETRY; } if (last_sent_handshake_message_tag() == kSHLO) {
diff --git a/quic/core/quic_crypto_server_stream_test.cc b/quic/core/quic_crypto_server_stream_test.cc index 33635d8..c0a3e08 100644 --- a/quic/core/quic_crypto_server_stream_test.cc +++ b/quic/core/quic_crypto_server_stream_test.cc
@@ -189,7 +189,7 @@ ParsedQuicVersionVector supported_versions_ = AllSupportedVersions(); }; -INSTANTIATE_TEST_CASE_P(Tests, QuicCryptoServerStreamTest, testing::Bool()); +INSTANTIATE_TEST_SUITE_P(Tests, QuicCryptoServerStreamTest, testing::Bool()); TEST_P(QuicCryptoServerStreamTest, NotInitiallyConected) { Initialize(); @@ -497,9 +497,9 @@ std::unique_ptr<FailingProofSource>(new FailingProofSource)) {} }; -INSTANTIATE_TEST_CASE_P(MoreTests, - QuicCryptoServerStreamTestWithFailingProofSource, - testing::Bool()); +INSTANTIATE_TEST_SUITE_P(MoreTests, + QuicCryptoServerStreamTestWithFailingProofSource, + testing::Bool()); TEST_P(QuicCryptoServerStreamTestWithFailingProofSource, Test) { Initialize(); @@ -531,9 +531,9 @@ QuicCryptoServerConfigPeer crypto_config_peer_; }; -INSTANTIATE_TEST_CASE_P(YetMoreTests, - QuicCryptoServerStreamTestWithFakeProofSource, - testing::Bool()); +INSTANTIATE_TEST_SUITE_P(YetMoreTests, + QuicCryptoServerStreamTestWithFakeProofSource, + testing::Bool()); // Regression test for b/35422225, in which multiple CHLOs arriving on the same // connection in close succession could cause a crash, especially when the use
diff --git a/quic/core/quic_crypto_stream.cc b/quic/core/quic_crypto_stream.cc index 8199571..43d1f1a 100644 --- a/quic/core/quic_crypto_stream.cc +++ b/quic/core/quic_crypto_stream.cc
@@ -27,7 +27,10 @@ session->connection()->transport_version()), session, /*is_static=*/true, - BIDIRECTIONAL) { + BIDIRECTIONAL), + substreams_{{this, ENCRYPTION_NONE}, + {this, ENCRYPTION_ZERO_RTT}, + {this, ENCRYPTION_FORWARD_SECURE}} { // The crypto stream is exempt from connection level flow control. DisableConnectionFlowControlForThisStream(); } @@ -43,56 +46,57 @@ /*include_diversification_nonce=*/true, version > QUIC_VERSION_43 ? PACKET_4BYTE_PACKET_NUMBER : PACKET_1BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_1, VARIABLE_LENGTH_INTEGER_LENGTH_2, /*offset=*/0); } -void QuicCryptoStream::OnDataAvailable() { - struct iovec iov; - // When calling CryptoMessageParser::ProcessInput, an EncryptionLevel needs to - // be provided. Note that in the general case, the following code may be - // incorrect. When a stream frame is added to the sequencer, the encryption - // level provided by the connection will be the encryption level that the - // frame was received under, but stream frames can be received out of order. - // If a later stream frame at a higher encryption level is received before an - // earlier stream frame at a lower encryption level, this code will call - // CryptoMessageParser::Process input with the data from both frames, but - // indicate that they both were received at the higher encryption level. - // - // For QUIC crypto, this is not a problem, because the CryptoFramer (which - // implements CryptoMessageParser) ignores the EncryptionLevel passed into - // ProcessInput. - // - // For the TLS handshake, this does not cause an issue for the transition from - // initial encryption (ClientHello, HelloRetryRequest, and ServerHello) to - // handshake encryption, as all data from the initial encryption level is - // needed to derive the handshake encryption keys. For the transition from - // handshake encryption to 1-RTT application data encryption, all messages at - // the handshake encryption level *except* the client Finished are needed. The - // only place this logic would be broken is if a server receives a crypto - // handshake message that is encrypted under the 1-RTT data keys before - // receiving the client's Finished message (under handshake encryption keys). - // Right now, this implementation of TLS in QUIC does not support doing that, - // but it is possible (although unlikely) that other implementations could. - // Therefore, this needs to be fixed before the TLS handshake is enabled. - // - // TODO(nharper): Use a more robust and correct mechanism to provide the - // EncryptionLevel to CryptoMessageParser::ProcessInput. This must be done - // before enabling the TLS handshake. +void QuicCryptoStream::OnCryptoFrame(const QuicCryptoFrame& frame) { + QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47) + << "Versions less than 47 shouldn't receive CRYPTO frames"; EncryptionLevel level = session()->connection()->last_decrypted_level(); - while (sequencer()->GetReadableRegion(&iov)) { + substreams_[level].sequencer.OnCryptoFrame(frame); +} + +void QuicCryptoStream::OnStreamFrame(const QuicStreamFrame& frame) { + if (session()->connection()->transport_version() >= QUIC_VERSION_47) { + QUIC_PEER_BUG + << "Crypto data received in stream frame instead of crypto frame"; + CloseConnectionWithDetails(QUIC_INVALID_STREAM_DATA, + "Unexpected stream frame"); + } + QuicStream::OnStreamFrame(frame); +} + +void QuicCryptoStream::OnDataAvailable() { + EncryptionLevel level = session()->connection()->last_decrypted_level(); + if (session()->connection()->transport_version() < QUIC_VERSION_47) { + // Versions less than 47 only support QUIC crypto, which ignores the + // EncryptionLevel passed into CryptoMessageParser::ProcessInput (and + // OnDataAvailableInSequencer). + OnDataAvailableInSequencer(sequencer(), level); + return; + } + OnDataAvailableInSequencer(&substreams_[level].sequencer, level); +} + +void QuicCryptoStream::OnDataAvailableInSequencer( + QuicStreamSequencer* sequencer, + EncryptionLevel level) { + struct iovec iov; + while (sequencer->GetReadableRegion(&iov)) { QuicStringPiece data(static_cast<char*>(iov.iov_base), iov.iov_len); if (!crypto_message_parser()->ProcessInput(data, level)) { CloseConnectionWithDetails(crypto_message_parser()->error(), crypto_message_parser()->error_detail()); return; } - sequencer()->MarkConsumed(iov.iov_len); + sequencer->MarkConsumed(iov.iov_len); if (handshake_confirmed() && crypto_message_parser()->InputBytesRemaining() == 0) { // If the handshake is complete and the current message has been fully // processed then no more handshake messages are likely to arrive soon // so release the memory in the stream sequencer. - sequencer()->ReleaseBufferIfEmpty(); + sequencer->ReleaseBufferIfEmpty(); } } } @@ -113,33 +117,90 @@ void QuicCryptoStream::WriteCryptoData(EncryptionLevel level, QuicStringPiece data) { - // TODO(nharper): This approach to writing data, by setting the encryption - // level, calling WriteOrBufferData, and then restoring the encryption level, - // is fragile and assumes that the data gets received by the peer when - // WriteOrBufferData is called. There is no guarantee that data will get - // retransmitted at the correct level. This needs to be redone with the - // cleanup for OnDataAvailable by managing the streams/crypto frames for - // encryption levels separately. + if (session()->connection()->transport_version() < QUIC_VERSION_47) { + // The QUIC crypto handshake takes care of setting the appropriate + // encryption level before writing data. Since that is the only handshake + // supported in versions less than 47, |level| can be ignored here. + WriteOrBufferData(data, /* fin */ false, /* ack_listener */ nullptr); + return; + } + if (data.empty()) { + QUIC_BUG << "Empty crypto data being written"; + return; + } + // Append |data| to the send buffer for this encryption level. + struct iovec iov(QuicUtils::MakeIovec(data)); + QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; + QuicStreamOffset offset = send_buffer->stream_offset(); + send_buffer->SaveStreamData(&iov, /*iov_count=*/1, /*iov_offset=*/0, + data.length()); + if (kMaxStreamLength - offset < data.length()) { + QUIC_BUG << "Writing too much crypto handshake data"; + // TODO(nharper): Switch this to an IETF QUIC error code, possibly + // INTERNAL_ERROR? + CloseConnectionWithDetails(QUIC_STREAM_LENGTH_OVERFLOW, + "Writing too much crypto handshake data"); + } + + // Set long header type based on the encryption level. + if (level != ENCRYPTION_FORWARD_SECURE) { + QuicStreamOffset fake_offset = level == ENCRYPTION_NONE ? 0 : 1; + // Implementations of GetLongHeaderType either don't care at all about the + // offset, or only care whether or not it's 0. However, they do care that it + // is an absolute offset from the start of unencrypted crypto data, not the + // offset at a particular encryption level. + QuicLongHeaderType type = GetLongHeaderType(fake_offset); + session()->connection()->SetLongHeaderType(type); + } EncryptionLevel current_level = session()->connection()->encryption_level(); session()->connection()->SetDefaultEncryptionLevel(level); - WriteOrBufferData(data, /* fin */ false, /* ack_listener */ nullptr); - if (current_level == ENCRYPTION_FORWARD_SECURE && level != current_level) { - session()->connection()->SetDefaultEncryptionLevel(current_level); - } + size_t bytes_consumed = + session()->connection()->SendCryptoData(level, data.length(), offset); + session()->connection()->SetDefaultEncryptionLevel(current_level); + + send_buffer->OnStreamDataConsumed(bytes_consumed); } void QuicCryptoStream::OnSuccessfulVersionNegotiation( const ParsedQuicVersion& version) {} +bool QuicCryptoStream::OnCryptoFrameAcked(const QuicCryptoFrame& frame, + QuicTime::Delta ack_delay_time) { + QuicByteCount newly_acked_length = 0; + if (!substreams_[frame.level].send_buffer.OnStreamDataAcked( + frame.offset, frame.data_length, &newly_acked_length)) { + CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, + "Trying to ack unsent crypto data."); + return false; + } + return newly_acked_length > 0; +} + void QuicCryptoStream::NeuterUnencryptedStreamData() { - for (const auto& interval : bytes_consumed_[ENCRYPTION_NONE]) { + if (session()->connection()->transport_version() < QUIC_VERSION_47) { + for (const auto& interval : bytes_consumed_[ENCRYPTION_NONE]) { + QuicByteCount newly_acked_length = 0; + send_buffer().OnStreamDataAcked( + interval.min(), interval.max() - interval.min(), &newly_acked_length); + } + return; + } + QuicStreamSendBuffer* send_buffer = &substreams_[ENCRYPTION_NONE].send_buffer; + // TODO(nharper): Consider adding a Clear() method to QuicStreamSendBuffer to + // replace the following code. + QuicIntervalSet<QuicStreamOffset> to_ack = send_buffer->bytes_acked(); + to_ack.Complement(0, send_buffer->stream_offset()); + for (const auto& interval : to_ack) { QuicByteCount newly_acked_length = 0; - send_buffer().OnStreamDataAcked( + send_buffer->OnStreamDataAcked( interval.min(), interval.max() - interval.min(), &newly_acked_length); } } void QuicCryptoStream::OnStreamDataConsumed(size_t bytes_consumed) { + if (session()->connection()->transport_version() >= QUIC_VERSION_47) { + QUIC_BUG << "Stream data consumed when CRYPTO frames should be in use"; + } if (bytes_consumed > 0) { bytes_consumed_[session()->connection()->encryption_level()].Add( stream_bytes_written(), stream_bytes_written() + bytes_consumed); @@ -147,6 +208,38 @@ QuicStream::OnStreamDataConsumed(bytes_consumed); } +bool QuicCryptoStream::HasPendingCryptoRetransmission() { + if (session()->connection()->transport_version() < QUIC_VERSION_47) { + return false; + } + for (EncryptionLevel level : + {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + if (substreams_[level].send_buffer.HasPendingRetransmission()) { + return true; + } + } + return false; +} + +void QuicCryptoStream::WritePendingCryptoRetransmission() { + QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47) + << "Versions less than 47 don't write CRYPTO frames"; + EncryptionLevel current_encryption_level = + session()->connection()->encryption_level(); + for (EncryptionLevel level : + {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + QuicStreamSendBuffer* send_buffer = &substreams_[level].send_buffer; + session()->connection()->SetDefaultEncryptionLevel(level); + while (send_buffer->HasPendingRetransmission()) { + auto pending = send_buffer->NextPendingRetransmission(); + size_t bytes_consumed = session()->connection()->SendCryptoData( + level, pending.length, pending.offset); + send_buffer->OnStreamDataRetransmitted(pending.offset, bytes_consumed); + } + } + session()->connection()->SetDefaultEncryptionLevel(current_encryption_level); +} + void QuicCryptoStream::WritePendingRetransmission() { while (HasPendingRetransmission()) { StreamPendingRetransmission pending = @@ -236,5 +329,97 @@ return true; } +uint64_t QuicCryptoStream::crypto_bytes_read() const { + if (session()->connection()->transport_version() < QUIC_VERSION_47) { + return stream_bytes_read(); + } + return substreams_[ENCRYPTION_NONE].sequencer.NumBytesConsumed() + + substreams_[ENCRYPTION_ZERO_RTT].sequencer.NumBytesConsumed() + + substreams_[ENCRYPTION_FORWARD_SECURE].sequencer.NumBytesConsumed(); +} + +uint64_t QuicCryptoStream::BytesReadOnLevel(EncryptionLevel level) const { + return substreams_[level].sequencer.NumBytesConsumed(); +} + +bool QuicCryptoStream::WriteCryptoFrame(EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer) { + QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47) + << "Versions less than 47 don't write CRYPTO frames (2)"; + return substreams_[level].send_buffer.WriteStreamData(offset, data_length, + writer); +} + +void QuicCryptoStream::OnCryptoFrameLost(QuicCryptoFrame* crypto_frame) { + QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47) + << "Versions less than 47 don't lose CRYPTO frames"; + substreams_[crypto_frame->level].send_buffer.OnStreamDataLost( + crypto_frame->offset, crypto_frame->data_length); +} + +void QuicCryptoStream::RetransmitData(QuicCryptoFrame* crypto_frame) { + QUIC_BUG_IF(session()->connection()->transport_version() < QUIC_VERSION_47) + << "Versions less than 47 don't retransmit CRYPTO frames"; + QuicIntervalSet<QuicStreamOffset> retransmission( + crypto_frame->offset, crypto_frame->offset + crypto_frame->data_length); + QuicStreamSendBuffer* send_buffer = + &substreams_[crypto_frame->level].send_buffer; + retransmission.Difference(send_buffer->bytes_acked()); + if (retransmission.Empty()) { + return; + } + EncryptionLevel current_encryption_level = + session()->connection()->encryption_level(); + for (const auto& interval : retransmission) { + size_t retransmission_offset = interval.min(); + size_t retransmission_length = interval.max() - interval.min(); + session()->connection()->SetDefaultEncryptionLevel(crypto_frame->level); + size_t bytes_consumed = session()->connection()->SendCryptoData( + crypto_frame->level, retransmission_length, retransmission_offset); + send_buffer->OnStreamDataRetransmitted(retransmission_offset, + bytes_consumed); + } + session()->connection()->SetDefaultEncryptionLevel(current_encryption_level); +} + +bool QuicCryptoStream::IsFrameOutstanding(EncryptionLevel level, + size_t offset, + size_t length) const { + if (session()->connection()->transport_version() < QUIC_VERSION_47) { + // This only happens if a client was originally configured for a version + // greater than 45, but received a version negotiation packet and is + // attempting to retransmit for a version less than 47. Outside of tests, + // this is a misconfiguration of the client, and this connection will be + // doomed. Return false here to avoid trying to retransmit CRYPTO frames on + // the wrong transport version. + return false; + } + return substreams_[level].send_buffer.IsStreamDataOutstanding(offset, length); +} + +bool QuicCryptoStream::IsWaitingForAcks() const { + if (session()->connection()->transport_version() < QUIC_VERSION_47) { + return QuicStream::IsWaitingForAcks(); + } + for (EncryptionLevel level : + {ENCRYPTION_NONE, ENCRYPTION_ZERO_RTT, ENCRYPTION_FORWARD_SECURE}) { + if (substreams_[level].send_buffer.stream_bytes_outstanding()) { + return true; + } + } + return false; +} + +QuicCryptoStream::CryptoSubstream::CryptoSubstream( + QuicCryptoStream* crypto_stream, + EncryptionLevel) + : sequencer(crypto_stream), + send_buffer(crypto_stream->session() + ->connection() + ->helper() + ->GetStreamSendBufferAllocator()) {} + #undef ENDPOINT // undef for jumbo builds } // namespace quic
diff --git a/quic/core/quic_crypto_stream.h b/quic/core/quic_crypto_stream.h index 0593f44..cfd81c7 100644 --- a/quic/core/quic_crypto_stream.h +++ b/quic/core/quic_crypto_stream.h
@@ -45,8 +45,16 @@ QuicTransportVersion version); // QuicStream implementation + void OnStreamFrame(const QuicStreamFrame& frame) override; void OnDataAvailable() override; + // Called when a CRYPTO frame is received. + void OnCryptoFrame(const QuicCryptoFrame& frame); + + // Called when a CRYPTO frame is ACKed. + bool OnCryptoFrameAcked(const QuicCryptoFrame& frame, + QuicTime::Delta ack_delay_time); + // Performs key extraction to derive a new secret of |result_len| bytes // dependent on |label|, |context|, and the stream's negotiated subkey secret. // Returns false if the handshake has not been confirmed or the parameters are @@ -86,6 +94,13 @@ // Override to record the encryption level of consumed data. void OnStreamDataConsumed(size_t bytes_consumed) override; + // Returns whether there are any bytes pending retransmission in CRYPTO + // frames. + virtual bool HasPendingCryptoRetransmission(); + + // Writes any pending CRYPTO frame retransmissions. + void WritePendingCryptoRetransmission(); + // Override to retransmit lost crypto data with the appropriate encryption // level. void WritePendingRetransmission() override; @@ -95,11 +110,66 @@ QuicByteCount data_length, bool fin) override; + // Returns the number of bytes of handshake data that have been received from + // the peer in either CRYPTO or STREAM frames. + uint64_t crypto_bytes_read() const; + + // Returns the number of bytes of handshake data that have been received from + // the peer in CRYPTO frames at a particular encryption level. + QuicByteCount BytesReadOnLevel(EncryptionLevel level) const; + + // Writes |data_length| of data of a crypto frame to |writer|. The data + // written is from the send buffer for encryption level |level| and starts at + // |offset|. + bool WriteCryptoFrame(EncryptionLevel level, + QuicStreamOffset offset, + QuicByteCount data_length, + QuicDataWriter* writer); + + // Called when data from a CRYPTO frame is considered lost. The lost data is + // identified by the encryption level, offset, and length in |crypto_frame|. + void OnCryptoFrameLost(QuicCryptoFrame* crypto_frame); + + // Called to retransmit any outstanding data in the range indicated by the + // encryption level, offset, and length in |crypto_frame|. + void RetransmitData(QuicCryptoFrame* crypto_frame); + + // Returns true if any portion of the data at encryption level |level| + // starting at |offset| for |length| bytes is outstanding. + bool IsFrameOutstanding(EncryptionLevel level, + size_t offset, + size_t length) const; + + // Returns true if the crypto handshake is still waiting for acks of sent + // data, and false if all data has been acked. + bool IsWaitingForAcks() const; + private: + // Data sent and received in CRYPTO frames is sent at multiple encryption + // levels. Some of the state for the single logical crypto stream is split + // across encryption levels, and a CryptoSubstream is used to manage that + // state for a particular encryption level. + struct CryptoSubstream { + CryptoSubstream(QuicCryptoStream* crypto_stream, EncryptionLevel); + + QuicStreamSequencer sequencer; + QuicStreamSendBuffer send_buffer; + }; + + // Helper method for OnDataAvailable. Calls CryptoMessageParser::ProcessInput + // with the data available in |sequencer| and |level|, and marks the data + // passed to ProcessInput as consumed. + void OnDataAvailableInSequencer(QuicStreamSequencer* sequencer, + EncryptionLevel level); + // Consumed data according to encryption levels. // TODO(fayang): This is not needed once switching from QUIC crypto to // TLS 1.3, which never encrypts crypto data. QuicIntervalSet<QuicStreamOffset> bytes_consumed_[NUM_ENCRYPTION_LEVELS]; + + // Keeps state for data sent/received in CRYPTO frames at each encryption + // level. + CryptoSubstream substreams_[NUM_ENCRYPTION_LEVELS]; }; } // namespace quic
diff --git a/quic/core/quic_crypto_stream_test.cc b/quic/core/quic_crypto_stream_test.cc index 6ce0b41..eb1a672 100644 --- a/quic/core/quic_crypto_stream_test.cc +++ b/quic/core/quic_crypto_stream_test.cc
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" +#include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" #include "net/third_party/quiche/src/quic/core/quic_utils.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.h" @@ -104,10 +105,15 @@ } TEST_F(QuicCryptoStreamTest, ProcessRawData) { - stream_->OnStreamFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), - /*fin=*/false, - /*offset=*/0, message_data_->AsStringPiece())); + if (connection_->transport_version() < QUIC_VERSION_47) { + stream_->OnStreamFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_->transport_version()), + /*fin=*/false, + /*offset=*/0, message_data_->AsStringPiece())); + } else { + stream_->OnCryptoFrame(QuicCryptoFrame(ENCRYPTION_NONE, /*offset*/ 0, + message_data_->AsStringPiece())); + } ASSERT_EQ(1u, stream_->messages()->size()); const CryptoHandshakeMessage& message = (*stream_->messages())[0]; EXPECT_EQ(kSHLO, message.tag()); @@ -126,9 +132,13 @@ EXPECT_CALL(*connection_, CloseConnection(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, testing::_, testing::_)); - stream_->OnStreamFrame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId(connection_->transport_version()), - /*fin=*/false, /*offset=*/0, bad)); + if (connection_->transport_version() < QUIC_VERSION_47) { + stream_->OnStreamFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(connection_->transport_version()), + /*fin=*/false, /*offset=*/0, bad)); + } else { + stream_->OnCryptoFrame(QuicCryptoFrame(ENCRYPTION_NONE, /*offset*/ 0, bad)); + } } TEST_F(QuicCryptoStreamTest, NoConnectionLevelFlowControl) { @@ -137,6 +147,9 @@ } TEST_F(QuicCryptoStreamTest, RetransmitCryptoData) { + if (connection_->transport_version() >= QUIC_VERSION_47) { + return; + } InSequence s; // Send [0, 1350) in ENCRYPTION_NONE. EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); @@ -148,9 +161,9 @@ 1350, 0, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); stream_->WriteOrBufferData(data, false, nullptr); - // Send [1350, 2700) in ENCRYPTION_INITIAL. - connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); + // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level()); EXPECT_CALL( session_, WritevData(_, @@ -192,7 +205,62 @@ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); } +TEST_F(QuicCryptoStreamTest, RetransmitCryptoDataInCryptoFrames) { + if (connection_->transport_version() < QUIC_VERSION_47) { + return; + } + EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0); + InSequence s; + // Send [0, 1350) in ENCRYPTION_NONE. + EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); + QuicString data(1350, 'a'); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WriteCryptoData(ENCRYPTION_NONE, data); + // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + std::unique_ptr<NullEncrypter> encrypter = + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT); + connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter)); + 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_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); + + // Lost [0, 1000). + QuicCryptoFrame lost_frame(ENCRYPTION_NONE, 0, 1000); + stream_->OnCryptoFrameLost(&lost_frame); + EXPECT_TRUE(stream_->HasPendingCryptoRetransmission()); + // Lost [1200, 2000). + lost_frame = QuicCryptoFrame(ENCRYPTION_NONE, 1200, 150); + stream_->OnCryptoFrameLost(&lost_frame); + lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650); + stream_->OnCryptoFrameLost(&lost_frame); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1000, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + // Verify [1200, 2000) are sent in [1200, 1350) and [1350, 2000) because of + // they are in different encryption levels. + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 150, 1200)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WritePendingCryptoRetransmission(); + EXPECT_FALSE(stream_->HasPendingCryptoRetransmission()); + // Verify connection's encryption level has restored. + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); +} + TEST_F(QuicCryptoStreamTest, NeuterUnencryptedStreamData) { + if (connection_->transport_version() >= QUIC_VERSION_47) { + return; + } // Send [0, 1350) in ENCRYPTION_NONE. EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); QuicString data(1350, 'a'); @@ -203,9 +271,9 @@ 1350, 0, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); stream_->WriteOrBufferData(data, false, nullptr); - // Send [1350, 2700) in ENCRYPTION_INITIAL. - connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); + // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level()); EXPECT_CALL( session_, WritevData(_, @@ -231,7 +299,53 @@ EXPECT_TRUE(stream_->HasPendingRetransmission()); } +TEST_F(QuicCryptoStreamTest, NeuterUnencryptedCryptoData) { + if (connection_->transport_version() < QUIC_VERSION_47) { + return; + } + // Send [0, 1350) in ENCRYPTION_NONE. + EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); + QuicString data(1350, 'a'); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WriteCryptoData(ENCRYPTION_NONE, data); + // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + std::unique_ptr<NullEncrypter> encrypter = + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT); + connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter)); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level()); + EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 1350, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WriteCryptoData(ENCRYPTION_ZERO_RTT, data); + + // Lost [0, 1350). + QuicCryptoFrame lost_frame(ENCRYPTION_NONE, 0, 1350); + stream_->OnCryptoFrameLost(&lost_frame); + EXPECT_TRUE(stream_->HasPendingCryptoRetransmission()); + // Neuters [0, 1350). + stream_->NeuterUnencryptedStreamData(); + EXPECT_FALSE(stream_->HasPendingCryptoRetransmission()); + // Lost [0, 1350) again. + stream_->OnCryptoFrameLost(&lost_frame); + EXPECT_FALSE(stream_->HasPendingCryptoRetransmission()); + + // Lost [1350, 2000), which starts at offset 0 at the ENCRYPTION_ZERO_RTT + // level. + lost_frame = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 650); + stream_->OnCryptoFrameLost(&lost_frame); + EXPECT_TRUE(stream_->HasPendingCryptoRetransmission()); + stream_->NeuterUnencryptedStreamData(); + EXPECT_TRUE(stream_->HasPendingCryptoRetransmission()); +} + TEST_F(QuicCryptoStreamTest, RetransmitStreamData) { + if (connection_->transport_version() >= QUIC_VERSION_47) { + return; + } InSequence s; // Send [0, 1350) in ENCRYPTION_NONE. EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); @@ -243,9 +357,9 @@ 1350, 0, _)) .WillOnce(Invoke(MockQuicSession::ConsumeData)); stream_->WriteOrBufferData(data, false, nullptr); - // Send [1350, 2700) in ENCRYPTION_INITIAL. - connection_->SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - EXPECT_EQ(ENCRYPTION_INITIAL, connection_->encryption_level()); + // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + EXPECT_EQ(ENCRYPTION_ZERO_RTT, connection_->encryption_level()); EXPECT_CALL( session_, WritevData(_, @@ -257,7 +371,10 @@ EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); // Ack [2000, 2500). - stream_->OnStreamFrameAcked(2000, 500, false, QuicTime::Delta::Zero()); + QuicByteCount newly_acked_length = 0; + stream_->OnStreamFrameAcked(2000, 500, false, QuicTime::Delta::Zero(), + &newly_acked_length); + EXPECT_EQ(500u, newly_acked_length); // Force crypto stream to send [1350, 2700) and only [1350, 1500) is consumed. EXPECT_CALL( @@ -298,8 +415,69 @@ EXPECT_TRUE(stream_->RetransmitStreamData(0, 0, false)); } +TEST_F(QuicCryptoStreamTest, RetransmitStreamDataWithCryptoFrames) { + if (connection_->transport_version() < QUIC_VERSION_47) { + return; + } + InSequence s; + // Send [0, 1350) in ENCRYPTION_NONE. + EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); + QuicString data(1350, 'a'); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WriteCryptoData(ENCRYPTION_NONE, data); + // Send [1350, 2700) in ENCRYPTION_ZERO_RTT. + connection_->SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); + std::unique_ptr<NullEncrypter> encrypter = + QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT); + connection_->SetEncrypter(ENCRYPTION_ZERO_RTT, std::move(encrypter)); + 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_->SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE); + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); + + // Ack [2000, 2500). + QuicCryptoFrame acked_frame(ENCRYPTION_ZERO_RTT, 650, 500); + EXPECT_TRUE( + stream_->OnCryptoFrameAcked(acked_frame, QuicTime::Delta::Zero())); + + // Retransmit only [1350, 1500). + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 150, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + QuicCryptoFrame frame_to_retransmit(ENCRYPTION_ZERO_RTT, 0, 150); + stream_->RetransmitData(&frame_to_retransmit); + + // Verify connection's encryption level has restored. + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); + + // Retransmit [1350, 2700) again and all data is sent. + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 650, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_ZERO_RTT, 200, 1150)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + frame_to_retransmit = QuicCryptoFrame(ENCRYPTION_ZERO_RTT, 0, 1350); + stream_->RetransmitData(&frame_to_retransmit); + // Verify connection's encryption level has restored. + EXPECT_EQ(ENCRYPTION_FORWARD_SECURE, connection_->encryption_level()); + + EXPECT_CALL(*connection_, SendCryptoData(_, _, _)).Times(0); + // Force to send an empty frame. + QuicCryptoFrame empty_frame(ENCRYPTION_FORWARD_SECURE, 0, 0); + stream_->RetransmitData(&empty_frame); +} + // Regression test for b/115926584. TEST_F(QuicCryptoStreamTest, HasUnackedCryptoData) { + if (connection_->transport_version() >= QUIC_VERSION_47) { + return; + } QuicString data(1350, 'a'); EXPECT_CALL( session_, @@ -325,6 +503,21 @@ EXPECT_TRUE(session_.HasUnackedCryptoData()); } +TEST_F(QuicCryptoStreamTest, HasUnackedCryptoDataWithCryptoFrames) { + if (connection_->transport_version() < QUIC_VERSION_47) { + return; + } + // Send [0, 1350) in ENCRYPTION_NONE. + EXPECT_EQ(ENCRYPTION_NONE, connection_->encryption_level()); + QuicString data(1350, 'a'); + EXPECT_CALL(*connection_, SendCryptoData(ENCRYPTION_NONE, 1350, 0)) + .WillOnce(Invoke(connection_, + &MockQuicConnection::QuicConnection_SendCryptoData)); + stream_->WriteCryptoData(ENCRYPTION_NONE, data); + EXPECT_TRUE(stream_->IsWaitingForAcks()); + EXPECT_TRUE(session_.HasUnackedCryptoData()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_data_reader.cc b/quic/core/quic_data_reader.cc index 13a4c5a..191c755 100644 --- a/quic/core/quic_data_reader.cc +++ b/quic/core/quic_data_reader.cc
@@ -12,6 +12,9 @@ namespace quic { +QuicDataReader::QuicDataReader(const char* data, const size_t len) + : QuicDataReader(data, len, NETWORK_BYTE_ORDER) {} + QuicDataReader::QuicDataReader(const char* data, const size_t len, Endianness endianness) @@ -129,17 +132,7 @@ } bool QuicDataReader::ReadConnectionId(QuicConnectionId* connection_id, - uint8_t length, - Perspective perspective) { - if (!QuicConnectionIdSupportsVariableLength(perspective)) { - uint64_t connection_id64 = 0; - if (!ReadBytes(&connection_id64, sizeof(connection_id64))) { - return false; - } - *connection_id = - QuicConnectionIdFromUInt64(QuicEndian::NetToHost64(connection_id64)); - return true; - } + uint8_t length) { DCHECK_LE(length, kQuicMaxConnectionIdLength); const bool ok = ReadBytes(connection_id->mutable_data(), length); @@ -159,7 +152,7 @@ return payload; } -QuicStringPiece QuicDataReader::PeekRemainingPayload() { +QuicStringPiece QuicDataReader::PeekRemainingPayload() const { return QuicStringPiece(data_ + pos_, len_ - pos_); } @@ -183,20 +176,29 @@ return len_ == pos_; } -int QuicDataReader::PeekVarInt62Length() { +QuicVariableLengthIntegerLength QuicDataReader::PeekVarInt62Length() { DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER); const unsigned char* next = reinterpret_cast<const unsigned char*>(data_ + pos_); if (BytesRemaining() == 0) { - return 0; + return VARIABLE_LENGTH_INTEGER_LENGTH_0; } - return 1 << ((*next & 0b11000000) >> 6); + return static_cast<QuicVariableLengthIntegerLength>( + 1 << ((*next & 0b11000000) >> 6)); } size_t QuicDataReader::BytesRemaining() const { return len_ - pos_; } +bool QuicDataReader::TruncateRemaining(size_t truncation_length) { + if (truncation_length > BytesRemaining()) { + return false; + } + len_ = pos_ + truncation_length; + return true; +} + bool QuicDataReader::CanRead(size_t bytes) const { return bytes <= (len_ - pos_); }
diff --git a/quic/core/quic_data_reader.h b/quic/core/quic_data_reader.h index ca9f323..fff0ffd 100644 --- a/quic/core/quic_data_reader.h +++ b/quic/core/quic_data_reader.h
@@ -32,6 +32,10 @@ // called after failure, as they will also fail immediately. class QUIC_EXPORT_PRIVATE QuicDataReader { public: + // Constructs a reader using NETWORK_BYTE_ORDER endianness. + // Caller must provide an underlying buffer to work on. + QuicDataReader(const char* data, const size_t len); + // Constructs a reader using the specified endianness. // Caller must provide an underlying buffer to work on. QuicDataReader(const char* data, const size_t len, Endianness endianness); QuicDataReader(const QuicDataReader&) = delete; @@ -75,11 +79,7 @@ // Reads connection ID into the given output parameter. // Forwards the internal iterator on success. // Returns true on success, false otherwise. - // TODO(dschinazi) b/120240679 - remove perspective once these flags are - // deprecated: quic_variable_length_connection_ids_(client|server). - bool ReadConnectionId(QuicConnectionId* connection_id, - uint8_t length, - Perspective perspective); + bool ReadConnectionId(QuicConnectionId* connection_id, uint8_t length); // Reads tag represented as 32-bit unsigned integer into given output // parameter. Tags are in big endian on the wire (e.g., CHLO is @@ -101,7 +101,7 @@ // This should be kept in mind when handling memory management! // // DOES NOT forward the internal iterator. - QuicStringPiece PeekRemainingPayload(); + QuicStringPiece PeekRemainingPayload() const; // Reads a given number of bytes into the given buffer. The buffer // must be of adequate size. @@ -115,11 +115,17 @@ // Returns the length in bytes of a variable length integer based on the next // two bits available. Returns 1, 2, 4, or 8 on success, and 0 on failure. - int PeekVarInt62Length(); + QuicVariableLengthIntegerLength PeekVarInt62Length(); // Returns the number of bytes remaining to be read. size_t BytesRemaining() const; + // Truncates the reader down by reducing its internal length. + // If called immediately after calling this, BytesRemaining will + // return |truncation_length|. If truncation_length is less than the + // current value of BytesRemaining, this does nothing and returns false. + bool TruncateRemaining(size_t truncation_length); + // Returns the next byte that to be read. Must not be called when there are no // bytes to be read. // @@ -158,7 +164,7 @@ const char* data_; // The length of the data buffer that we're reading from. - const size_t len_; + size_t len_; // The location of the next read from our data buffer. size_t pos_;
diff --git a/quic/core/quic_data_writer.cc b/quic/core/quic_data_writer.cc index 865b262..c7bedb5 100644 --- a/quic/core/quic_data_writer.cc +++ b/quic/core/quic_data_writer.cc
@@ -15,6 +15,9 @@ namespace quic { +QuicDataWriter::QuicDataWriter(size_t size, char* buffer) + : QuicDataWriter(size, buffer, NETWORK_BYTE_ORDER) {} + QuicDataWriter::QuicDataWriter(size_t size, char* buffer, Endianness endianness) : buffer_(buffer), capacity_(size), length_(0), endianness_(endianness) {} @@ -171,14 +174,7 @@ return WriteRepeatedByte(0x00, count); } -bool QuicDataWriter::WriteConnectionId(QuicConnectionId connection_id, - Perspective perspective) { - if (!QuicConnectionIdSupportsVariableLength(perspective)) { - uint64_t connection_id64 = - QuicEndian::HostToNet64(QuicConnectionIdToUInt64(connection_id)); - - return WriteBytes(&connection_id64, sizeof(connection_id64)); - } +bool QuicDataWriter::WriteConnectionId(QuicConnectionId connection_id) { return WriteBytes(connection_id.data(), connection_id.length()); } @@ -283,23 +279,58 @@ return false; } +bool QuicDataWriter::WriteVarInt62( + uint64_t value, + QuicVariableLengthIntegerLength write_length) { + DCHECK_EQ(endianness_, NETWORK_BYTE_ORDER); + + size_t remaining = capacity_ - length_; + if (remaining < write_length) { + return false; + } + + const QuicVariableLengthIntegerLength min_length = GetVarInt62Len(value); + if (write_length < min_length) { + QUIC_BUG << "Cannot write value " << value << " with write_length " + << write_length; + return false; + } + if (write_length == min_length) { + return WriteVarInt62(value); + } + + if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_2) { + return WriteUInt8(0b01000000) && WriteUInt8(value); + } + if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_4) { + return WriteUInt8(0b10000000) && WriteUInt8(0) && WriteUInt16(value); + } + if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_8) { + return WriteUInt8(0b11000000) && WriteUInt8(0) && WriteUInt16(0) && + WriteUInt32(value); + } + + QUIC_BUG << "Invalid write_length " << static_cast<int>(write_length); + return false; +} + // static -int QuicDataWriter::GetVarInt62Len(uint64_t value) { +QuicVariableLengthIntegerLength QuicDataWriter::GetVarInt62Len(uint64_t value) { if ((value & kVarInt62ErrorMask) != 0) { QUIC_BUG << "Attempted to encode a value, " << value << ", that is too big for VarInt62"; - return 0; + return VARIABLE_LENGTH_INTEGER_LENGTH_0; } if ((value & kVarInt62Mask8Bytes) != 0) { - return 8; + return VARIABLE_LENGTH_INTEGER_LENGTH_8; } if ((value & kVarInt62Mask4Bytes) != 0) { - return 4; + return VARIABLE_LENGTH_INTEGER_LENGTH_4; } if ((value & kVarInt62Mask2Bytes) != 0) { - return 2; + return VARIABLE_LENGTH_INTEGER_LENGTH_2; } - return 1; + return VARIABLE_LENGTH_INTEGER_LENGTH_1; } bool QuicDataWriter::WriteStringPieceVarInt62(
diff --git a/quic/core/quic_data_writer.h b/quic/core/quic_data_writer.h index 9423553..e107fcb 100644 --- a/quic/core/quic_data_writer.h +++ b/quic/core/quic_data_writer.h
@@ -38,7 +38,11 @@ // of the QuicDataWriter. class QUIC_EXPORT_PRIVATE QuicDataWriter { public: - // Creates a QuicDataWriter where |buffer| is not owned. + // Creates a QuicDataWriter where |buffer| is not owned + // using NETWORK_BYTE_ORDER endianness. + QuicDataWriter(size_t size, char* buffer); + // Creates a QuicDataWriter where |buffer| is not owned + // using the specified endianness. QuicDataWriter(size_t size, char* buffer, Endianness endianness); QuicDataWriter(const QuicDataWriter&) = delete; QuicDataWriter& operator=(const QuicDataWriter&) = delete; @@ -68,6 +72,13 @@ // buffer. bool WriteVarInt62(uint64_t value); + // Same as WriteVarInt62(uint64_t), but forces an encoding size to write to. + // This is not as optimized as WriteVarInt62(uint64_t). + // Returns false if the value does not fit in the specified write_length or if + // there is no room in the buffer. + bool WriteVarInt62(uint64_t value, + QuicVariableLengthIntegerLength write_length); + // Writes a string piece as a consecutive length/content pair. The // length is VarInt62 encoded. bool WriteStringPieceVarInt62(const QuicStringPiece& string_piece); @@ -76,7 +87,7 @@ // the given value using IETF VarInt62 encoding. Returns the number // of bytes required to encode the given integer or 0 if the value // is too large to encode. - static int GetVarInt62Len(uint64_t value); + static QuicVariableLengthIntegerLength GetVarInt62Len(uint64_t value); // Writes least significant |num_bytes| of a 64-bit unsigned integer in the // correct byte order. @@ -96,10 +107,7 @@ bool WritePaddingBytes(size_t count); // Write connection ID to the payload. - // TODO(dschinazi) b/120240679 - remove perspective once these flags are - // deprecated: quic_variable_length_connection_ids_(client|server). - bool WriteConnectionId(QuicConnectionId connection_id, - Perspective perspective); + bool WriteConnectionId(QuicConnectionId connection_id); // Write tag as a 32-bit unsigned integer to the payload. As tags are already // converted to big endian (e.g., CHLO is 'C','H','L','O') in memory by TAG or
diff --git a/quic/core/quic_data_writer_test.cc b/quic/core/quic_data_writer_test.cc index 9fe05e6..978143e 100644 --- a/quic/core/quic_data_writer_test.cc +++ b/quic/core/quic_data_writer_test.cc
@@ -37,9 +37,8 @@ class QuicDataWriterTest : public QuicTestWithParam<TestParams> {}; -INSTANTIATE_TEST_CASE_P(QuicDataWriterTests, - QuicDataWriterTest, - ::testing::ValuesIn(GetTestParams())); +INSTANTIATE_TEST_SUITE_P(QuicDataWriterTests, QuicDataWriterTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicDataWriterTest, SanityCheckUFloat16Consts) { // Check the arithmetic on the constants - otherwise the values below make @@ -256,99 +255,16 @@ ASSERT_LE(connection_id.length(), kQuicMaxConnectionIdLength); char buffer[kQuicMaxConnectionIdLength]; QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness); - EXPECT_TRUE(writer.WriteConnectionId(connection_id, Perspective::IS_CLIENT)); + EXPECT_TRUE(writer.WriteConnectionId(connection_id)); test::CompareCharArraysWithHexError("connection_id", buffer, connection_id.length(), big_endian, connection_id.length()); QuicConnectionId read_connection_id; QuicDataReader reader(buffer, connection_id.length(), GetParam().endianness); - EXPECT_TRUE(reader.ReadConnectionId( - &read_connection_id, QUIC_ARRAYSIZE(big_endian), Perspective::IS_CLIENT)); + EXPECT_TRUE( + reader.ReadConnectionId(&read_connection_id, QUIC_ARRAYSIZE(big_endian))); EXPECT_EQ(connection_id, read_connection_id); - - // TODO(dschinazi) b/120240679 - remove this second read once these flags are - // deprecated: quic_variable_length_connection_ids_(client|server). - QuicConnectionId read_connection_id2; - QuicDataReader reader2(buffer, connection_id.length(), GetParam().endianness); - EXPECT_TRUE(reader2.ReadConnectionId(&read_connection_id2, - QUIC_ARRAYSIZE(big_endian), - Perspective::IS_SERVER)); - EXPECT_EQ(connection_id, read_connection_id2); -} - -// TODO(dschinazi) b/120240679 - remove this test once these flags are -// deprecated: quic_variable_length_connection_ids_(client|server). -TEST_P(QuicDataWriterTest, WriteConnectionIdServerAllowingVariableLength) { - if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) { - // This test is pointless if the flag is off. - return; - } - SetQuicRestartFlag(quic_variable_length_connection_ids_client, false); - SetQuicRestartFlag(quic_variable_length_connection_ids_server, true); - QuicConnectionId connection_id = - TestConnectionId(UINT64_C(0x0011223344556677)); - char big_endian[] = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - }; - EXPECT_EQ(connection_id.length(), QUIC_ARRAYSIZE(big_endian)); - ASSERT_LE(connection_id.length(), kQuicMaxConnectionIdLength); - char buffer[kQuicMaxConnectionIdLength]; - QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness); - EXPECT_TRUE(writer.WriteConnectionId(connection_id, Perspective::IS_SERVER)); - test::CompareCharArraysWithHexError("connection_id", buffer, - connection_id.length(), big_endian, - connection_id.length()); - - QuicConnectionId read_connection_id; - QuicDataReader reader(buffer, connection_id.length(), GetParam().endianness); - EXPECT_TRUE(reader.ReadConnectionId( - &read_connection_id, QUIC_ARRAYSIZE(big_endian), Perspective::IS_CLIENT)); - EXPECT_EQ(connection_id, read_connection_id); - - QuicConnectionId read_connection_id2; - QuicDataReader reader2(buffer, connection_id.length(), GetParam().endianness); - EXPECT_TRUE(reader2.ReadConnectionId(&read_connection_id2, - QUIC_ARRAYSIZE(big_endian), - Perspective::IS_SERVER)); - EXPECT_EQ(connection_id, read_connection_id2); -} - -// TODO(dschinazi) b/120240679 - remove this test once these flags are -// deprecated: quic_variable_length_connection_ids_(client|server). -TEST_P(QuicDataWriterTest, WriteConnectionIdClientAllowingVariableLength) { - if (!GetQuicRestartFlag(quic_connection_ids_network_byte_order)) { - // This test is pointless if the flag is off. - return; - } - SetQuicRestartFlag(quic_variable_length_connection_ids_client, true); - SetQuicRestartFlag(quic_variable_length_connection_ids_server, false); - QuicConnectionId connection_id = - TestConnectionId(UINT64_C(0x0011223344556677)); - char big_endian[] = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - }; - EXPECT_EQ(connection_id.length(), QUIC_ARRAYSIZE(big_endian)); - ASSERT_LE(connection_id.length(), kQuicMaxConnectionIdLength); - char buffer[kQuicMaxConnectionIdLength]; - QuicDataWriter writer(connection_id.length(), buffer, GetParam().endianness); - EXPECT_TRUE(writer.WriteConnectionId(connection_id, Perspective::IS_SERVER)); - test::CompareCharArraysWithHexError("connection_id", buffer, - connection_id.length(), big_endian, - connection_id.length()); - - QuicConnectionId read_connection_id; - QuicDataReader reader(buffer, connection_id.length(), GetParam().endianness); - EXPECT_TRUE(reader.ReadConnectionId( - &read_connection_id, QUIC_ARRAYSIZE(big_endian), Perspective::IS_CLIENT)); - EXPECT_EQ(connection_id, read_connection_id); - - QuicConnectionId read_connection_id2; - QuicDataReader reader2(buffer, connection_id.length(), GetParam().endianness); - EXPECT_TRUE(reader2.ReadConnectionId(&read_connection_id2, - QUIC_ARRAYSIZE(big_endian), - Perspective::IS_SERVER)); - EXPECT_EQ(connection_id, read_connection_id2); } TEST_P(QuicDataWriterTest, WriteTag) { @@ -991,6 +907,76 @@ EXPECT_FALSE(reader.ReadVarInt62(&test_val)); } +// Test writing varints with a forced length. +TEST_P(QuicDataWriterTest, VarIntFixedLength) { + char buffer[90]; + memset(buffer, 0, sizeof(buffer)); + QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + Endianness::NETWORK_BYTE_ORDER); + + writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_1); + writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62(1, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_1); + writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62(63, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62(64, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62(16383, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62(16384, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62(16384, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62(1073741823, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62(1073741823, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62(1073741824, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + QuicDataReader reader(buffer, sizeof(buffer), Endianness::NETWORK_BYTE_ORDER); + + uint64_t test_val = 0; + for (int i = 0; i < 4; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 1); + } + for (int i = 0; i < 4; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 63); + } + + for (int i = 0; i < 3; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 64); + } + for (int i = 0; i < 3; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 16383); + } + + for (int i = 0; i < 2; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 16384); + } + for (int i = 0; i < 2; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 1073741823); + } + + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 1073741824); + + // We are at the end of the buffer so this should fail. + EXPECT_FALSE(reader.ReadVarInt62(&test_val)); +} + // Test encoding/decoding stream-id values. void EncodeDecodeStreamId(uint64_t value_in, bool expected_decode_result) { char buffer[1 * kMultiVarCount];
diff --git a/quic/core/quic_default_packet_writer.cc b/quic/core/quic_default_packet_writer.cc index 2c162e0..3b16a74 100644 --- a/quic/core/quic_default_packet_writer.cc +++ b/quic/core/quic_default_packet_writer.cc
@@ -30,10 +30,6 @@ return result; } -bool QuicDefaultPacketWriter::IsWriteBlockedDataBuffered() const { - return false; -} - bool QuicDefaultPacketWriter::IsWriteBlocked() const { return write_blocked_; }
diff --git a/quic/core/quic_default_packet_writer.h b/quic/core/quic_default_packet_writer.h index 93917da..b5473eb 100644 --- a/quic/core/quic_default_packet_writer.h +++ b/quic/core/quic_default_packet_writer.h
@@ -30,7 +30,6 @@ const QuicIpAddress& self_address, const QuicSocketAddress& peer_address, PerPacketOptions* options) override; - bool IsWriteBlockedDataBuffered() const override; bool IsWriteBlocked() const override; void SetWritable() override; QuicByteCount GetMaxPacketSize(
diff --git a/quic/core/quic_dispatcher.cc b/quic/core/quic_dispatcher.cc index 0cb03aa..f17bdf2 100644 --- a/quic/core/quic_dispatcher.cc +++ b/quic/core/quic_dispatcher.cc
@@ -96,8 +96,7 @@ QuicStreamOffset offset, QuicByteCount data_length, QuicDataWriter* writer) override { - QUIC_BUG << "PacketCollector::WriteCryptoData is unimplemented."; - return false; + return send_buffer_.WriteStreamData(offset, data_length, writer); } std::vector<std::unique_ptr<QuicEncryptedPacket>>* packets() { @@ -143,7 +142,12 @@ frame->error_details = error_details; // TODO(fayang): Use the right long header type for conneciton close sent by // dispatcher. - creator_.SetLongHeaderType(RETRY); + if (QuicVersionHasLongHeaderLengths(framer_->transport_version())) { + creator_.SetLongHeaderType(HANDSHAKE); + } else { + // TODO(b/123493765): we should probably not be sending RETRY here. + creator_.SetLongHeaderType(RETRY); + } if (!creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION)) { QUIC_BUG << "Unable to add frame to an empty packet"; delete frame; @@ -165,16 +169,31 @@ collector_.SaveStatelessRejectFrameData(reject); while (offset < reject.length()) { QuicFrame frame; - creator_.SetLongHeaderType(RETRY); - if (!creator_.ConsumeData( - QuicUtils::GetCryptoStreamId(framer_->transport_version()), - reject.length(), offset, offset, - /*fin=*/false, - /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) { - QUIC_BUG << "Unable to consume data into an empty packet."; - return; + if (QuicVersionHasLongHeaderLengths(framer_->transport_version())) { + creator_.SetLongHeaderType(HANDSHAKE); + } else { + // TODO(b/123493765): we should probably not be sending RETRY here. + creator_.SetLongHeaderType(RETRY); } - offset += frame.stream_frame.data_length; + if (framer_->transport_version() < QUIC_VERSION_47) { + if (!creator_.ConsumeData( + QuicUtils::GetCryptoStreamId(framer_->transport_version()), + reject.length(), offset, offset, + /*fin=*/false, + /*needs_full_padding=*/true, NOT_RETRANSMISSION, &frame)) { + QUIC_BUG << "Unable to consume data into an empty packet."; + return; + } + offset += frame.stream_frame.data_length; + } else { + if (!creator_.ConsumeCryptoData(ENCRYPTION_NONE, + reject.length() - offset, offset, + NOT_RETRANSMISSION, &frame)) { + QUIC_BUG << "Unable to consume crypto data into an empty packet."; + return; + } + offset += frame.crypto_frame->data_length; + } if (offset < reject.length()) { DCHECK(!creator_.HasRoomForStreamFrame( QuicUtils::GetCryptoStreamId(framer_->transport_version()), offset, @@ -267,7 +286,7 @@ } // namespace QuicDispatcher::QuicDispatcher( - const QuicConfig& config, + const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper, @@ -404,16 +423,13 @@ if (ShouldCreateSessionForUnknownVersion(framer_.last_version_label())) { return true; } - if (!GetQuicReloadableFlag(quic_limit_version_negotiation) || - current_packet_->length() >= kMinPacketSizeForVersionNegotiation) { + if (current_packet_->length() >= kMinPacketSizeForVersionNegotiation) { // Since the version is not supported, send a version negotiation // packet and stop processing the current packet. time_wait_list_manager()->SendVersionNegotiationPacket( connection_id, header.form != GOOGLE_QUIC_PACKET, GetSupportedVersions(), current_self_address_, current_peer_address_, GetPerPacketContext()); - } else { - QUIC_RELOADABLE_FLAG_COUNT(quic_limit_version_negotiation); } return false; } @@ -845,6 +861,10 @@ return false; } +void QuicDispatcher::OnCoalescedPacket(const QuicEncryptedPacket& /*packet*/) { + DCHECK(false); +} + bool QuicDispatcher::OnStreamFrame(const QuicStreamFrame& /*frame*/) { DCHECK(false); return false; @@ -1202,7 +1222,7 @@ ChloAlpnExtractor alpn_extractor; if (FLAGS_quic_allow_chlo_buffering && !ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), - config_.create_session_tag_indicators(), + config_->create_session_tag_indicators(), &alpn_extractor)) { // Buffer non-CHLO packets. ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, @@ -1224,7 +1244,7 @@ current_peer_address_, current_self_address_, rejector.get()); if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(), - config_.create_session_tag_indicators(), + config_->create_session_tag_indicators(), &validator)) { ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form, version); return; @@ -1281,12 +1301,6 @@ current_packet_ = current_packet.get(); current_connection_id_ = rejector->connection_id(); framer_.set_version(first_version); - if (GetQuicReloadableFlag(quic_fix_last_packet_is_ietf_quic)) { - if (GetLastPacketFormat() != current_packet_format) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_last_packet_is_ietf_quic); - } - framer_.set_last_packet_form(current_packet_format); - } // Stop buffering packets on this connection const auto num_erased = @@ -1385,8 +1399,4 @@ framer_.set_validate_flags(false); } -PacketHeaderFormat QuicDispatcher::GetLastPacketFormat() const { - return framer_.GetLastPacketFormat(); -} - } // namespace quic
diff --git a/quic/core/quic_dispatcher.h b/quic/core/quic_dispatcher.h index d6eb35b..b0c2509 100644 --- a/quic/core/quic_dispatcher.h +++ b/quic/core/quic_dispatcher.h
@@ -44,7 +44,7 @@ // Ideally we'd have a linked_hash_set: the boolean is unused. typedef QuicLinkedHashMap<QuicBlockedWriterInterface*, bool> WriteBlockedList; - QuicDispatcher(const QuicConfig& config, + QuicDispatcher(const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper, @@ -143,6 +143,7 @@ const QuicVersionNegotiationPacket& packet) override; void OnDecryptedPacket(EncryptionLevel level) override; bool OnPacketHeader(const QuicPacketHeader& header) override; + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override; bool OnStreamFrame(const QuicStreamFrame& frame) override; bool OnCryptoFrame(const QuicCryptoFrame& frame) override; bool OnAckFrameStart(QuicPacketNumber largest_acked, @@ -271,7 +272,7 @@ } const QuicReceivedPacket& current_packet() const { return *current_packet_; } - const QuicConfig& config() const { return config_; } + const QuicConfig& config() const { return *config_; } const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; } @@ -351,11 +352,6 @@ // Skip validating that the public flags are set to legal values. void DisableFlagValidation(); - // Please do not use this method. - // TODO(fayang): Remove this method when deprecating - // quic_fix_last_packet_is_ietf_quic flag. - PacketHeaderFormat GetLastPacketFormat() const; - private: friend class test::QuicDispatcherPeer; friend class StatelessRejectorProcessDoneCallback; @@ -410,7 +406,7 @@ new_sessions_allowed_per_event_loop_ = new_sessions_allowed_per_event_loop; } - const QuicConfig& config_; + const QuicConfig* config_; const QuicCryptoServerConfig* crypto_config_;
diff --git a/quic/core/quic_dispatcher_test.cc b/quic/core/quic_dispatcher_test.cc index 0381cf5..7fc1263 100644 --- a/quic/core/quic_dispatcher_test.cc +++ b/quic/core/quic_dispatcher_test.cc
@@ -72,7 +72,7 @@ TestQuicSpdyServerSession& operator=(const TestQuicSpdyServerSession&) = delete; - ~TestQuicSpdyServerSession() override { delete connection(); }; + ~TestQuicSpdyServerSession() override { delete connection(); } MOCK_METHOD3(OnConnectionClosed, void(QuicErrorCode error, @@ -114,7 +114,7 @@ class TestDispatcher : public QuicDispatcher { public: - TestDispatcher(const QuicConfig& config, + TestDispatcher(const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager) : QuicDispatcher(config, @@ -157,7 +157,6 @@ using QuicDispatcher::current_client_address; using QuicDispatcher::current_peer_address; using QuicDispatcher::current_self_address; - using QuicDispatcher::GetLastPacketFormat; using QuicDispatcher::writer; }; @@ -207,7 +206,8 @@ std::move(proof_source), KeyExchangeSource::Default(), TlsServerHandshaker::CreateSslCtx()), - dispatcher_(new NiceMock<TestDispatcher>(config_, + server_address_(QuicIpAddress::Any4(), 5), + dispatcher_(new NiceMock<TestDispatcher>(&config_, &crypto_config_, &version_manager_)), time_wait_list_manager_(nullptr), @@ -370,9 +370,12 @@ }; TEST_F(QuicDispatcherTest, TlsClientHelloCreatesSession) { + if (CurrentSupportedVersions().front().transport_version < QUIC_VERSION_47) { + // TLS is only supported in versions 47 and greater. + return; + } FLAGS_quic_supports_tls_handshake = true; QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(1), client_address, @@ -400,7 +403,6 @@ TEST_F(QuicDispatcherTest, ProcessPackets) { QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(1), client_address, @@ -448,7 +450,6 @@ // Regression test of b/93325907. TEST_F(QuicDispatcherTest, DispatcherDoesNotRejectPacketNumberZero) { QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(1), client_address, @@ -486,9 +487,7 @@ TEST_F(QuicDispatcherTest, StatelessVersionNegotiation) { CreateTimeWaitListManager(); - SetQuicReloadableFlag(quic_limit_version_negotiation, false); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, @@ -497,16 +496,17 @@ QuicTransportVersion version = static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1); ParsedQuicVersion parsed_version(PROTOCOL_QUIC_CRYPTO, version); - ProcessPacket(client_address, TestConnectionId(1), true, parsed_version, - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_4BYTE_PACKET_NUMBER, 1); + // Pad the CHLO message with enough data to make the packet large enough + // to trigger version negotiation. + QuicString chlo = SerializeCHLO() + QuicString(1200, 'a'); + DCHECK_LE(1200u, chlo.length()); + ProcessPacket(client_address, TestConnectionId(1), true, parsed_version, chlo, + PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); } TEST_F(QuicDispatcherTest, NoVersionNegotiationWithSmallPacket) { CreateTimeWaitListManager(); - SetQuicReloadableFlag(quic_limit_version_negotiation, true); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, _, _)).Times(0); EXPECT_CALL(*time_wait_list_manager_, @@ -515,10 +515,12 @@ QuicTransportVersion version = static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1); ParsedQuicVersion parsed_version(PROTOCOL_QUIC_CRYPTO, version); - QuicString chlo = SerializeCHLO(); + QuicString chlo = SerializeCHLO() + QuicString(1200, 'a'); // Truncate to 1100 bytes of payload which results in a packet just // under 1200 bytes after framing, packet, and encryption overhead. + DCHECK_LE(1200u, chlo.length()); QuicString truncated_chlo = chlo.substr(0, 1100); + DCHECK_EQ(1100u, truncated_chlo.length()); ProcessPacket(client_address, TestConnectionId(1), true, parsed_version, truncated_chlo, PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); @@ -607,7 +609,6 @@ CreateTimeWaitListManager(); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 0); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); // dispatcher_ should drop this packet. EXPECT_CALL(*dispatcher_, @@ -623,7 +624,6 @@ TEST_F(QuicDispatcherTest, OKSeqNoPacketProcessed) { QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); QuicConnectionId connection_id = TestConnectionId(1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); EXPECT_CALL(*dispatcher_, CreateQuicSession(TestConnectionId(1), client_address, @@ -681,17 +681,15 @@ } TEST_F(QuicDispatcherTest, SupportedTransportVersionsChangeInFlight) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - SetQuicReloadableFlag(quic_disable_version_35, false); + SetQuicReloadableFlag(quic_disable_version_39, false); SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); - SetQuicReloadableFlag(quic_enable_version_45, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, true); SetQuicReloadableFlag(quic_enable_version_99, true); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); uint64_t conn_id = 1; QuicConnectionId connection_id = TestConnectionId(conn_id); @@ -808,39 +806,6 @@ SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); - // Turn off version 45. - SetQuicReloadableFlag(quic_enable_version_45, false); - connection_id = TestConnectionId(++conn_id); - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"), _)) - .Times(0); - ProcessPacket(client_address, connection_id, true, - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45), - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_4BYTE_PACKET_NUMBER, 1); - - // Turn on version 45. - SetQuicReloadableFlag(quic_enable_version_45, true); - connection_id = TestConnectionId(++conn_id); - EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, - QuicStringPiece("hq"), _)) - .WillOnce(testing::Return(CreateSession( - dispatcher_.get(), config_, connection_id, client_address, - &mock_helper_, &mock_alarm_factory_, &crypto_config_, - QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_))); - EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()), - ProcessUdpPacket(_, _, _)) - .WillOnce(WithArg<2>( - Invoke([this, connection_id](const QuicEncryptedPacket& packet) { - ValidatePacket(connection_id, packet); - }))); - EXPECT_CALL(*dispatcher_, - ShouldCreateOrBufferPacketForConnection(connection_id, _)); - ProcessPacket(client_address, connection_id, true, - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45), - SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, - PACKET_4BYTE_PACKET_NUMBER, 1); - // Turn off version 44. SetQuicReloadableFlag(quic_enable_version_44, false); connection_id = TestConnectionId(++conn_id); @@ -907,19 +872,19 @@ SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); - // Turn off version 35. - SetQuicReloadableFlag(quic_disable_version_35, true); + // Turn off version 39. + SetQuicReloadableFlag(quic_disable_version_39, true); connection_id = TestConnectionId(++conn_id); EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, QuicStringPiece("hq"), _)) .Times(0); ProcessPacket(client_address, connection_id, true, - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35), + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39), SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); - // Turn on version 35. - SetQuicReloadableFlag(quic_disable_version_35, false); + // Turn on version 39. + SetQuicReloadableFlag(quic_disable_version_39, false); connection_id = TestConnectionId(++conn_id); EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address, QuicStringPiece("hq"), _)) @@ -936,7 +901,7 @@ EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(connection_id, _)); ProcessPacket(client_address, connection_id, true, - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35), + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39), SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); } @@ -1067,9 +1032,9 @@ // Parameterized test for stateless rejects. Should test all // combinations of enabling/disabling, reject/no-reject for stateless // rejects. -INSTANTIATE_TEST_CASE_P(QuicDispatcherStatelessRejectTests, - QuicDispatcherStatelessRejectTest, - ::testing::ValuesIn(GetStatelessRejectTestParams())); +INSTANTIATE_TEST_SUITE_P(QuicDispatcherStatelessRejectTests, + QuicDispatcherStatelessRejectTest, + ::testing::ValuesIn(GetStatelessRejectTestParams())); TEST_P(QuicDispatcherStatelessRejectTest, ParameterizedBasicTest) { CreateTimeWaitListManager(); @@ -1624,6 +1589,7 @@ public: BufferedPacketStoreTest() : QuicDispatcherTest(), + server_addr_(QuicSocketAddress(QuicIpAddress::Any4(), 5)), client_addr_(QuicIpAddress::Loopback4(), 1234), signed_config_(new QuicSignedServerConfig) { SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, @@ -1660,7 +1626,7 @@ CryptoHandshakeMessage full_chlo_; }; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BufferedPacketStoreTests, BufferedPacketStoreTest, ::testing::ValuesIn(GetBufferedPacketStoreTestParams())); @@ -1668,7 +1634,6 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsUptoLimitAndProcessChlo) { InSequence s; QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); QuicConnectionId conn_id = TestConnectionId(1); // A bunch of non-CHLO should be buffered upon arrival, and the first one // should trigger ShouldCreateOrBufferPacketForConnection(). @@ -1708,7 +1673,6 @@ TEST_P(BufferedPacketStoreTest, ProcessNonChloPacketsForDifferentConnectionsUptoLimit) { InSequence s; - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); // A bunch of non-CHLO should be buffered upon arrival. size_t kNumConnections = kMaxConnectionsWithoutCHLO + 1; for (size_t i = 1; i <= kNumConnections; ++i) { @@ -1781,7 +1745,6 @@ TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) { InSequence s; QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); QuicConnectionId conn_id = TestConnectionId(1); ProcessPacket(client_address, conn_id, true, QuicStrCat("data packet ", 2), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, @@ -1817,7 +1780,6 @@ QuicBufferedPacketStorePeer::set_clock(store, mock_helper_.GetClock()); QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1); - server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5); QuicConnectionId conn_id = TestConnectionId(1); ProcessPacket(client_address, conn_id, true, QuicStrCat("data packet ", 2), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, @@ -2125,6 +2087,7 @@ client_addr_(QuicIpAddress::Loopback4(), 1234), client_addr_2_(QuicIpAddress::Loopback4(), 1357), crypto_config_peer_(&crypto_config_), + server_addr_(QuicIpAddress::Any4(), 5), signed_config_(new QuicSignedServerConfig) { SetQuicReloadableFlag(enable_quic_stateless_reject_support, true); SetQuicReloadableFlag(quic_use_cheap_stateless_rejects, true); @@ -2722,16 +2685,17 @@ // different endianness which causes the client to close the connection // because of QUIC_INVALID_STREAM_DATA. - SetQuicReloadableFlag(quic_disable_version_35, false); - ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39); + SetQuicReloadableFlag(quic_disable_version_39, false); + SetQuicReloadableFlag(quic_enable_version_43, true); + ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43); chlo_.SetVersion(kVER, chlo_version); - // Send a CHLO with v39. Dispatcher framer's version is set to v39. + // Send a CHLO with v43. Dispatcher framer's version is set to v43. ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version, SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); - // Send another CHLO with v35. Dispatcher framer's version is set to v35. - chlo_version.transport_version = QUIC_VERSION_35; + // Send another CHLO with v39. Dispatcher framer's version is set to v39. + chlo_version.transport_version = QUIC_VERSION_39; chlo_.SetVersion(kVER, chlo_version); // Invalidate the cached serialized form. chlo_.MarkDirty(); @@ -2740,7 +2704,7 @@ PACKET_4BYTE_PACKET_NUMBER, 1); ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); - // Complete the ProofSource::GetProof call for v39. This would cause the + // Complete the ProofSource::GetProof call for v43. This would cause the // version mismatch between the CHLO packet and the dispatcher. GetFakeProofSource()->InvokePendingCallback(0); ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); @@ -2748,15 +2712,12 @@ // Regression test for b/116200989. TEST_F(AsyncGetProofTest, DispatcherHasWrongLastPacketIsIetfQuic) { - SetQuicReloadableFlag(quic_fix_last_packet_is_ietf_quic, true); - // Process a packet of v44. ParsedQuicVersion chlo_version(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44); chlo_.SetVersion(kVER, chlo_version); ProcessPacket(client_addr_, TestConnectionId(1), true, chlo_version, SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); - EXPECT_NE(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat()); // Process another packet of v43. chlo_version.transport_version = QUIC_VERSION_43; @@ -2766,18 +2727,14 @@ ProcessPacket(client_addr_, TestConnectionId(2), true, chlo_version, SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1); - EXPECT_EQ(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat()); ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2); // Complete the ProofSource::GetProof call for v44. GetFakeProofSource()->InvokePendingCallback(0); - // Verify the last_packet_is_ietf_quic gets reset properly. - EXPECT_NE(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat()); ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1); // Complete the ProofSource::GetProof call for v43. GetFakeProofSource()->InvokePendingCallback(0); - EXPECT_EQ(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat()); ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0); }
diff --git a/quic/core/quic_epoll_alarm_factory.cc b/quic/core/quic_epoll_alarm_factory.cc index 2ec2f6f..2d6efdf 100644 --- a/quic/core/quic_epoll_alarm_factory.cc +++ b/quic/core/quic_epoll_alarm_factory.cc
@@ -69,7 +69,7 @@ QuicEpollAlarmFactory::QuicEpollAlarmFactory(QuicEpollServer* epoll_server) : epoll_server_(epoll_server) {} -QuicEpollAlarmFactory::~QuicEpollAlarmFactory() {} +QuicEpollAlarmFactory::~QuicEpollAlarmFactory() = default; QuicAlarm* QuicEpollAlarmFactory::CreateAlarm(QuicAlarm::Delegate* delegate) { return new QuicEpollAlarm(epoll_server_,
diff --git a/quic/core/quic_epoll_alarm_factory_test.cc b/quic/core/quic_epoll_alarm_factory_test.cc index b8d4caf..08a7cfe 100644 --- a/quic/core/quic_epoll_alarm_factory_test.cc +++ b/quic/core/quic_epoll_alarm_factory_test.cc
@@ -40,9 +40,8 @@ QuicConnectionArena arena_; }; -INSTANTIATE_TEST_CASE_P(UseArena, - QuicEpollAlarmFactoryTest, - ::testing::ValuesIn({true, false})); +INSTANTIATE_TEST_SUITE_P(UseArena, QuicEpollAlarmFactoryTest, + ::testing::ValuesIn({true, false})); TEST_P(QuicEpollAlarmFactoryTest, CreateAlarm) { QuicArenaScopedPtr<TestDelegate> delegate =
diff --git a/quic/core/quic_epoll_connection_helper.cc b/quic/core/quic_epoll_connection_helper.cc index 49002f6..e05139f 100644 --- a/quic/core/quic_epoll_connection_helper.cc +++ b/quic/core/quic_epoll_connection_helper.cc
@@ -22,7 +22,7 @@ random_generator_(QuicRandom::GetInstance()), allocator_type_(type) {} -QuicEpollConnectionHelper::~QuicEpollConnectionHelper() {} +QuicEpollConnectionHelper::~QuicEpollConnectionHelper() = default; const QuicClock* QuicEpollConnectionHelper::GetClock() const { return &clock_;
diff --git a/quic/core/quic_epoll_connection_helper.h b/quic/core/quic_epoll_connection_helper.h index 62e030c..8b2a469 100644 --- a/quic/core/quic_epoll_connection_helper.h +++ b/quic/core/quic_epoll_connection_helper.h
@@ -56,8 +56,6 @@ QuicBufferAllocator* GetStreamSendBufferAllocator() override; private: - friend class QuicEpollConnectionHelperPeer; - const QuicEpollClock clock_; QuicRandom* random_generator_; // Set up allocators. They take up minimal memory before use.
diff --git a/quic/core/quic_error_codes.cc b/quic/core/quic_error_codes.cc index a6259e9..215f527 100644 --- a/quic/core/quic_error_codes.cc +++ b/quic/core/quic_error_codes.cc
@@ -155,6 +155,7 @@ RETURN_STRING_LITERAL(QUIC_STREAM_ID_BLOCKED_ERROR); RETURN_STRING_LITERAL(QUIC_MAX_STREAM_ID_ERROR); RETURN_STRING_LITERAL(QUIC_HTTP_DECODER_ERROR); + RETURN_STRING_LITERAL(QUIC_STALE_CONNECTION_CANCELLED); RETURN_STRING_LITERAL(QUIC_LAST_ERROR); // Intentionally have no default case, so we'll break the build
diff --git a/quic/core/quic_error_codes.h b/quic/core/quic_error_codes.h index ebf15f5..d3446a8 100644 --- a/quic/core/quic_error_codes.h +++ b/quic/core/quic_error_codes.h
@@ -325,9 +325,11 @@ QUIC_MAX_STREAM_ID_ERROR = 119, // Error in Http decoder QUIC_HTTP_DECODER_ERROR = 120, + // Connection from stale host needs to be cancelled. + QUIC_STALE_CONNECTION_CANCELLED = 121, // No error. Used as bound while iterating. - QUIC_LAST_ERROR = 121, + QUIC_LAST_ERROR = 122, }; // QuicErrorCodes is encoded as a single octet on-the-wire. static_assert(static_cast<int>(QUIC_LAST_ERROR) <=
diff --git a/quic/core/quic_framer.cc b/quic/core/quic_framer.cc index 1b93074..854b8c7 100644 --- a/quic/core/quic_framer.cc +++ b/quic/core/quic_framer.cc
@@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/core/quic_framer.h" +#include <cstddef> #include <cstdint> #include <memory> @@ -23,12 +24,14 @@ #include "net/third_party/quiche/src/quic/core/quic_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_aligned.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h" #include "net/third_party/quiche/src/quic/platform/api/quic_fallthrough.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" #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_stack_trace.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" @@ -186,7 +189,7 @@ uint8_t PacketNumberLengthToOnWireValue( QuicTransportVersion version, QuicPacketNumberLength packet_number_length) { - if (version > QUIC_VERSION_46) { + if (version > QUIC_VERSION_44) { return packet_number_length - 1; } switch (packet_number_length) { @@ -209,7 +212,7 @@ QuicPacketNumberLength* packet_number_length) { DCHECK(!(type & FLAGS_LONG_HEADER)); const bool two_bits_packet_number_length = - infer_packet_header_type_from_version ? version > QUIC_VERSION_46 + infer_packet_header_type_from_version ? version > QUIC_VERSION_44 : (type & FLAGS_FIXED_BIT); if (two_bits_packet_number_length) { *packet_number_length = @@ -237,13 +240,13 @@ QuicLongHeaderType type) { switch (type) { case INITIAL: - return version > QUIC_VERSION_46 ? 0 : 0x7F; + return version > QUIC_VERSION_44 ? 0 : 0x7F; case ZERO_RTT_PROTECTED: - return version > QUIC_VERSION_46 ? 1 << 4 : 0x7C; + return version > QUIC_VERSION_44 ? 1 << 4 : 0x7C; case HANDSHAKE: - return version > QUIC_VERSION_46 ? 2 << 4 : 0x7D; + return version > QUIC_VERSION_44 ? 2 << 4 : 0x7D; case RETRY: - return version > QUIC_VERSION_46 ? 3 << 4 : 0x7E; + return version > QUIC_VERSION_44 ? 3 << 4 : 0x7E; case VERSION_NEGOTIATION: return 0xF0; // Value does not matter default: @@ -256,7 +259,7 @@ uint8_t type, QuicLongHeaderType* long_header_type) { DCHECK((type & FLAGS_LONG_HEADER) && version != QUIC_VERSION_UNSUPPORTED); - if (version > QUIC_VERSION_46) { + if (version > QUIC_VERSION_44) { switch ((type & 0x30) >> 4) { case 0: *long_header_type = INITIAL; @@ -303,7 +306,7 @@ QuicPacketNumberLength GetLongHeaderPacketNumberLength( QuicTransportVersion version, uint8_t type) { - if (version > QUIC_VERSION_46) { + if (version > QUIC_VERSION_44) { return static_cast<QuicPacketNumberLength>((type & 0x03) + 1); } return PACKET_4BYTE_PACKET_NUMBER; @@ -343,6 +346,63 @@ version == QUIC_VERSION_99); } +// Convert a stream ID to a count of streams, for IETF QUIC/Version 99 only. +// There is no need to take into account whether the ID is for uni- or +// bi-directional streams, or whether it's server- or client- initiated. It +// always returns a valid count. +QuicStreamId StreamIdToCount(QuicTransportVersion version, + QuicStreamId stream_id) { + DCHECK_EQ(QUIC_VERSION_99, version); + if ((stream_id & 0x3) == 0) { + return (stream_id / QuicUtils::StreamIdDelta(version)); + } + return (stream_id / QuicUtils::StreamIdDelta(version)) + 1; +} + +// Returns the maximum value that a stream count may have, taking into account +// the fact that bidirectional, client initiated, streams have one fewer stream +// available than the others. This is because the old crypto streams, with ID == +// 0 are not included in the count. +// The version is not included in the call, nor does the method take the version +// into account, because this is called only from code used for IETF QUIC. +// TODO(fkastenholz): Remove this method and replace calls to it with direct +// references to kMaxQuicStreamIdCount when streamid 0 becomes a normal stream +// id. +QuicStreamId GetMaxStreamCount(bool unidirectional, Perspective perspective) { + if (!unidirectional && perspective == Perspective::IS_CLIENT) { + return kMaxQuicStreamId >> 2; + } + return (kMaxQuicStreamId >> 2) + 1; +} + +// Convert a stream count to the maximum stream ID for that count. +// Needs to know whether the resulting stream ID should be uni-directional, +// bi-directional, server-initiated, or client-initiated. +// Returns true if it works, false if not. The only error condition is that +// the stream_count is too big and it would generate a stream id that is larger +// than the implementation's maximum stream id value. +bool StreamCountToId(QuicStreamId stream_count, + bool unidirectional, + Perspective perspective, + QuicTransportVersion version, + QuicStreamId* generated_stream_id) { + DCHECK_EQ(QUIC_VERSION_99, version); + // TODO(fkastenholz): when the MAX_STREAMS and STREAMS_BLOCKED frames + // are connected all the way up to the stream_id_manager, handle count==0 + // properly (interpret it as "can open 0 streams") and the count being too + // large (close the connection). + if ((stream_count == 0) || + (stream_count > GetMaxStreamCount(unidirectional, perspective))) { + return false; + } + *generated_stream_id = + ((unidirectional) + ? QuicUtils::GetFirstUnidirectionalStreamId(version, perspective) + : QuicUtils::GetFirstBidirectionalStreamId(version, perspective)) + + ((stream_count - 1) * QuicUtils::StreamIdDelta(version)); + return true; +} + } // namespace QuicFramer::QuicFramer(const ParsedQuicVersionVector& supported_versions, @@ -352,7 +412,6 @@ error_(QUIC_NO_ERROR), last_serialized_connection_id_(EmptyQuicConnectionId()), last_version_label_(0), - last_header_form_(GOOGLE_QUIC_PACKET), version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED), supported_versions_(supported_versions), decrypter_level_(ENCRYPTION_NONE), @@ -485,7 +544,7 @@ if (version != QUIC_VERSION_99) { return kQuicFrameTypeSize + kQuicMaxStreamIdSize + kQuicMaxStreamOffsetSize; } - if (frame.stream_id == 0) { + if (frame.stream_id == QuicUtils::GetInvalidStreamId(version)) { // Frame would be a MAX DATA frame, which has only a Maximum Data field. return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.byte_offset); @@ -498,24 +557,32 @@ } // static -size_t QuicFramer::GetMaxStreamIdFrameSize(QuicTransportVersion version, - const QuicMaxStreamIdFrame& frame) { +size_t QuicFramer::GetMaxStreamsFrameSize(QuicTransportVersion version, + const QuicMaxStreamIdFrame& frame) { if (version != QUIC_VERSION_99) { QUIC_BUG << "In version " << version << " - not 99 - and tried to serialize MaxStreamId Frame."; } - return kQuicFrameTypeSize + - QuicDataWriter::GetVarInt62Len(frame.max_stream_id); + + // Convert from the stream id on which the connection is blocked to a count + QuicStreamId stream_count = StreamIdToCount(version, frame.max_stream_id); + + return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(stream_count); } + // static -size_t QuicFramer::GetStreamIdBlockedFrameSize( +size_t QuicFramer::GetStreamsBlockedFrameSize( QuicTransportVersion version, const QuicStreamIdBlockedFrame& frame) { if (version != QUIC_VERSION_99) { QUIC_BUG << "In version " << version << " - not 99 - and tried to serialize StreamIdBlocked Frame."; } - return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.stream_id); + + // Convert from the stream id on which the connection is blocked to a count + QuicStreamId stream_count = StreamIdToCount(version, frame.stream_id); + + return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(stream_count); } // static @@ -524,10 +591,7 @@ if (version != QUIC_VERSION_99) { return kQuicFrameTypeSize + kQuicMaxStreamIdSize; } - // TODO(fkastenholz): This should be converted to use - // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value - // and not rely on 0. - if (frame.stream_id == 0) { + if (frame.stream_id == QuicUtils::GetInvalidStreamId(version)) { // return size of IETF QUIC Blocked frame return kQuicFrameTypeSize + QuicDataWriter::GetVarInt62Len(frame.offset); } @@ -591,10 +655,9 @@ case NEW_TOKEN_FRAME: return GetNewTokenFrameSize(*frame.new_token_frame); case MAX_STREAM_ID_FRAME: - return GetMaxStreamIdFrameSize(version, frame.max_stream_id_frame); + return GetMaxStreamsFrameSize(version, frame.max_stream_id_frame); case STREAM_ID_BLOCKED_FRAME: - return GetStreamIdBlockedFrameSize(version, - frame.stream_id_blocked_frame); + return GetStreamsBlockedFrameSize(version, frame.stream_id_blocked_frame); case PATH_RESPONSE_FRAME: return GetPathResponseFrameSize(*frame.path_response_frame); case PATH_CHALLENGE_FRAME: @@ -761,19 +824,63 @@ QuicFramer::AckFrameInfo::~AckFrameInfo() {} +bool QuicFramer::WriteIetfLongHeaderLength(const QuicPacketHeader& header, + QuicDataWriter* writer, + size_t length_field_offset, + EncryptionLevel level) { + if (!QuicVersionHasLongHeaderLengths(transport_version()) || + !header.version_flag || length_field_offset == 0) { + return true; + } + if (writer->length() < length_field_offset || + writer->length() - length_field_offset < + kQuicDefaultLongHeaderLengthLength) { + set_detailed_error("Invalid length_field_offset."); + QUIC_BUG << "Invalid length_field_offset."; + return false; + } + size_t length_to_write = writer->length() - length_field_offset - + kQuicDefaultLongHeaderLengthLength; + // Add length of auth tag. + length_to_write = GetCiphertextSize(level, length_to_write); + + QuicDataWriter length_writer(writer->length() - length_field_offset, + writer->data() + length_field_offset); + if (!length_writer.WriteVarInt62(length_to_write, + kQuicDefaultLongHeaderLengthLength)) { + set_detailed_error("Failed to overwrite long header length."); + QUIC_BUG << "Failed to overwrite long header length."; + return false; + } + return true; +} + size_t QuicFramer::BuildDataPacket(const QuicPacketHeader& header, const QuicFrames& frames, char* buffer, - size_t packet_length) { - if (version_.transport_version == QUIC_VERSION_99) { - return BuildIetfDataPacket(header, frames, buffer, packet_length); - } - QuicDataWriter writer(packet_length, buffer, endianness()); - if (!AppendPacketHeader(header, &writer)) { + size_t packet_length, + EncryptionLevel level) { + QuicDataWriter writer(packet_length, buffer); + size_t length_field_offset = 0; + if (!AppendPacketHeader(header, &writer, &length_field_offset)) { QUIC_BUG << "AppendPacketHeader failed"; return 0; } + if (transport_version() == QUIC_VERSION_99) { + if (AppendIetfFrames(frames, &writer) == 0) { + return 0; + } + if (!WriteIetfLongHeaderLength(header, &writer, length_field_offset, + level)) { + return 0; + } + return writer.length(); + } + // TODO(dschinazi) if we enable long header lengths before v99, we need to + // add support for fixing up lengths in QuicFramer::BuildDataPacket. + DCHECK(!QuicVersionHasLongHeaderLengths(transport_version())); + size_t i = 0; for (const QuicFrame& frame : frames) { // Determine if we should write stream frame length in header. @@ -893,173 +1000,11 @@ } break; case CRYPTO_FRAME: - set_detailed_error( - "Attempt to append CRYPTO frame and not in version 99."); - return RaiseError(QUIC_INTERNAL_ERROR); - default: - RaiseError(QUIC_INVALID_FRAME_DATA); - QUIC_BUG << "QUIC_INVALID_FRAME_DATA"; - return 0; - } - ++i; - } - - return writer.length(); -} - -size_t QuicFramer::BuildIetfDataPacket(const QuicPacketHeader& header, - const QuicFrames& frames, - char* buffer, - size_t packet_length) { - QuicDataWriter writer(packet_length, buffer, endianness()); - if (!AppendIetfPacketHeader(header, &writer)) { - QUIC_BUG << "AppendPacketHeader failed"; - return 0; - } - - size_t i = 0; - for (const QuicFrame& frame : frames) { - // Determine if we should write stream frame length in header. - const bool last_frame_in_packet = i == frames.size() - 1; - if (!AppendIetfTypeByte(frame, last_frame_in_packet, &writer)) { - QUIC_BUG << "AppendIetfTypeByte failed"; - return 0; - } - - switch (frame.type) { - case PADDING_FRAME: - if (!AppendPaddingFrame(frame.padding_frame, &writer)) { - QUIC_BUG << "AppendPaddingFrame of " - << frame.padding_frame.num_padding_bytes << " failed"; - return 0; + if (version_.transport_version < QUIC_VERSION_47) { + set_detailed_error( + "Attempt to append CRYPTO frame in version prior to 47."); + return RaiseError(QUIC_INTERNAL_ERROR); } - break; - case STREAM_FRAME: - if (!AppendStreamFrame(frame.stream_frame, last_frame_in_packet, - &writer)) { - QUIC_BUG << "AppendStreamFrame failed"; - return 0; - } - break; - case ACK_FRAME: - if (!AppendIetfAckFrameAndTypeByte(*frame.ack_frame, &writer)) { - QUIC_BUG << "AppendAckFrameAndTypeByte failed"; - return 0; - } - break; - case STOP_WAITING_FRAME: - set_detailed_error( - "Attempt to append STOP WAITING frame in version 99."); - return RaiseError(QUIC_INTERNAL_ERROR); - case MTU_DISCOVERY_FRAME: - // MTU discovery frames are serialized as ping frames. - QUIC_FALLTHROUGH_INTENDED; - case PING_FRAME: - // Ping has no payload. - break; - case RST_STREAM_FRAME: - if (!AppendRstStreamFrame(*frame.rst_stream_frame, &writer)) { - QUIC_BUG << "AppendRstStreamFrame failed"; - return 0; - } - break; - case CONNECTION_CLOSE_FRAME: - if (!AppendConnectionCloseFrame(*frame.connection_close_frame, - &writer)) { - QUIC_BUG << "AppendConnectionCloseFrame failed"; - return 0; - } - break; - case GOAWAY_FRAME: - set_detailed_error("Attempt to append GOAWAY frame in version 99."); - return RaiseError(QUIC_INTERNAL_ERROR); - case WINDOW_UPDATE_FRAME: - // Depending on whether there is a stream ID or not, will be either a - // MAX STREAM DATA frame or a MAX DATA frame. - if (frame.window_update_frame->stream_id == 0) { - if (!AppendMaxDataFrame(*frame.window_update_frame, &writer)) { - QUIC_BUG << "AppendMaxDataFrame failed"; - return 0; - } - } else { - if (!AppendMaxStreamDataFrame(*frame.window_update_frame, &writer)) { - QUIC_BUG << "AppendMaxStreamDataFrame failed"; - return 0; - } - } - break; - case BLOCKED_FRAME: - if (!AppendBlockedFrame(*frame.blocked_frame, &writer)) { - QUIC_BUG << "AppendBlockedFrame failed"; - return 0; - } - break; - case APPLICATION_CLOSE_FRAME: - if (!AppendApplicationCloseFrame(*frame.application_close_frame, - &writer)) { - QUIC_BUG << "AppendApplicationCloseFrame failed"; - return 0; - } - break; - case MAX_STREAM_ID_FRAME: - if (!AppendMaxStreamIdFrame(frame.max_stream_id_frame, &writer)) { - QUIC_BUG << "AppendMaxStreamIdFrame failed"; - return 0; - } - break; - case STREAM_ID_BLOCKED_FRAME: - if (!AppendStreamIdBlockedFrame(frame.stream_id_blocked_frame, - &writer)) { - QUIC_BUG << "AppendMaxStreamIdFrame failed"; - return 0; - } - break; - case NEW_CONNECTION_ID_FRAME: - if (!AppendNewConnectionIdFrame(*frame.new_connection_id_frame, - &writer)) { - QUIC_BUG << "AppendNewConnectionIdFrame failed"; - return 0; - } - break; - case RETIRE_CONNECTION_ID_FRAME: - if (!AppendRetireConnectionIdFrame(*frame.retire_connection_id_frame, - &writer)) { - QUIC_BUG << "AppendRetireConnectionIdFrame failed"; - return 0; - } - break; - case NEW_TOKEN_FRAME: - if (!AppendNewTokenFrame(*frame.new_token_frame, &writer)) { - QUIC_BUG << "AppendNewTokenFrame failed"; - return 0; - } - break; - case STOP_SENDING_FRAME: - if (!AppendStopSendingFrame(*frame.stop_sending_frame, &writer)) { - QUIC_BUG << "AppendStopSendingFrame failed"; - return 0; - } - break; - case PATH_CHALLENGE_FRAME: - if (!AppendPathChallengeFrame(*frame.path_challenge_frame, &writer)) { - QUIC_BUG << "AppendPathChallengeFrame failed"; - return 0; - } - break; - case PATH_RESPONSE_FRAME: - if (!AppendPathResponseFrame(*frame.path_response_frame, &writer)) { - QUIC_BUG << "AppendPathResponseFrame failed"; - return 0; - } - break; - case MESSAGE_FRAME: - if (!AppendMessageFrameAndTypeByte(*frame.message_frame, - last_frame_in_packet, &writer)) { - QUIC_BUG << "AppendMessageFrame failed"; - return 0; - } - break; - case CRYPTO_FRAME: if (!AppendCryptoFrame(*frame.crypto_frame, &writer)) { QUIC_BUG << "AppendCryptoFrame failed"; return 0; @@ -1076,10 +1021,176 @@ return writer.length(); } -size_t QuicFramer::BuildIetfConnectivityProbingPacket( +size_t QuicFramer::AppendIetfFrames(const QuicFrames& frames, + QuicDataWriter* writer) { + size_t i = 0; + for (const QuicFrame& frame : frames) { + // Determine if we should write stream frame length in header. + const bool last_frame_in_packet = i == frames.size() - 1; + if (!AppendIetfTypeByte(frame, last_frame_in_packet, writer)) { + QUIC_BUG << "AppendIetfTypeByte failed: " << detailed_error(); + return 0; + } + + switch (frame.type) { + case PADDING_FRAME: + if (!AppendPaddingFrame(frame.padding_frame, writer)) { + QUIC_BUG << "AppendPaddingFrame of " + << frame.padding_frame.num_padding_bytes + << " failed: " << detailed_error(); + return 0; + } + break; + case STREAM_FRAME: + if (!AppendStreamFrame(frame.stream_frame, last_frame_in_packet, + writer)) { + QUIC_BUG << "AppendStreamFrame failed: " << detailed_error(); + return 0; + } + break; + case ACK_FRAME: + if (!AppendIetfAckFrameAndTypeByte(*frame.ack_frame, writer)) { + QUIC_BUG << "AppendAckFrameAndTypeByte failed: " << detailed_error(); + return 0; + } + break; + case STOP_WAITING_FRAME: + set_detailed_error( + "Attempt to append STOP WAITING frame in version 99."); + return RaiseError(QUIC_INTERNAL_ERROR); + case MTU_DISCOVERY_FRAME: + // MTU discovery frames are serialized as ping frames. + QUIC_FALLTHROUGH_INTENDED; + case PING_FRAME: + // Ping has no payload. + break; + case RST_STREAM_FRAME: + if (!AppendRstStreamFrame(*frame.rst_stream_frame, writer)) { + QUIC_BUG << "AppendRstStreamFrame failed: " << detailed_error(); + return 0; + } + break; + case CONNECTION_CLOSE_FRAME: + if (!AppendConnectionCloseFrame(*frame.connection_close_frame, + writer)) { + QUIC_BUG << "AppendConnectionCloseFrame failed: " << detailed_error(); + return 0; + } + break; + case GOAWAY_FRAME: + set_detailed_error("Attempt to append GOAWAY frame in version 99."); + return RaiseError(QUIC_INTERNAL_ERROR); + case WINDOW_UPDATE_FRAME: + // Depending on whether there is a stream ID or not, will be either a + // MAX STREAM DATA frame or a MAX DATA frame. + if (frame.window_update_frame->stream_id == + QuicUtils::GetInvalidStreamId(transport_version())) { + if (!AppendMaxDataFrame(*frame.window_update_frame, writer)) { + QUIC_BUG << "AppendMaxDataFrame failed: " << detailed_error(); + return 0; + } + } else { + if (!AppendMaxStreamDataFrame(*frame.window_update_frame, writer)) { + QUIC_BUG << "AppendMaxStreamDataFrame failed: " << detailed_error(); + return 0; + } + } + break; + case BLOCKED_FRAME: + if (!AppendBlockedFrame(*frame.blocked_frame, writer)) { + QUIC_BUG << "AppendBlockedFrame failed: " << detailed_error(); + return 0; + } + break; + case APPLICATION_CLOSE_FRAME: + if (!AppendApplicationCloseFrame(*frame.application_close_frame, + writer)) { + QUIC_BUG << "AppendApplicationCloseFrame failed: " + << detailed_error(); + return 0; + } + break; + case MAX_STREAM_ID_FRAME: + if (!AppendMaxStreamsFrame(frame.max_stream_id_frame, writer)) { + QUIC_BUG << "AppendMaxStreamsFrame failed" << detailed_error(); + return 0; + } + break; + case STREAM_ID_BLOCKED_FRAME: + if (!AppendStreamsBlockedFrame(frame.stream_id_blocked_frame, writer)) { + QUIC_BUG << "AppendStreamsBlockedFrame failed" << detailed_error(); + return 0; + } + break; + case NEW_CONNECTION_ID_FRAME: + if (!AppendNewConnectionIdFrame(*frame.new_connection_id_frame, + writer)) { + QUIC_BUG << "AppendNewConnectionIdFrame failed: " << detailed_error(); + return 0; + } + break; + case RETIRE_CONNECTION_ID_FRAME: + if (!AppendRetireConnectionIdFrame(*frame.retire_connection_id_frame, + writer)) { + QUIC_BUG << "AppendRetireConnectionIdFrame failed: " + << detailed_error(); + return 0; + } + break; + case NEW_TOKEN_FRAME: + if (!AppendNewTokenFrame(*frame.new_token_frame, writer)) { + QUIC_BUG << "AppendNewTokenFrame failed: " << detailed_error(); + return 0; + } + break; + case STOP_SENDING_FRAME: + if (!AppendStopSendingFrame(*frame.stop_sending_frame, writer)) { + QUIC_BUG << "AppendStopSendingFrame failed: " << detailed_error(); + return 0; + } + break; + case PATH_CHALLENGE_FRAME: + if (!AppendPathChallengeFrame(*frame.path_challenge_frame, writer)) { + QUIC_BUG << "AppendPathChallengeFrame failed: " << detailed_error(); + return 0; + } + break; + case PATH_RESPONSE_FRAME: + if (!AppendPathResponseFrame(*frame.path_response_frame, writer)) { + QUIC_BUG << "AppendPathResponseFrame failed: " << detailed_error(); + return 0; + } + break; + case MESSAGE_FRAME: + if (!AppendMessageFrameAndTypeByte(*frame.message_frame, + last_frame_in_packet, writer)) { + QUIC_BUG << "AppendMessageFrame failed: " << detailed_error(); + return 0; + } + break; + case CRYPTO_FRAME: + if (!AppendCryptoFrame(*frame.crypto_frame, writer)) { + QUIC_BUG << "AppendCryptoFrame failed: " << detailed_error(); + return 0; + } + break; + default: + RaiseError(QUIC_INVALID_FRAME_DATA); + set_detailed_error("Tried to append unknown frame type."); + QUIC_BUG << "QUIC_INVALID_FRAME_DATA"; + return 0; + } + ++i; + } + + return writer->length(); +} + +size_t QuicFramer::BuildConnectivityProbingPacketNew( const QuicPacketHeader& header, char* buffer, - size_t packet_length) { + size_t packet_length, + EncryptionLevel level) { QuicFrames frames; // Write a PING frame, which has no data payload. @@ -1090,19 +1201,26 @@ QuicPaddingFrame padding_frame; frames.push_back(QuicFrame(padding_frame)); - return BuildIetfDataPacket(header, frames, buffer, packet_length); + return BuildDataPacket(header, frames, buffer, packet_length, level); } size_t QuicFramer::BuildConnectivityProbingPacket( const QuicPacketHeader& header, char* buffer, - size_t packet_length) { - if (version_.transport_version == QUIC_VERSION_99) { - return BuildIetfConnectivityProbingPacket(header, buffer, packet_length); + size_t packet_length, + EncryptionLevel level) { + if (transport_version() == QUIC_VERSION_99 || + QuicVersionHasLongHeaderLengths(transport_version()) || + GetQuicReloadableFlag(quic_simplify_build_connectivity_probing_packet)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_simplify_build_connectivity_probing_packet); + // TODO(rch): Remove this method when the flag is deprecated. + return BuildConnectivityProbingPacketNew(header, buffer, packet_length, + level); } - QuicDataWriter writer(packet_length, buffer, endianness()); - if (!AppendPacketHeader(header, &writer)) { + QuicDataWriter writer(packet_length, buffer); + + if (!AppendPacketHeader(header, &writer, nullptr)) { QUIC_BUG << "AppendPacketHeader failed"; return 0; } @@ -1133,7 +1251,8 @@ char* buffer, size_t packet_length, QuicPathFrameBuffer* payload, - QuicRandom* randomizer) { + QuicRandom* randomizer, + EncryptionLevel level) { if (version_.transport_version != QUIC_VERSION_99) { QUIC_BUG << "Attempt to build a PATH_CHALLENGE Connectivity Probing " "packet and not doing IETF QUIC"; @@ -1152,7 +1271,7 @@ QuicPaddingFrame padding_frame; frames.push_back(QuicFrame(padding_frame)); - return BuildIetfDataPacket(header, frames, buffer, packet_length); + return BuildDataPacket(header, frames, buffer, packet_length, level); } size_t QuicFramer::BuildPathResponsePacket( @@ -1160,7 +1279,8 @@ char* buffer, size_t packet_length, const QuicDeque<QuicPathFrameBuffer>& payloads, - const bool is_padded) { + const bool is_padded, + EncryptionLevel level) { if (payloads.empty()) { QUIC_BUG << "Attempt to generate connectivity response with no request payloads"; @@ -1192,7 +1312,7 @@ frames.push_back(QuicFrame(padding_frame)); } - return BuildIetfDataPacket(header, frames, buffer, packet_length); + return BuildDataPacket(header, frames, buffer, packet_length, level); } // static @@ -1221,7 +1341,7 @@ std::unique_ptr<char[]> buffer(new char[len]); // Endianness is not a concern here, as writer is not going to write integers // or floating numbers. - QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(len, buffer.get()); uint8_t flags = static_cast<uint8_t>(PACKET_PUBLIC_FLAGS_RST | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID); @@ -1231,7 +1351,7 @@ return nullptr; } - if (!writer.WriteConnectionId(packet.connection_id, Perspective::IS_SERVER)) { + if (!writer.WriteConnectionId(packet.connection_id)) { return nullptr; } @@ -1255,7 +1375,7 @@ size_t len = kPacketHeaderTypeSize + random_bytes_length + sizeof(stateless_reset_token); std::unique_ptr<char[]> buffer(new char[len]); - QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(len, buffer.get()); uint8_t type = 0; type |= FLAGS_FIXED_BIT; @@ -1306,7 +1426,7 @@ std::unique_ptr<char[]> buffer(new char[len]); // Endianness is not a concern here, version negotiation packet does not have // integers or floating numbers. - QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(len, buffer.get()); uint8_t flags = static_cast<uint8_t>( PACKET_PUBLIC_FLAGS_VERSION | PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID | @@ -1316,7 +1436,7 @@ return nullptr; } - if (!writer.WriteConnectionId(connection_id, Perspective::IS_SERVER)) { + if (!writer.WriteConnectionId(connection_id)) { return nullptr; } @@ -1342,7 +1462,7 @@ PACKET_8BYTE_CONNECTION_ID + (versions.size() + 1) * kQuicVersionSize; std::unique_ptr<char[]> buffer(new char[len]); - QuicDataWriter writer(len, buffer.get(), NETWORK_BYTE_ORDER); + QuicDataWriter writer(len, buffer.get()); // TODO(fayang): Randomly select a value for the type. uint8_t type = static_cast<uint8_t>(FLAGS_LONG_HEADER | VERSION_NEGOTIATION); @@ -1356,8 +1476,7 @@ if (!AppendIetfConnectionId(true, EmptyQuicConnectionId(), PACKET_0BYTE_CONNECTION_ID, connection_id, - PACKET_8BYTE_CONNECTION_ID, &writer, - Perspective::IS_SERVER)) { + PACKET_8BYTE_CONNECTION_ID, &writer)) { return nullptr; } @@ -1373,7 +1492,7 @@ } bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) { - QuicDataReader reader(packet.data(), packet.length(), endianness()); + QuicDataReader reader(packet.data(), packet.length()); bool last_packet_is_ietf_quic = false; if (infer_packet_header_type_from_version_) { @@ -1384,7 +1503,6 @@ } if (last_packet_is_ietf_quic) { QUIC_DVLOG(1) << ENDPOINT << "Processing IETF QUIC packet."; - reader.set_endianness(NETWORK_BYTE_ORDER); } visitor_->OnPacket(); @@ -1397,7 +1515,6 @@ DCHECK_NE("", detailed_error_); return RaiseError(QUIC_INVALID_PACKET_HEADER); } - last_header_form_ = header.form; if (!visitor_->OnUnauthenticatedPublicHeader(header)) { // The visitor suppresses further processing of the packet. @@ -1411,9 +1528,6 @@ } } - // framer's version may change, reset reader's endianness. - reader.set_endianness(endianness()); - bool rv; if (IsVersionNegotiation(header, last_packet_is_ietf_quic)) { QUIC_DVLOG(1) << ENDPOINT << "Received version negotiation packet"; @@ -1467,6 +1581,119 @@ return true; } +bool QuicFramer::MaybeProcessIetfInitialRetryToken( + QuicDataReader* encrypted_reader, + QuicPacketHeader* header) { + if (!QuicVersionHasLongHeaderLengths(header->version.transport_version) || + header->form != IETF_QUIC_LONG_HEADER_PACKET || + header->long_packet_type != INITIAL) { + return true; + } + uint64_t retry_token_length = 0; + header->retry_token_length_length = encrypted_reader->PeekVarInt62Length(); + if (!encrypted_reader->ReadVarInt62(&retry_token_length)) { + set_detailed_error("Unable to read INITIAL retry token length."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + header->retry_token = encrypted_reader->PeekRemainingPayload(); + // Safety check to avoid spending ressources if malformed. + // At this point header->retry_token contains the rest of the packet + // so its length() is the amount of data remaining in the packet. + if (retry_token_length > header->retry_token.length()) { + set_detailed_error("INITIAL token length longer than packet."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + // Resize retry_token to make it only contain the retry token. + header->retry_token.remove_suffix(header->retry_token.length() - + retry_token_length); + // Advance encrypted_reader by retry_token_length. + uint8_t wasted_byte; + for (uint64_t i = 0; i < retry_token_length; ++i) { + if (!encrypted_reader->ReadUInt8(&wasted_byte)) { + set_detailed_error("Unable to read INITIAL retry token."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + } + return true; +} + +// Seeks the current packet to check for a coalesced packet at the end. +// If the IETF length field only spans part of the outer packet, +// then there is a coalesced packet after this one. +void QuicFramer::MaybeProcessCoalescedPacket( + const QuicDataReader& encrypted_reader, + uint64_t remaining_bytes_length, + const QuicPacketHeader& header) { + if (header.remaining_packet_length >= remaining_bytes_length) { + // There is no coalesced packet. + return; + } + + QuicStringPiece remaining_data = encrypted_reader.PeekRemainingPayload(); + DCHECK_EQ(remaining_data.length(), remaining_bytes_length); + + const char* coalesced_data = + remaining_data.data() + header.remaining_packet_length; + uint64_t coalesced_data_length = + remaining_bytes_length - header.remaining_packet_length; + QuicDataReader coalesced_reader(coalesced_data, coalesced_data_length); + + QuicPacketHeader coalesced_header; + if (!ProcessIetfPacketHeader(&coalesced_reader, &coalesced_header)) { + QUIC_PEER_BUG << ENDPOINT + << "Failed to parse received coalesced header of length " + << coalesced_data_length << ": " + << QuicTextUtils::HexEncode(coalesced_data, + coalesced_data_length) + << " previous header was " << header; + return; + } + + if (coalesced_header.destination_connection_id != + header.destination_connection_id || + (coalesced_header.form != IETF_QUIC_SHORT_HEADER_PACKET && + coalesced_header.version != header.version)) { + QUIC_PEER_BUG << ENDPOINT << "Received mismatched coalesced header " + << coalesced_header << " previous header was " << header; + return; + } + + QuicEncryptedPacket coalesced_packet(coalesced_data, coalesced_data_length, + /*owns_buffer=*/false); + visitor_->OnCoalescedPacket(coalesced_packet); +} + +bool QuicFramer::MaybeProcessIetfLength(QuicDataReader* encrypted_reader, + QuicPacketHeader* header) { + if (!QuicVersionHasLongHeaderLengths(header->version.transport_version) || + header->form != IETF_QUIC_LONG_HEADER_PACKET || + (header->long_packet_type != INITIAL && + header->long_packet_type != HANDSHAKE && + header->long_packet_type != ZERO_RTT_PROTECTED)) { + return true; + } + header->length_length = encrypted_reader->PeekVarInt62Length(); + if (!encrypted_reader->ReadVarInt62(&header->remaining_packet_length)) { + set_detailed_error("Unable to read long header payload length."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + uint64_t remaining_bytes_length = encrypted_reader->BytesRemaining(); + if (header->remaining_packet_length > remaining_bytes_length) { + set_detailed_error("Long header payload length longer than packet."); + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + + MaybeProcessCoalescedPacket(*encrypted_reader, remaining_bytes_length, + *header); + + if (!encrypted_reader->TruncateRemaining(header->remaining_packet_length)) { + set_detailed_error("Length TruncateRemaining failed."); + QUIC_BUG << "Length TruncateRemaining failed."; + return RaiseError(QUIC_INVALID_PACKET_HEADER); + } + return true; +} + bool QuicFramer::ProcessIetfDataPacket(QuicDataReader* encrypted_reader, QuicPacketHeader* header, const QuicEncryptedPacket& packet, @@ -1474,6 +1701,10 @@ size_t buffer_length) { DCHECK_NE(GOOGLE_QUIC_PACKET, header->form); DCHECK(!header->has_possible_stateless_reset_token); + header->retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + header->retry_token = QuicStringPiece(); + header->length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + header->remaining_packet_length = 0; if (header->form == IETF_QUIC_SHORT_HEADER_PACKET && perspective_ == Perspective::IS_CLIENT) { // Peek possible stateless reset token. Will only be used on decryption @@ -1488,6 +1719,14 @@ } } + if (!MaybeProcessIetfInitialRetryToken(encrypted_reader, header)) { + return false; + } + + if (!MaybeProcessIetfLength(encrypted_reader, header)) { + return false; + } + if (header->form == IETF_QUIC_SHORT_HEADER_PACKET || header->long_packet_type != VERSION_NEGOTIATION) { // Process packet number. @@ -1518,7 +1757,8 @@ // using QUIC crypto. if (header->form == IETF_QUIC_LONG_HEADER_PACKET && header->long_packet_type == ZERO_RTT_PROTECTED && - perspective_ == Perspective::IS_CLIENT) { + perspective_ == Perspective::IS_CLIENT && + version_.handshake_protocol == PROTOCOL_QUIC_CRYPTO) { if (!encrypted_reader->ReadBytes( reinterpret_cast<uint8_t*>(last_nonce_.data()), last_nonce_.size())) { @@ -1537,8 +1777,17 @@ return false; } + QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload(); + QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket( + version_.transport_version, packet, + header->destination_connection_id_length, + header->source_connection_id_length, header->version_flag, + header->nonce != nullptr, header->packet_number_length, + header->retry_token_length_length, header->retry_token.length(), + header->length_length); + size_t decrypted_length = 0; - if (!DecryptPayload(encrypted_reader, *header, packet, decrypted_buffer, + if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer, buffer_length, &decrypted_length)) { if (IsIetfStatelessResetPacket(*header)) { // This is a stateless reset packet. @@ -1550,7 +1799,7 @@ set_detailed_error("Unable to decrypt payload."); return RaiseError(QUIC_DECRYPTION_FAILURE); } - QuicDataReader reader(decrypted_buffer, decrypted_length, endianness()); + QuicDataReader reader(decrypted_buffer, decrypted_length); // Update the largest packet number after we have decrypted the packet // so we are confident is not attacker controlled. @@ -1609,14 +1858,23 @@ return false; } + QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload(); + QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket( + version_.transport_version, packet, + header->destination_connection_id_length, + header->source_connection_id_length, header->version_flag, + header->nonce != nullptr, header->packet_number_length, + header->retry_token_length_length, header->retry_token.length(), + header->length_length); + size_t decrypted_length = 0; - if (!DecryptPayload(encrypted_reader, *header, packet, decrypted_buffer, + if (!DecryptPayload(encrypted, associated_data, *header, decrypted_buffer, buffer_length, &decrypted_length)) { set_detailed_error("Unable to decrypt payload."); return RaiseError(QUIC_DECRYPTION_FAILURE); } - QuicDataReader reader(decrypted_buffer, decrypted_length, endianness()); + QuicDataReader reader(decrypted_buffer, decrypted_length); // Update the largest packet number after we have decrypted the packet // so we are confident is not attacker controlled. @@ -1704,9 +1962,10 @@ } bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, - QuicDataWriter* writer) { + QuicDataWriter* writer, + size_t* length_field_offset) { if (transport_version() > QUIC_VERSION_43) { - return AppendIetfPacketHeader(header, writer); + return AppendIetfPacketHeader(header, writer, length_field_offset); } QUIC_DVLOG(1) << ENDPOINT << "Appending header: " << header; uint8_t public_flags = 0; @@ -1745,8 +2004,7 @@ public_flags |= PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID_OLD; } if (!writer->WriteUInt8(public_flags) || - !writer->WriteConnectionId(header.destination_connection_id, - perspective_)) { + !writer->WriteConnectionId(header.destination_connection_id)) { return false; } break; @@ -1781,7 +2039,7 @@ bool QuicFramer::AppendIetfHeaderTypeByte(const QuicPacketHeader& header, QuicDataWriter* writer) { uint8_t type = 0; - if (transport_version() > QUIC_VERSION_46) { + if (transport_version() > QUIC_VERSION_44) { if (header.version_flag) { type = static_cast<uint8_t>( FLAGS_LONG_HEADER | FLAGS_FIXED_BIT | @@ -1814,7 +2072,8 @@ } bool QuicFramer::AppendIetfPacketHeader(const QuicPacketHeader& header, - QuicDataWriter* writer) { + QuicDataWriter* writer, + size_t* length_field_offset) { QUIC_DVLOG(1) << ENDPOINT << "Appending IETF header: " << header; QUIC_BUG_IF(!QuicUtils::IsConnectionIdValidForVersion( header.destination_connection_id, transport_version())) @@ -1838,11 +2097,34 @@ if (!AppendIetfConnectionId( header.version_flag, header.destination_connection_id, header.destination_connection_id_length, header.source_connection_id, - header.source_connection_id_length, writer, perspective_)) { + header.source_connection_id_length, writer)) { return false; } last_serialized_connection_id_ = header.destination_connection_id; + if (QuicVersionHasLongHeaderLengths(transport_version()) && + header.version_flag) { + if (header.long_packet_type == INITIAL) { + // Write retry token length. + if (!writer->WriteVarInt62(header.retry_token.length(), + header.retry_token_length_length)) { + return false; + } + // Write retry token. + if (!header.retry_token.empty() && + !writer->WriteStringPiece(header.retry_token)) { + return false; + } + } + if (length_field_offset != nullptr) { + *length_field_offset = writer->length(); + } + // Add fake length to reserve two bytes to add length in later. + writer->WriteVarInt62(256); + } else if (length_field_offset != nullptr) { + *length_field_offset = 0; + } + // Append packet number. if (!AppendPacketNumber(header.packet_number_length, header.packet_number, writer)) { @@ -1943,8 +2225,7 @@ switch (public_flags & PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID) { case PACKET_PUBLIC_FLAGS_8BYTE_CONNECTION_ID: if (!reader->ReadConnectionId(&header->destination_connection_id, - kQuicDefaultConnectionIdLength, - perspective_)) { + kQuicDefaultConnectionIdLength)) { set_detailed_error("Unable to read ConnectionId."); return false; } @@ -2133,7 +2414,7 @@ } else { header->version = ParseQuicVersionLabel(version_label); if (header->version.transport_version != QUIC_VERSION_UNSUPPORTED) { - if (header->version.transport_version > QUIC_VERSION_46 && + if (header->version.transport_version > QUIC_VERSION_44 && !(type & FLAGS_FIXED_BIT)) { set_detailed_error("Fixed bit is 0 in long header."); return false; @@ -2170,7 +2451,7 @@ header->destination_connection_id = last_serialized_connection_id_; } if (infer_packet_header_type_from_version_ && - transport_version() > QUIC_VERSION_46 && !(type & FLAGS_FIXED_BIT)) { + transport_version() > QUIC_VERSION_44 && !(type & FLAGS_FIXED_BIT)) { set_detailed_error("Fixed bit is 0 in short header."); return false; } @@ -2218,14 +2499,14 @@ // Read connection ID. if (header->destination_connection_id_length == PACKET_8BYTE_CONNECTION_ID && !reader->ReadConnectionId(&header->destination_connection_id, - kQuicDefaultConnectionIdLength, perspective_)) { + kQuicDefaultConnectionIdLength)) { set_detailed_error("Unable to read Destination ConnectionId."); return false; } if (header->source_connection_id_length == PACKET_8BYTE_CONNECTION_ID && !reader->ReadConnectionId(&header->source_connection_id, - kQuicDefaultConnectionIdLength, perspective_)) { + kQuicDefaultConnectionIdLength)) { set_detailed_error("Unable to read Source ConnectionId."); return false; } @@ -2428,6 +2709,22 @@ } break; } + case CRYPTO_FRAME: { + if (version_.transport_version < QUIC_VERSION_47) { + set_detailed_error("Illegal frame type."); + return RaiseError(QUIC_INVALID_FRAME_DATA); + } + QuicCryptoFrame frame; + if (!ProcessCryptoFrame(reader, &frame)) { + return RaiseError(QUIC_INVALID_FRAME_DATA); + } + if (!visitor_->OnCryptoFrame(frame)) { + QUIC_DVLOG(1) << "Visitor asked to stop further processing."; + // Returning true since there was no parsing error. + return true; + } + break; + } default: set_detailed_error("Illegal frame type."); @@ -2556,9 +2853,10 @@ } break; } - case IETF_MAX_STREAM_ID: { + case IETF_MAX_STREAMS_BIDIRECTIONAL: + case IETF_MAX_STREAMS_UNIDIRECTIONAL: { QuicMaxStreamIdFrame frame; - if (!ProcessMaxStreamIdFrame(reader, &frame)) { + if (!ProcessMaxStreamsFrame(reader, &frame, frame_type)) { return RaiseError(QUIC_MAX_STREAM_ID_DATA); } QUIC_CODE_COUNT_N(max_stream_id_received, 1, 2); @@ -2603,9 +2901,10 @@ } break; } - case IETF_STREAM_ID_BLOCKED: { + case IETF_STREAMS_BLOCKED_UNIDIRECTIONAL: + case IETF_STREAMS_BLOCKED_BIDIRECTIONAL: { QuicStreamIdBlockedFrame frame; - if (!ProcessStreamIdBlockedFrame(reader, &frame)) { + if (!ProcessStreamsBlockedFrame(reader, &frame, frame_type)) { return RaiseError(QUIC_STREAM_ID_BLOCKED_DATA); } QUIC_CODE_COUNT_N(stream_id_blocked_received, 1, 2); @@ -2927,9 +3226,7 @@ return false; } - if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) && - largest_acked < first_sending_packet_number_.ToUint64()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 1, 3); + if (largest_acked < first_sending_packet_number_.ToUint64()) { // Connection always sends packet starting from kFirstSendingPacketNumber > // 0, peer has observed an unsent packet. set_detailed_error("Largest acked is 0."); @@ -2966,25 +3263,12 @@ } if (first_block_length == 0) { - // For non-empty ACKs, the first block length must be non-zero. - // TODO(fayang): remove this if and return false directly when deprecating - // gfe2_reloadable_flag_quic_disallow_peer_ack_0. - if (largest_acked != 0 || num_ack_blocks != 0) { - set_detailed_error( - QuicStrCat("First block length is zero but ACK is " - "not empty. largest acked is ", - largest_acked, ", num ack blocks is ", - QuicTextUtils::Uint64ToString(num_ack_blocks), ".") - .c_str()); - return false; - } - DCHECK(!GetQuicReloadableFlag(quic_disallow_peer_ack_0)); + set_detailed_error("First block length is zero."); + return false; } bool first_ack_block_underflow = first_block_length > largest_acked + 1; - if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) && - first_block_length + first_sending_packet_number_.ToUint64() > - largest_acked + 1) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 2, 3); + if (first_block_length + first_sending_packet_number_.ToUint64() > + largest_acked + 1) { first_ack_block_underflow = true; } if (first_ack_block_underflow) { @@ -3018,10 +3302,8 @@ return false; } bool ack_block_underflow = first_received < gap + current_block_length; - if (GetQuicReloadableFlag(quic_disallow_peer_ack_0) && - first_received < gap + current_block_length + + if (first_received < gap + current_block_length + first_sending_packet_number_.ToUint64()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_disallow_peer_ack_0, 3, 3); ack_block_underflow = true; } if (ack_block_underflow) { @@ -3074,6 +3356,14 @@ return false; } + if (largest_acked.ToUint64() <= delta_from_largest_observed) { + set_detailed_error(QuicStrCat("delta_from_largest_observed too high: ", + delta_from_largest_observed, + ", largest_acked: ", largest_acked.ToUint64()) + .c_str()); + return false; + } + // Time delta from the framer creation. uint32_t time_delta_us; if (!reader->ReadUInt32(&time_delta_us)) { @@ -3093,6 +3383,14 @@ set_detailed_error("Unable to read sequence delta in received packets."); return false; } + if (largest_acked.ToUint64() <= delta_from_largest_observed) { + set_detailed_error( + QuicStrCat("delta_from_largest_observed too high: ", + delta_from_largest_observed, + ", largest_acked: ", largest_acked.ToUint64()) + .c_str()); + return false; + } seq_num = largest_acked - delta_from_largest_observed; // Time delta from the previous timestamp. @@ -3410,11 +3708,6 @@ void QuicFramer::ProcessPaddingFrame(QuicDataReader* reader, QuicPaddingFrame* frame) { - if (version_.transport_version == QUIC_VERSION_35) { - frame->num_padding_bytes = reader->BytesRemaining() + 1; - reader->ReadRemainingPayload(); - return; - } // Type byte has been read. frame->num_padding_bytes = 1; uint8_t next_byte; @@ -3429,7 +3722,9 @@ bool no_message_length, QuicMessageFrame* frame) { if (no_message_length) { - frame->message_data = QuicString(reader->ReadRemainingPayload()); + QuicStringPiece remaining(reader->ReadRemainingPayload()); + frame->data = remaining.data(); + frame->message_length = remaining.length(); return true; } @@ -3445,7 +3740,8 @@ return false; } - frame->message_data = QuicString(message_piece); + frame->data = message_piece.data(); + frame->message_length = message_length; return true; } @@ -3458,14 +3754,18 @@ QuicConnectionIdLength source_connection_id_length, bool includes_version, bool includes_diversification_nonce, - QuicPacketNumberLength packet_number_length) { + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + uint64_t retry_token_length, + QuicVariableLengthIntegerLength length_length) { // TODO(ianswett): This is identical to QuicData::AssociatedData. return QuicStringPiece( encrypted.data(), GetStartOfEncryptedData(version, destination_connection_id_length, source_connection_id_length, includes_version, includes_diversification_nonce, - packet_number_length)); + packet_number_length, retry_token_length_length, + retry_token_length, length_length)); } void QuicFramer::SetDecrypter(EncryptionLevel level, @@ -3509,7 +3809,7 @@ DCHECK(packet_number.IsInitialized()); size_t output_length = 0; if (!encrypter_[level]->EncryptPacket( - version_.transport_version, packet_number.ToUint64(), + packet_number.ToUint64(), QuicStringPiece(buffer, ad_len), // Associated data QuicStringPiece(buffer + ad_len, total_len - ad_len), // Plaintext buffer + ad_len, // Destination buffer @@ -3538,7 +3838,7 @@ // Encrypt the plaintext into the buffer. size_t output_length = 0; if (!encrypter_[level]->EncryptPacket( - version_.transport_version, packet_number.ToUint64(), associated_data, + packet_number.ToUint64(), associated_data, packet.Plaintext(version_.transport_version), buffer + ad_len, &output_length, buffer_len - ad_len)) { RaiseError(QUIC_ENCRYPTION_FAILURE); @@ -3548,6 +3848,11 @@ return ad_len + output_length; } +size_t QuicFramer::GetCiphertextSize(EncryptionLevel level, + size_t plaintext_size) const { + return encrypter_[level]->GetCiphertextSize(plaintext_size); +} + size_t QuicFramer::GetMaxPlaintextSize(size_t ciphertext_size) { // In order to keep the code simple, we don't have the current encryption // level to hand. Both the NullEncrypter and AES-GCM have a tag length of 12. @@ -3565,24 +3870,17 @@ return min_plaintext_size; } -bool QuicFramer::DecryptPayload(QuicDataReader* encrypted_reader, +bool QuicFramer::DecryptPayload(QuicStringPiece encrypted, + QuicStringPiece associated_data, const QuicPacketHeader& header, - const QuicEncryptedPacket& packet, char* decrypted_buffer, size_t buffer_length, size_t* decrypted_length) { - QuicStringPiece encrypted = encrypted_reader->ReadRemainingPayload(); DCHECK(decrypter_ != nullptr); - QuicStringPiece associated_data = GetAssociatedDataFromEncryptedPacket( - version_.transport_version, packet, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); bool success = decrypter_->DecryptPacket( - version_.transport_version, header.packet_number.ToUint64(), - associated_data, encrypted, decrypted_buffer, decrypted_length, - buffer_length); + header.packet_number.ToUint64(), associated_data, encrypted, + decrypted_buffer, decrypted_length, buffer_length); if (success) { visitor_->OnDecryptedPacket(decrypter_level_); } else if (alternative_decrypter_ != nullptr) { @@ -3591,7 +3889,7 @@ alternative_decrypter_->SetDiversificationNonce(*header.nonce); } bool try_alternative_decryption = true; - if (alternative_decrypter_level_ == ENCRYPTION_INITIAL) { + if (alternative_decrypter_level_ == ENCRYPTION_ZERO_RTT) { if (perspective_ == Perspective::IS_CLIENT) { if (header.nonce == nullptr) { // Can not use INITIAL decryption without a diversification nonce. @@ -3604,9 +3902,8 @@ if (try_alternative_decryption) { success = alternative_decrypter_->DecryptPacket( - version_.transport_version, header.packet_number.ToUint64(), - associated_data, encrypted, decrypted_buffer, decrypted_length, - buffer_length); + header.packet_number.ToUint64(), associated_data, encrypted, + decrypted_buffer, decrypted_length, buffer_length); } if (success) { visitor_->OnDecryptedPacket(alternative_decrypter_level_); @@ -3793,7 +4090,7 @@ case MESSAGE_FRAME: return GetMessageFrameSize(version_.transport_version, last_frame_in_packet, - frame.message_frame->message_data.length()); + frame.message_frame->message_length); case PADDING_FRAME: DCHECK(false); return 0; @@ -3890,14 +4187,16 @@ case WINDOW_UPDATE_FRAME: // Depending on whether there is a stream ID or not, will be either a // MAX_STREAM_DATA frame or a MAX_DATA frame. - if (frame.window_update_frame->stream_id == 0) { + if (frame.window_update_frame->stream_id == + QuicUtils::GetInvalidStreamId(transport_version())) { type_byte = IETF_MAX_DATA; } else { type_byte = IETF_MAX_STREAM_DATA; } break; case BLOCKED_FRAME: - if (frame.blocked_frame->stream_id == 0) { + if (frame.blocked_frame->stream_id == + QuicUtils::GetInvalidStreamId(transport_version())) { type_byte = IETF_BLOCKED; } else { type_byte = IETF_STREAM_BLOCKED; @@ -3935,10 +4234,20 @@ type_byte = IETF_NEW_TOKEN; break; case MAX_STREAM_ID_FRAME: - type_byte = IETF_MAX_STREAM_ID; + if (QuicUtils::IsBidirectionalStreamId( + frame.max_stream_id_frame.max_stream_id)) { + type_byte = IETF_MAX_STREAMS_BIDIRECTIONAL; + } else { + type_byte = IETF_MAX_STREAMS_UNIDIRECTIONAL; + } break; case STREAM_ID_BLOCKED_FRAME: - type_byte = IETF_STREAM_ID_BLOCKED; + if (QuicUtils::IsBidirectionalStreamId( + frame.max_stream_id_frame.max_stream_id)) { + type_byte = IETF_STREAMS_BLOCKED_BIDIRECTIONAL; + } else { + type_byte = IETF_STREAMS_BLOCKED_UNIDIRECTIONAL; + } break; case PATH_RESPONSE_FRAME: type_byte = IETF_PATH_RESPONSE; @@ -4061,8 +4370,6 @@ return true; } -// TODO(dschinazi) b/120240679 - remove perspective once these flags are -// deprecated: quic_variable_length_connection_ids_(client|server). // static bool QuicFramer::AppendIetfConnectionId( bool version_flag, @@ -4070,8 +4377,7 @@ QuicConnectionIdLength destination_connection_id_length, QuicConnectionId source_connection_id, QuicConnectionIdLength source_connection_id_length, - QuicDataWriter* writer, - Perspective perspective) { + QuicDataWriter* writer) { if (version_flag) { // Append connection ID length byte. uint8_t dcil = GetConnectionIdLengthValue(destination_connection_id_length); @@ -4082,11 +4388,11 @@ } } if (destination_connection_id_length == PACKET_8BYTE_CONNECTION_ID && - !writer->WriteConnectionId(destination_connection_id, perspective)) { + !writer->WriteConnectionId(destination_connection_id)) { return false; } if (source_connection_id_length == PACKET_8BYTE_CONNECTION_ID && - !writer->WriteConnectionId(source_connection_id, perspective)) { + !writer->WriteConnectionId(source_connection_id)) { return false; } return true; @@ -4688,10 +4994,7 @@ bool QuicFramer::AppendBlockedFrame(const QuicBlockedFrame& frame, QuicDataWriter* writer) { if (version_.transport_version == QUIC_VERSION_99) { - // TODO(fkastenholz): This should be converted to use - // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value - // and not rely on 0. - if (frame.stream_id == 0) { + if (frame.stream_id == QuicUtils::GetInvalidStreamId(transport_version())) { return AppendIetfBlockedFrame(frame, writer); } return AppendStreamBlockedFrame(frame, writer); @@ -4705,11 +5008,6 @@ bool QuicFramer::AppendPaddingFrame(const QuicPaddingFrame& frame, QuicDataWriter* writer) { - if (version_.transport_version == QUIC_VERSION_35) { - writer->WritePadding(); - return true; - } - if (frame.num_padding_bytes == 0) { return false; } @@ -4730,12 +5028,15 @@ if (!writer->WriteUInt8(type_byte)) { return false; } - if (!last_frame_in_packet && - !writer->WriteVarInt62(frame.message_data.length())) { + if (!last_frame_in_packet && !writer->WriteVarInt62(frame.message_length)) { return false; } - return writer->WriteBytes(frame.message_data.data(), - frame.message_data.length()); + for (const auto& slice : frame.message_data) { + if (!writer->WriteBytes(slice.data(), slice.length())) { + return false; + } + } + return true; } bool QuicFramer::RaiseError(QuicErrorCode error) { @@ -4760,11 +5061,6 @@ return header.long_packet_type == VERSION_NEGOTIATION; } -Endianness QuicFramer::endianness() const { - return version_.transport_version != QUIC_VERSION_35 ? NETWORK_BYTE_ORDER - : HOST_BYTE_ORDER; -} - bool QuicFramer::StartsWithChlo(QuicStreamId id, QuicStreamOffset offset) const { if (data_producer_ == nullptr) { @@ -4772,7 +5068,7 @@ return false; } char buf[sizeof(kCHLO)]; - QuicDataWriter writer(sizeof(kCHLO), buf, endianness()); + QuicDataWriter writer(sizeof(kCHLO), buf); if (data_producer_->WriteStreamData(id, offset, sizeof(kCHLO), &writer) != WRITE_SUCCESS) { QUIC_BUG << "Failed to write data for stream " << id << " with offset " @@ -4784,10 +5080,6 @@ 0; } -PacketHeaderFormat QuicFramer::GetLastPacketFormat() const { - return last_header_form_; -} - bool QuicFramer::AppendIetfConnectionCloseFrame( const QuicConnectionCloseFrame& frame, QuicDataWriter* writer) { @@ -5003,7 +5295,7 @@ bool QuicFramer::ProcessMaxDataFrame(QuicDataReader* reader, QuicWindowUpdateFrame* frame) { - frame->stream_id = 0; + frame->stream_id = QuicUtils::GetInvalidStreamId(transport_version()); if (!reader->ReadVarInt62(&frame->byte_offset)) { set_detailed_error("Can not read MAX_DATA byte-offset"); return false; @@ -5038,22 +5330,47 @@ return true; } -bool QuicFramer::AppendMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame, - QuicDataWriter* writer) { - if (!writer->WriteVarInt62(frame.max_stream_id)) { - set_detailed_error("Can not write MAX_STREAM_ID stream id"); +bool QuicFramer::AppendMaxStreamsFrame(const QuicMaxStreamIdFrame& frame, + QuicDataWriter* writer) { + // Convert from the stream id on which the connection is blocked to a count + QuicStreamId stream_count = + StreamIdToCount(version_.transport_version, frame.max_stream_id); + + if (!writer->WriteVarInt62(stream_count)) { + set_detailed_error("Can not write MAX_STREAMS stream count"); return false; } return true; } -bool QuicFramer::ProcessMaxStreamIdFrame(QuicDataReader* reader, - QuicMaxStreamIdFrame* frame) { - if (!reader->ReadVarIntStreamId(&frame->max_stream_id)) { - set_detailed_error("Can not read MAX_STREAM_ID stream id."); +bool QuicFramer::ProcessMaxStreamsFrame(QuicDataReader* reader, + QuicMaxStreamIdFrame* frame, + uint64_t frame_type) { + QuicStreamId received_stream_count; + if (!reader->ReadVarIntStreamId(&received_stream_count)) { + set_detailed_error("Can not read MAX_STREAMS stream count."); return false; } - return true; + // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED + // frame is implemented and passed up to the stream ID manager. + if (received_stream_count == 0) { + set_detailed_error("MAX_STREAMS stream count of 0 not supported."); + return false; + } + // Note that this code assumes that the only possible error that + // StreamCountToId can detect is that the stream count is too big or is 0. + // Too big is prevented by passing in the minimum of the received count + // and the maximum supported count, ensuring that the stream ID is + // pegged at the maximum allowed ID. + // count==0 is handled above, so that detailed_error_ may be set + // properly. + return StreamCountToId( + std::min( + received_stream_count, + GetMaxStreamCount((frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL), + perspective_)), + /*unidirectional=*/(frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL), + perspective_, version_.transport_version, &frame->max_stream_id); } bool QuicFramer::AppendIetfBlockedFrame(const QuicBlockedFrame& frame, @@ -5068,10 +5385,7 @@ bool QuicFramer::ProcessIetfBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame) { // Indicates that it is a BLOCKED frame (as opposed to STREAM_BLOCKED). - // TODO(fkastenholz): This should be converted to use - // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value - // and not rely on 0. - frame->stream_id = 0; + frame->stream_id = QuicUtils::GetInvalidStreamId(transport_version()); if (!reader->ReadVarInt62(&frame->offset)) { set_detailed_error("Can not read blocked offset."); return false; @@ -5105,23 +5419,58 @@ return true; } -bool QuicFramer::AppendStreamIdBlockedFrame( +bool QuicFramer::AppendStreamsBlockedFrame( const QuicStreamIdBlockedFrame& frame, QuicDataWriter* writer) { - if (!writer->WriteVarInt62(frame.stream_id)) { - set_detailed_error("Can not write STREAM_ID_BLOCKED stream id"); + // Convert from the stream id on which the connection is blocked to a count + QuicStreamId stream_count = + StreamIdToCount(version_.transport_version, frame.stream_id); + + if (!writer->WriteVarInt62(stream_count)) { + set_detailed_error("Can not write STREAMS_BLOCKED stream count"); return false; } return true; } -bool QuicFramer::ProcessStreamIdBlockedFrame(QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame) { - if (!reader->ReadVarIntStreamId(&frame->stream_id)) { - set_detailed_error("Can not read STREAM_ID_BLOCKED stream id."); +bool QuicFramer::ProcessStreamsBlockedFrame(QuicDataReader* reader, + QuicStreamIdBlockedFrame* frame, + uint64_t frame_type) { + QuicStreamId received_stream_count; + if (!reader->ReadVarIntStreamId(&received_stream_count)) { + set_detailed_error("Can not read STREAMS_BLOCKED stream id."); return false; } - return true; + // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED + // frame is implemented and passed up to the stream ID manager. + if (received_stream_count == 0) { + set_detailed_error("STREAMS_BLOCKED stream count 0 not supported."); + return false; + } + // TODO(fkastenholz): handle properly when the STREAMS_BLOCKED + // frame is implemented and passed up to the stream ID manager. + if (received_stream_count > + GetMaxStreamCount((frame_type == IETF_MAX_STREAMS_UNIDIRECTIONAL), + ((perspective_ == Perspective::IS_CLIENT) + ? Perspective::IS_SERVER + : Perspective::IS_CLIENT))) { + // If stream count is such that the resulting stream ID would exceed our + // implementation limit, generate an error. + set_detailed_error( + "STREAMS_BLOCKED stream count exceeds implementation limit."); + return false; + } + // Convert the stream count to an ID that can be used. + // The STREAMS_BLOCKED frame is a request for more streams + // that the peer will initiate. If this node is a client, it + // means that the peer is a server, and wants server-initiated + // stream IDs. + return StreamCountToId( + received_stream_count, + /*unidirectional=*/(frame_type == IETF_STREAMS_BLOCKED_UNIDIRECTIONAL), + (perspective_ == Perspective::IS_CLIENT) ? Perspective::IS_SERVER + : Perspective::IS_CLIENT, + version_.transport_version, &frame->stream_id); } bool QuicFramer::AppendNewConnectionIdFrame( @@ -5136,7 +5485,7 @@ "Can not write New Connection ID frame connection ID Length"); return false; } - if (!writer->WriteConnectionId(frame.connection_id, perspective_)) { + if (!writer->WriteConnectionId(frame.connection_id)) { set_detailed_error("Can not write New Connection ID frame connection ID"); return false; } @@ -5171,8 +5520,7 @@ return false; } - if (!reader->ReadConnectionId(&frame->connection_id, connection_id_length, - perspective_)) { + if (!reader->ReadConnectionId(&frame->connection_id, connection_id_length)) { set_detailed_error("Unable to read new connection ID frame connection id."); return false; }
diff --git a/quic/core/quic_framer.h b/quic/core/quic_framer.h index 46280c5..76d86b8 100644 --- a/quic/core/quic_framer.h +++ b/quic/core/quic_framer.h
@@ -112,6 +112,16 @@ // If OnPacketHeader returns false, framing for this packet will cease. virtual bool OnPacketHeader(const QuicPacketHeader& header) = 0; + // Called when the packet being processed contains multiple IETF QUIC packets, + // which is due to there being more data after what is covered by the length + // field. |packet| contains the remaining data which can be processed. + // Note that this is called when the framer parses the length field, before + // it attempts to decrypt the first payload. It is the visitor's + // responsibility to buffer the packet and call ProcessPacket on it + // after the framer is done parsing the current payload. |packet| does not + // own its internal buffer, the visitor should make a copy of it. + virtual void OnCoalescedPacket(const QuicEncryptedPacket& packet) = 0; + // Called when a StreamFrame has been parsed. virtual bool OnStreamFrame(const QuicStreamFrame& frame) = 0; @@ -304,11 +314,11 @@ // be generated and calculates the appropriate size. static size_t GetWindowUpdateFrameSize(QuicTransportVersion version, const QuicWindowUpdateFrame& frame); - // Size in bytes of all MaxStreamId frame fields. - static size_t GetMaxStreamIdFrameSize(QuicTransportVersion version, - const QuicMaxStreamIdFrame& frame); - // Size in bytes of all StreamIdBlocked frame fields. - static size_t GetStreamIdBlockedFrameSize( + // Size in bytes of all MaxStreams frame fields. + static size_t GetMaxStreamsFrameSize(QuicTransportVersion version, + const QuicMaxStreamIdFrame& frame); + // Size in bytes of all StreamsBlocked frame fields. + static size_t GetStreamsBlockedFrameSize( QuicTransportVersion version, const QuicStreamIdBlockedFrame& frame); // Size in bytes of all Blocked frame fields. @@ -362,7 +372,10 @@ QuicConnectionIdLength source_connection_id_length, bool includes_version, bool includes_diversification_nonce, - QuicPacketNumberLength packet_number_length); + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + uint64_t retry_token_length, + QuicVariableLengthIntegerLength length_length); // Serializes a packet containing |frames| into |buffer|. // Returns the length of the packet, which must not be longer than @@ -370,19 +383,22 @@ size_t BuildDataPacket(const QuicPacketHeader& header, const QuicFrames& frames, char* buffer, - size_t packet_length); + size_t packet_length, + EncryptionLevel level); // Serializes a probing packet, which is a padded PING packet. Returns the // length of the packet. Returns 0 if it fails to serialize. size_t BuildConnectivityProbingPacket(const QuicPacketHeader& header, char* buffer, - size_t packet_length); + size_t packet_length, + EncryptionLevel level); - // Serializes an IETF probing packet, which is a padded PING packet. - // Returns the length of the packet. Returns 0 if it fails to serialize. - size_t BuildIetfConnectivityProbingPacket(const QuicPacketHeader& header, - char* buffer, - size_t packet_length); + // Serializes a probing packet, which is a padded PING packet. Returns the + // length of the packet. Returns 0 if it fails to serialize. + size_t BuildConnectivityProbingPacketNew(const QuicPacketHeader& header, + char* buffer, + size_t packet_length, + EncryptionLevel level); // Serialize a probing packet that uses IETF QUIC's PATH CHALLENGE frame. Also // fills the packet with padding. @@ -390,7 +406,8 @@ char* buffer, size_t packet_length, QuicPathFrameBuffer* payload, - QuicRandom* randomizer); + QuicRandom* randomizer, + EncryptionLevel level); // Serialize a probing response packet that uses IETF QUIC's PATH RESPONSE // frame. Also fills the packet with padding if |is_padded| is @@ -400,7 +417,8 @@ char* buffer, size_t packet_length, const QuicDeque<QuicPathFrameBuffer>& payloads, - const bool is_padded); + const bool is_padded, + EncryptionLevel level); // Returns a new public reset packet. static std::unique_ptr<QuicEncryptedPacket> BuildPublicResetPacket( @@ -426,17 +444,24 @@ // packet will be set -- but it will be set from version_ not // header.versions. bool AppendPacketHeader(const QuicPacketHeader& header, - QuicDataWriter* writer); + QuicDataWriter* writer, + size_t* length_field_offset); bool AppendIetfHeaderTypeByte(const QuicPacketHeader& header, QuicDataWriter* writer); bool AppendIetfPacketHeader(const QuicPacketHeader& header, - QuicDataWriter* writer); + QuicDataWriter* writer, + size_t* length_field_offset); + bool WriteIetfLongHeaderLength(const QuicPacketHeader& header, + QuicDataWriter* writer, + size_t length_field_offset, + EncryptionLevel level); bool AppendTypeByte(const QuicFrame& frame, bool last_frame_in_packet, QuicDataWriter* writer); bool AppendIetfTypeByte(const QuicFrame& frame, bool last_frame_in_packet, QuicDataWriter* writer); + size_t AppendIetfFrames(const QuicFrames& frames, QuicDataWriter* writer); bool AppendStreamFrame(const QuicStreamFrame& frame, bool last_frame_in_packet, QuicDataWriter* writer); @@ -485,6 +510,10 @@ char* buffer, size_t buffer_len); + // Returns the length of the ciphertext that would be generated by encrypting + // to plaintext of size |plaintext_size| at the given level. + size_t GetCiphertextSize(EncryptionLevel level, size_t plaintext_size) const; + // Returns the maximum length of plaintext that can be encrypted // to ciphertext no larger than |ciphertext_size|. size_t GetMaxPlaintextSize(size_t ciphertext_size); @@ -507,28 +536,15 @@ // Returns true if data with |offset| of stream |id| starts with 'CHLO'. bool StartsWithChlo(QuicStreamId id, QuicStreamOffset offset) const; - // Returns byte order to read/write integers and floating numbers. - Endianness endianness() const; - // Returns true if |header| is considered as an stateless reset packet. bool IsIetfStatelessResetPacket(const QuicPacketHeader& header) const; - // Returns header wire format of last received packet. - // Please do not use this method. - // TODO(fayang): Remove last_header_form_ when deprecating - // quic_fix_last_packet_is_ietf_quic flag. - PacketHeaderFormat GetLastPacketFormat() const; - void set_validate_flags(bool value) { validate_flags_ = value; } Perspective perspective() const { return perspective_; } QuicVersionLabel last_version_label() const { return last_version_label_; } - void set_last_packet_form(PacketHeaderFormat form) { - last_header_form_ = form; - } - void set_data_producer(QuicStreamFrameDataProducer* data_producer) { data_producer_ = data_producer; } @@ -566,12 +582,6 @@ size_t num_ack_blocks; }; - // The same as BuildDataPacket, but it only builds IETF-format packets. - size_t BuildIetfDataPacket(const QuicPacketHeader& header, - const QuicFrames& frames, - char* buffer, - size_t packet_length); - bool ProcessDataPacket(QuicDataReader* reader, QuicPacketHeader* header, const QuicEncryptedPacket& packet, @@ -590,6 +600,16 @@ bool ProcessVersionNegotiationPacket(QuicDataReader* reader, const QuicPacketHeader& header); + bool MaybeProcessIetfInitialRetryToken(QuicDataReader* encrypted_reader, + QuicPacketHeader* header); + + void MaybeProcessCoalescedPacket(const QuicDataReader& encrypted_reader, + uint64_t remaining_bytes_length, + const QuicPacketHeader& header); + + bool MaybeProcessIetfLength(QuicDataReader* encrypted_reader, + QuicPacketHeader* header); + bool ProcessPublicHeader(QuicDataReader* reader, bool last_packet_is_ietf_quic, QuicPacketHeader* header); @@ -640,9 +660,9 @@ bool no_message_length, QuicMessageFrame* frame); - bool DecryptPayload(QuicDataReader* encrypted_reader, + bool DecryptPayload(QuicStringPiece encrypted, + QuicStringPiece associated_data, const QuicPacketHeader& header, - const QuicEncryptedPacket& packet, char* decrypted_buffer, size_t buffer_length, size_t* decrypted_length); @@ -703,8 +723,7 @@ QuicConnectionIdLength destination_connection_id_length, QuicConnectionId source_connection_id, QuicConnectionIdLength source_connection_id_length, - QuicDataWriter* writer, - Perspective perspective); + QuicDataWriter* writer); // The Append* methods attempt to write the provided header or frame using the // |writer|, and return true if successful. @@ -789,10 +808,11 @@ bool ProcessMaxStreamDataFrame(QuicDataReader* reader, QuicWindowUpdateFrame* frame); - bool AppendMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame, - QuicDataWriter* writer); - bool ProcessMaxStreamIdFrame(QuicDataReader* reader, - QuicMaxStreamIdFrame* frame); + bool AppendMaxStreamsFrame(const QuicMaxStreamIdFrame& frame, + QuicDataWriter* writer); + bool ProcessMaxStreamsFrame(QuicDataReader* reader, + QuicMaxStreamIdFrame* frame, + uint64_t frame_type); bool AppendIetfBlockedFrame(const QuicBlockedFrame& frame, QuicDataWriter* writer); @@ -803,10 +823,12 @@ bool ProcessStreamBlockedFrame(QuicDataReader* reader, QuicBlockedFrame* frame); - bool AppendStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame, - QuicDataWriter* writer); - bool ProcessStreamIdBlockedFrame(QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame); + bool AppendStreamsBlockedFrame(const QuicStreamIdBlockedFrame& frame, + QuicDataWriter* writer); + bool ProcessStreamsBlockedFrame(QuicDataReader* reader, + QuicStreamIdBlockedFrame* frame, + uint64_t frame_type); + bool AppendNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame, QuicDataWriter* writer); bool ProcessNewConnectionIdFrame(QuicDataReader* reader, @@ -845,9 +867,6 @@ QuicConnectionId last_serialized_connection_id_; // The last QUIC version label received. QuicVersionLabel last_version_label_; - // Format of last received packet header, whether it is Google QUIC, IETF long - // header packet or IETF short header packet. - PacketHeaderFormat last_header_form_; // Version of the protocol being used. ParsedQuicVersion version_; // This vector contains QUIC versions which we currently support.
diff --git a/quic/core/quic_framer_test.cc b/quic/core/quic_framer_test.cc index 888c87e..c674896 100644 --- a/quic/core/quic_framer_test.cc +++ b/quic/core/quic_framer_test.cc
@@ -24,6 +24,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" #include "net/third_party/quiche/src/quic/test_tools/quic_framer_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" @@ -83,14 +84,12 @@ bool SetKey(QuicStringPiece key) override { return true; } bool SetNoncePrefix(QuicStringPiece nonce_prefix) override { return true; } bool SetIV(QuicStringPiece iv) override { return true; } - bool EncryptPacket(QuicTransportVersion version, - uint64_t packet_number, + bool EncryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece plaintext, char* output, size_t* output_length, size_t max_output_length) override { - version_ = version; packet_number_ = QuicPacketNumber(packet_number); associated_data_ = QuicString(associated_data); plaintext_ = QuicString(plaintext); @@ -110,7 +109,6 @@ QuicStringPiece GetKey() const override { return QuicStringPiece(); } QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } - QuicTransportVersion version_; QuicPacketNumber packet_number_; QuicString associated_data_; QuicString plaintext_; @@ -129,14 +127,12 @@ bool SetDiversificationNonce(const DiversificationNonce& key) override { return true; } - bool DecryptPacket(QuicTransportVersion version, - uint64_t packet_number, + bool DecryptPacket(uint64_t packet_number, QuicStringPiece associated_data, QuicStringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) override { - version_ = version; packet_number_ = QuicPacketNumber(packet_number); associated_data_ = QuicString(associated_data); ciphertext_ = QuicString(ciphertext); @@ -150,7 +146,6 @@ QuicStringPiece GetNoncePrefix() const override { return QuicStringPiece(); } // Use a distinct value starting with 0xFFFFFF, which is never used by TLS. uint32_t cipher_id() const override { return 0xFFFFFFF2; } - QuicTransportVersion version_; QuicPacketNumber packet_number_; QuicString associated_data_; QuicString ciphertext_; @@ -212,6 +207,15 @@ return accept_packet_; } + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override { + size_t coalesced_data_length = packet.length(); + char* coalesced_data = new char[coalesced_data_length]; + memcpy(coalesced_data, packet.data(), coalesced_data_length); + coalesced_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>( + coalesced_data, coalesced_data_length, + /*owns_buffer=*/true)); + } + bool OnStreamFrame(const QuicStreamFrame& frame) override { ++frame_count_; // Save a copy of the data so it is valid after the packet is processed. @@ -278,7 +282,8 @@ bool OnMessageFrame(const QuicMessageFrame& frame) override { ++frame_count_; - message_frames_.push_back(QuicMakeUnique<QuicMessageFrame>(frame)); + message_frames_.push_back( + QuicMakeUnique<QuicMessageFrame>(frame.data, frame.message_length)); return true; } @@ -386,6 +391,7 @@ std::vector<std::unique_ptr<QuicPaddingFrame>> padding_frames_; std::vector<std::unique_ptr<QuicPingFrame>> ping_frames_; std::vector<std::unique_ptr<QuicMessageFrame>> message_frames_; + std::vector<std::unique_ptr<QuicEncryptedPacket>> coalesced_packets_; QuicRstStreamFrame rst_stream_frame_; QuicConnectionCloseFrame connection_close_frame_; QuicApplicationCloseFrame application_close_frame_; @@ -459,7 +465,6 @@ } bool CheckEncryption(QuicPacketNumber packet_number, QuicPacket* packet) { - EXPECT_EQ(version_.transport_version, encrypter_->version_); if (packet_number != encrypter_->packet_number_) { QUIC_LOG(ERROR) << "Encrypted incorrect packet number. expected " << packet_number @@ -488,36 +493,53 @@ bool includes_diversification_nonce, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length) { - EXPECT_EQ(version_.transport_version, decrypter_->version_); + return CheckDecryption( + encrypted, includes_version, includes_diversification_nonce, + destination_connection_id_length, source_connection_id_length, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + } + + bool CheckDecryption( + const QuicEncryptedPacket& encrypted, + bool includes_version, + bool includes_diversification_nonce, + QuicConnectionIdLength destination_connection_id_length, + QuicConnectionIdLength source_connection_id_length, + QuicVariableLengthIntegerLength retry_token_length_length, + size_t retry_token_length, + QuicVariableLengthIntegerLength length_length) { if (visitor_.header_->packet_number != decrypter_->packet_number_) { QUIC_LOG(ERROR) << "Decrypted incorrect packet number. expected " << visitor_.header_->packet_number << " actual: " << decrypter_->packet_number_; return false; } - if (QuicFramer::GetAssociatedDataFromEncryptedPacket( + QuicStringPiece associated_data = + QuicFramer::GetAssociatedDataFromEncryptedPacket( framer_.transport_version(), encrypted, destination_connection_id_length, source_connection_id_length, includes_version, includes_diversification_nonce, - PACKET_4BYTE_PACKET_NUMBER) != decrypter_->associated_data_) { + PACKET_4BYTE_PACKET_NUMBER, retry_token_length_length, + retry_token_length, length_length); + if (associated_data != decrypter_->associated_data_) { QUIC_LOG(ERROR) << "Decrypted incorrect associated data. expected " - << QuicFramer::GetAssociatedDataFromEncryptedPacket( - framer_.transport_version(), encrypted, - destination_connection_id_length, - source_connection_id_length, includes_version, - includes_diversification_nonce, - PACKET_4BYTE_PACKET_NUMBER) - << " actual: " << decrypter_->associated_data_; + << QuicTextUtils::HexEncode(associated_data) + << " actual: " + << QuicTextUtils::HexEncode(decrypter_->associated_data_); return false; } QuicStringPiece ciphertext( encrypted.AsStringPiece().substr(GetStartOfEncryptedData( framer_.transport_version(), destination_connection_id_length, source_connection_id_length, includes_version, - includes_diversification_nonce, PACKET_4BYTE_PACKET_NUMBER))); + includes_diversification_nonce, PACKET_4BYTE_PACKET_NUMBER, + retry_token_length_length, retry_token_length, length_length))); if (ciphertext != decrypter_->ciphertext_) { QUIC_LOG(ERROR) << "Decrypted incorrect ciphertext data. expected " - << ciphertext << " actual: " << decrypter_->ciphertext_; + << QuicTextUtils::HexEncode(ciphertext) << " actual: " + << QuicTextUtils::HexEncode(decrypter_->ciphertext_) + << " associated data: " + << QuicTextUtils::HexEncode(associated_data); return false; } return true; @@ -609,12 +631,29 @@ return BuildUnsizedDataPacket(&framer_, header, frames, packet_size); } + // N starts at 1. + QuicStreamId GetNthStreamid(QuicTransportVersion transport_version, + Perspective perspective, + bool bidirectional, + int n) { + if (bidirectional) { + return QuicUtils::GetFirstBidirectionalStreamId(transport_version, + perspective) + + ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); + } + // Unidirectional + return QuicUtils::GetFirstUnidirectionalStreamId(transport_version, + perspective) + + ((n - 1) * QuicUtils::StreamIdDelta(transport_version)); + } + test::TestEncrypter* encrypter_; test::TestDecrypter* decrypter_; ParsedQuicVersion version_; QuicTime start_; QuicFramer framer_; test::TestQuicVisitor visitor_; + SimpleBufferAllocator allocator_; }; // Multiple test cases of QuicFramerTest use byte arrays to define packets for @@ -626,7 +665,7 @@ GetQuicVersionDigitOnes() // Run all framer tests with all supported versions of QUIC. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( QuicFramerTests, QuicFramerTest, ::testing::ValuesIn(AllSupportedVersionsIncludingTls())); @@ -764,7 +803,7 @@ // packet number 0x78, 0x56, 0x34, 0x12, }; - unsigned char packet47[kMaxPacketSize + 1] = { + unsigned char packet46[kMaxPacketSize + 1] = { // type (short header 4 byte packet number) 0x43, // connection_id @@ -775,9 +814,9 @@ // clang-format on unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); @@ -786,7 +825,8 @@ const size_t header_size = GetPacketHeaderSize( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size, 0, kMaxPacketSize - header_size); @@ -802,20 +842,12 @@ } TEST_P(QuicFramerTest, PacketHeader) { - // clang-format off - PacketFragments packet38 = { - // public flags (8 byte connection_id) - {"Unable to read public flags.", - {0x28}}, - // connection_id - {"Unable to read ConnectionId.", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // packet number - {"Unable to read packet number.", - {0x78, 0x56, 0x34, 0x12}}, - }; + if (framer_.transport_version() > QUIC_VERSION_43) { + return; + } - PacketFragments packet39 = { + // clang-format off + PacketFragments packet = { // public flags (8 byte connection_id) {"Unable to read public flags.", {0x28}}, @@ -828,12 +860,7 @@ }; // clang-format on - if (framer_.transport_version() > QUIC_VERSION_43) { - return; - } - - PacketFragments& fragments = - framer_.transport_version() == QUIC_VERSION_35 ? packet38 : packet39; + PacketFragments& fragments = packet; std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); @@ -869,7 +896,7 @@ {"Unable to read packet number.", {0x12, 0x34, 0x56, 0x78}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (long header with packet type INITIAL) {"Unable to read type.", {0xC3}}, @@ -888,12 +915,13 @@ }; // clang-format on - if (framer_.transport_version() <= QUIC_VERSION_43) { + if (framer_.transport_version() <= QUIC_VERSION_43 || + QuicVersionHasLongHeaderLengths(framer_.transport_version())) { return; } PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44; + framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44; std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); @@ -907,7 +935,7 @@ EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); CheckFramingBoundaries( - framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet44, + framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet44, QUIC_INVALID_PACKET_HEADER); } @@ -924,16 +952,6 @@ // connection_id // packet number {"Unable to read packet number.", - {0x78, 0x56, 0x34, 0x12}} - }; - - PacketFragments packet39 = { - // public flags (0 byte connection_id) - {"Unable to read public flags.", - {0x20}}, - // connection_id - // packet number - {"Unable to read packet number.", {0x12, 0x34, 0x56, 0x78}}, }; @@ -947,7 +965,7 @@ {0x12, 0x34, 0x56, 0x78}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"Unable to read type.", {0x43}}, @@ -959,12 +977,9 @@ // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() == QUIC_VERSION_35 ? packet - : packet39)); + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); @@ -993,21 +1008,6 @@ {QUIC_VERSION_BYTES}}, // packet number {"Unable to read packet number.", - {0x78, 0x56, 0x34, 0x12}}, - }; - - PacketFragments packet39 = { - // public flags (0 byte connection_id) - {"Unable to read public flags.", - {0x29}}, - // connection_id - {"Unable to read ConnectionId.", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // version tag - {"Unable to read protocol version.", - {QUIC_VERSION_BYTES}}, - // packet number - {"Unable to read packet number.", {0x12, 0x34, 0x56, 0x78}}, }; @@ -1029,7 +1029,7 @@ {0x12, 0x34, 0x56, 0x78}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes // packet number) {"Unable to read type.", @@ -1047,15 +1047,37 @@ {"Unable to read packet number.", {0x12, 0x34, 0x56, 0x78}}, }; + + PacketFragments packet99 = { + // type (long header with packet type ZERO_RTT_PROTECTED and 4 bytes + // packet number) + {"Unable to read type.", + {0xD3}}, + // version tag + {"Unable to read protocol version.", + {QUIC_VERSION_BYTES}}, + // connection_id length + {"Unable to read ConnectionId length.", + {0x50}}, + // connection_id + {"Unable to read Destination ConnectionId.", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // long header packet length + {"Unable to read long header payload length.", + {0x04}}, + // packet number + {"Long header payload length longer than packet.", + {0x12, 0x34, 0x56, 0x78}}, + }; // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() == QUIC_VERSION_35 ? packet - : packet39)); + framer_.transport_version() == QUIC_VERSION_99 + ? packet99 + : framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); @@ -1084,18 +1106,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0x78, 0x56, 0x34, 0x12}}, - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id and 4 byte packet number) - {"Unable to read public flags.", - {0x28}}, - // connection_id - {"Unable to read ConnectionId.", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // packet number - {"Unable to read packet number.", {0x12, 0x34, 0x56, 0x78}}, }; @@ -1111,7 +1121,7 @@ {0x12, 0x34, 0x56, 0x78}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"Unable to read type.", {0x43}}, @@ -1125,12 +1135,9 @@ // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() == QUIC_VERSION_35 ? packet - : packet39)); + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); @@ -1158,18 +1165,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"Unable to read packet number.", - {0x78, 0x56}}, - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id and 2 byte packet number) - {"Unable to read public flags.", - {0x18}}, - // connection_id - {"Unable to read ConnectionId.", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // packet number - {"Unable to read packet number.", {0x56, 0x78}}, }; @@ -1185,7 +1180,7 @@ {0x56, 0x78}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 2 byte packet number) {"Unable to read type.", {0x41}}, @@ -1199,12 +1194,9 @@ // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() == QUIC_VERSION_35 ? packet - : packet39)); + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); @@ -1248,7 +1240,7 @@ {0x78}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (8 byte connection_id and 1 byte packet number) {"Unable to read type.", {0x40}}, @@ -1263,8 +1255,8 @@ // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); @@ -1360,24 +1352,6 @@ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (padding) - 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - unsigned char packet39[] = { - // public flags: includes nonce flag - 0x2C, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // nonce - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (padding) @@ -1407,7 +1381,7 @@ 0x00, 0x00, 0x00, 0x00 }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet // number. 0xD0, @@ -1429,18 +1403,48 @@ 0x00, 0x00, 0x00, 0x00, 0x00 }; + + unsigned char packet99[] = { + // type: Long header with packet type ZERO_RTT_PROTECTED and 1 byte packet + // number. + 0xD0, + // version tag + QUIC_VERSION_BYTES, + // connection_id length + 0x05, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x26, + // packet number + 0x78, + // nonce + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + + // frame type (padding) + 0x00, + 0x00, 0x00, 0x00, 0x00 + }; // clang-format on + if (framer_.version().handshake_protocol != PROTOCOL_QUIC_CRYPTO) { + return; + } + unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + if (framer_.transport_version() == QUIC_VERSION_99) { + p = packet99; + p_size = QUIC_ARRAYSIZE(packet99); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); @@ -1452,7 +1456,7 @@ } EXPECT_EQ(1u, visitor_.padding_frames_.size()); EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); -}; +} TEST_P(QuicFramerTest, LargePublicFlagWithMismatchedVersions) { // clang-format off @@ -1464,21 +1468,6 @@ // version tag 'Q', '0', '0', '0', // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (padding frame) - 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id, version flag and an unknown flag) - 0x29, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // version tag - 'Q', '0', '0', '0', - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (padding frame) @@ -1505,11 +1494,8 @@ // clang-format on QuicEncryptedPacket encrypted( - AsChars(framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() == QUIC_VERSION_35 - ? packet - : packet39)), + AsChars(framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet), framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) : QUIC_ARRAYSIZE(packet), false); @@ -1520,7 +1506,7 @@ EXPECT_EQ(1, visitor_.version_mismatch_); EXPECT_EQ(1u, visitor_.padding_frames_.size()); EXPECT_EQ(5, visitor_.padding_frames_[0]->num_padding_bytes); -}; +} TEST_P(QuicFramerTest, PaddingFrame) { // clang-format off @@ -1530,88 +1516,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (padding frame) - 0x00, - // Ignored data (which in this case is a stream frame) - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - // clang-format on - - if (framer_.transport_version() != QUIC_VERSION_35) { - return; - } - - QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); - ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption( - encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - - ASSERT_EQ(0u, visitor_.stream_frames_.size()); - EXPECT_EQ(0u, visitor_.ack_frames_.size()); - EXPECT_EQ(1u, visitor_.padding_frames_.size()); - EXPECT_EQ(28, visitor_.padding_frames_[0]->num_padding_bytes); - // A packet with no frames is not acceptable. - CheckProcessingFails( - packet, - GetPacketHeaderSize( - framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, - PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER), - "Packet has no frames.", QUIC_MISSING_PAYLOAD); -} - -TEST_P(QuicFramerTest, NewPaddingFrame) { - // clang-format off - unsigned char packet[] = { - // public flags (8 byte connection_id) - 0x28, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number - 0x78, 0x56, 0x34, 0x12, - - // paddings - 0x00, 0x00, - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - // paddings - 0x00, 0x00, - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x28, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // paddings @@ -1660,7 +1564,7 @@ 0x00, 0x00, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -1716,22 +1620,17 @@ }; // clang-format on - if (framer_.transport_version() == QUIC_VERSION_35) { - return; - } unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); @@ -1764,36 +1663,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (stream frame with fin) - {"", - {0xFF}}, - // stream id - {"Unable to read stream_id.", - {0x04, 0x03, 0x02, 0x01}}, - // offset - {"Unable to read offset.", - {0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A}}, - {"Unable to read frame data.", - { - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!'}}, - }; - - PacketFragments packet39 = { - // 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 (stream frame with fin) {"", @@ -1845,7 +1714,7 @@ 'r', 'l', 'd', '!'}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -1909,13 +1778,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -1996,33 +1862,10 @@ QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); decrypter_ = new test::TestDecrypter(); framer_.SetAlternativeDecrypter( - ENCRYPTION_INITIAL, std::unique_ptr<QuicDecrypter>(decrypter_), false); + ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); // clang-format off unsigned char packet[] = { - // public flags (8 byte connection_id) - 0x28, - // connection_id - 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - - unsigned char packet39[] = { // public flags (8 byte connection_id) 0x28, // connection_id @@ -2076,8 +1919,6 @@ unsigned char* p = packet; if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), framer_.transport_version() > QUIC_VERSION_43 @@ -2108,36 +1949,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (stream frame with fin) - {"", - {0xFE}}, - // stream id - {"Unable to read stream_id.", - {0x04, 0x03, 0x02}}, - // offset - {"Unable to read offset.", - {0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A}}, - {"Unable to read frame data.", - { - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!'}}, - }; - - PacketFragments packet39 = { - // 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 (stream frame with fin) {"", @@ -2160,8 +1971,7 @@ }; // clang-format on - PacketFragments& fragments = - framer_.transport_version() != QUIC_VERSION_35 ? packet39 : packet; + PacketFragments& fragments = packet; std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -2194,36 +2004,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (stream frame with fin) - {"", - {0xFD}}, - // stream id - {"Unable to read stream_id.", - {0x04, 0x03}}, - // offset - {"Unable to read offset.", - {0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A}}, - {"Unable to read frame data.", - { - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!'}}, - }; - - PacketFragments packet39 = { - // 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 (stream frame with fin) {"", @@ -2275,7 +2055,7 @@ 'r', 'l', 'd', '!'}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -2339,13 +2119,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -2378,36 +2155,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (stream frame with fin) - {"", - {0xFC}}, - // stream id - {"Unable to read stream_id.", - {0x04}}, - // offset - {"Unable to read offset.", - {0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A}}, - {"Unable to read frame data.", - { - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!'}}, - }; - - PacketFragments packet39 = { - // 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 (stream frame with fin) {"", @@ -2459,7 +2206,7 @@ 'r', 'l', 'd', '!'}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -2523,13 +2270,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -2565,39 +2309,6 @@ {QUIC_VERSION_BYTES}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (stream frame with fin) - {"", - {0xFE}}, - // stream id - {"Unable to read stream_id.", - {0x04, 0x03, 0x02}}, - // offset - {"Unable to read offset.", - {0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A}}, - {"Unable to read frame data.", - { - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!'}}, - }; - - PacketFragments packet39 = { - // public flags (version, 8 byte connection_id) - {"", - {0x29}}, - // connection_id - {"", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // version tag - {"", - {QUIC_VERSION_BYTES}}, - // packet number - {"", {0x12, 0x34, 0x56, 0x78}}, // frame type (stream frame with fin) {"", @@ -2655,7 +2366,7 @@ 'r', 'l', 'd', '!'}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // public flags (long header with packet type ZERO_RTT_PROTECTED and // 4-byte packet number) {"", @@ -2706,6 +2417,9 @@ // connection_id {"", {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // long header packet length + {"", + {0x1E}}, // packet number {"", {0x12, 0x34, 0x56, 0x78}}, @@ -2713,33 +2427,38 @@ {"", {0x08 | 0x01 | 0x02 | 0x04}}, // stream id - {"Unable to read stream_id.", + {"Long header payload length longer than packet.", {kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04}}, // offset - {"Unable to read stream data offset.", + {"Long header payload length longer than packet.", {kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54}}, // data length - {"Unable to read stream data length.", + {"Long header payload length longer than packet.", {kVarInt62OneByte + 0x0c}}, // data - {"Unable to read frame data.", + {"Long header payload length longer than packet.", { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'}}, }; // clang-format on + QuicVariableLengthIntegerLength retry_token_length_length = + VARIABLE_LENGTH_INTEGER_LENGTH_0; + size_t retry_token_length = 0; + QuicVariableLengthIntegerLength length_length = + QuicVersionHasLongHeaderLengths(framer_.transport_version()) + ? VARIABLE_LENGTH_INTEGER_LENGTH_1 + : VARIABLE_LENGTH_INTEGER_LENGTH_0; + PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -2748,7 +2467,8 @@ ASSERT_TRUE(visitor_.header_.get()); EXPECT_TRUE(CheckDecryption( *encrypted, kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, + retry_token_length_length, retry_token_length, length_length)); ASSERT_EQ(1u, visitor_.stream_frames_.size()); EXPECT_EQ(0u, visitor_.ack_frames_.size()); @@ -2758,7 +2478,10 @@ EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); - CheckFramingBoundaries(fragments, QUIC_INVALID_STREAM_DATA); + CheckFramingBoundaries(fragments, + framer_.transport_version() == QUIC_VERSION_99 + ? QUIC_INVALID_PACKET_HEADER + : QUIC_INVALID_STREAM_DATA); } TEST_P(QuicFramerTest, RejectPacket) { @@ -2771,29 +2494,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - - unsigned char packet39[] = { - // 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 (stream frame with fin) @@ -2834,7 +2534,7 @@ 'r', 'l', 'd', '!', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -2859,12 +2559,10 @@ // clang-format on unsigned char* p = packet; - if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), framer_.transport_version() > QUIC_VERSION_43 @@ -2903,7 +2601,7 @@ 0x01, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 1 byte packet number) 0x40, // connection_id @@ -2914,12 +2612,12 @@ // clang-format on QuicEncryptedPacket encrypted( - framer_.transport_version() > QUIC_VERSION_46 - ? AsChars(packet47) + framer_.transport_version() > QUIC_VERSION_44 + ? AsChars(packet46) : (framer_.transport_version() > QUIC_VERSION_43 ? AsChars(packet44) : AsChars(packet)), - framer_.transport_version() > QUIC_VERSION_46 - ? QUIC_ARRAYSIZE(packet47) + framer_.transport_version() > QUIC_VERSION_44 + ? QUIC_ARRAYSIZE(packet46) : (framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) : QUIC_ARRAYSIZE(packet)), @@ -2942,34 +2640,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (ack frame) - // (one ack block, 2 byte largest observed, 2 byte block length) - {"", - {0x45}}, - // largest acked - {"Unable to read largest acked.", - {0x34, 0x12}}, - // Zero delta time. - {"Unable to read ack delay time.", - {0x00, 0x00}}, - // first ack block length. - {"Unable to read first ack block length.", - {0x34, 0x12}}, - // num timestamps. - {"Unable to read num received packets.", - {0x00}} - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id) - {"", - {0x2C}}, - // connection_id - {"", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // packet number - {"", {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) @@ -3017,7 +2687,7 @@ {0x00}} }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short packet, 4 byte packet number) {"", {0x43}}, @@ -3084,13 +2754,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -3124,34 +2791,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (ack frame) - // (one ack block, 2 byte largest observed, 2 byte block length) - {"", - {0x45}}, - // largest acked - {"Unable to read largest acked.", - {0x34, 0x12}}, - // Zero delta time. - {"Unable to read ack delay time.", - {0x00, 0x00}}, - // first ack block length. - {"Unable to read first ack block length.", - {0x88, 0x88}}, - // num timestamps. - {"Underflow with first ack block length 34952 largest acked is 4660.", - {0x00}} - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id) - {"", - {0x2C}}, - // connection_id - {"", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // packet number - {"", {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) // (one ack block, 2 byte largest observed, 2 byte block length) @@ -3199,7 +2838,7 @@ {0x00}} }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -3258,13 +2897,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_FALSE(framer_.ProcessPacket(*encrypted)); @@ -3557,47 +3193,6 @@ { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0x78, 0x56, 0x34, 0x12 }}, - - // frame type (ack frame) - // (more than one ack block, 2 byte largest observed, 2 byte block length) - {"", - { 0x65 }}, - // largest acked - {"Unable to read largest acked.", - { 0x34, 0x12 }}, - // Zero delta time. - {"Unable to read ack delay time.", - { 0x00, 0x00 }}, - // num ack blocks ranges. - {"Unable to read num of ack blocks.", - { 0x01 }}, - // first ack block length. - {"Unable to read first ack block length.", - { 0x00, 0x00 }}, - // gap to next block. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", - { 0x01 }}, - // ack block length. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", - { 0xaf, 0x0e }}, - // Number of timestamps. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", - { 0x00 }}, - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id) - {"", - { 0x2C }}, - // connection_id - {"", - { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, - // packet number - {"", { 0x12, 0x34, 0x56, 0x78 }}, // frame type (ack frame) @@ -3617,16 +3212,13 @@ {"Unable to read first ack block length.", { 0x00, 0x00 }}, // gap to next block. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x01 }}, // ack block length. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x0e, 0xaf }}, // Number of timestamps. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x00 }}, }; @@ -3658,20 +3250,17 @@ {"Unable to read first ack block length.", { 0x00, 0x00 }}, // gap to next block. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x01 }}, // ack block length. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x0e, 0xaf }}, // Number of timestamps. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x00 }}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", { 0x43 }}, @@ -3699,27 +3288,21 @@ {"Unable to read first ack block length.", { 0x00, 0x00 }}, // gap to next block. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x01 }}, // ack block length. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x0e, 0xaf }}, // Number of timestamps. - { "First block length is zero but ACK is not empty. " - "largest acked is 4660, num ack blocks is 1.", + { "First block length is zero.", { 0x00 }}, }; // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 ? packet39 - : packet)); + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); @@ -3749,34 +3332,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (ack frame) - // (one ack block, 4 byte largest observed, 2 byte block length) - {"", - {0x49}}, - // largest acked - {"Unable to read largest acked.", - {0x78, 0x56, 0x34, 0x12}}, - // Zero delta time. - {"Unable to read ack delay time.", - {0x00, 0x00}}, - // first ack block length. - {"Unable to read first ack block length.", - {0x34, 0x12}}, - // num timestamps. - {"Unable to read num received packets.", - {0x00}} - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id) - {"", - {0x2C}}, - // connection_id - {"", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // packet number - {"", {0x12, 0x34, 0x56, 0x78}}, // frame type (ack frame) // (one ack block, 4 byte largest observed, 2 byte block length) @@ -3824,7 +3379,7 @@ {0x00}} }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -3883,13 +3438,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -3922,74 +3474,6 @@ { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, // packet number {"", - { 0x78, 0x56, 0x34, 0x12 }}, - - // frame type (ack frame) - // (more than one ack block, 2 byte largest observed, 2 byte block length) - {"", - { 0x65 }}, - // largest acked - {"Unable to read largest acked.", - { 0x34, 0x12 }}, - // Zero delta time. - {"Unable to read ack delay time.", - { 0x00, 0x00 }}, - // num ack blocks ranges. - {"Unable to read num of ack blocks.", - { 0x04 }}, - // first ack block length. - {"Unable to read first ack block length.", - { 0x01, 0x00 }}, - // gap to next block. - { "Unable to read gap to next ack block.", - { 0x01 }}, - // ack block length. - { "Unable to ack block length.", - { 0xaf, 0x0e }}, - // gap to next block. - { "Unable to read gap to next ack block.", - { 0xff }}, - // ack block length. - { "Unable to ack block length.", - { 0x00, 0x00 }}, - // gap to next block. - { "Unable to read gap to next ack block.", - { 0x91 }}, - // ack block length. - { "Unable to ack block length.", - { 0xea, 0x01 }}, - // gap to next block. - { "Unable to read gap to next ack block.", - { 0x05 }}, - // ack block length. - { "Unable to ack block length.", - { 0x04, 0x00 }}, - // Number of timestamps. - { "Unable to read num received packets.", - { 0x02 }}, - // Delta from largest observed. - { "Unable to read sequence delta in received packets.", - { 0x01 }}, - // Delta time. - { "Unable to read time delta in received packets.", - { 0x10, 0x32, 0x54, 0x76 }}, - // Delta from largest observed. - { "Unable to read sequence delta in received packets.", - { 0x02 }}, - // Delta time. - { "Unable to read incremental time delta in received packets.", - { 0x10, 0x32 }}, - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id) - {"", - { 0x2C }}, - // connection_id - {"", - { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }}, - // packet number - {"", { 0x12, 0x34, 0x56, 0x78 }}, // frame type (ack frame) @@ -4117,7 +3601,7 @@ { 0x32, 0x10 }}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", { 0x43 }}, @@ -4245,13 +3729,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); @@ -4279,6 +3760,200 @@ CheckFramingBoundaries(fragments, QUIC_INVALID_ACK_DATA); } +TEST_P(QuicFramerTest, AckFrameTimeStampDeltaTooHigh) { + // clang-format off + unsigned char 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 (ack frame) + // (no ack blocks, 1 byte largest observed, 1 byte block length) + 0x40, + // largest acked + 0x01, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x01, + // num timestamps. + 0x01, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + }; + + unsigned char packet44[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + // (no ack blocks, 1 byte largest observed, 1 byte block length) + 0x40, + // largest acked + 0x01, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x01, + // num timestamps. + 0x01, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + }; + + unsigned char 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 (ack frame) + // (no ack blocks, 1 byte largest observed, 1 byte block length) + 0x40, + // largest acked + 0x01, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x01, + // num timestamps. + 0x01, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + }; + // clang-format on + if (framer_.transport_version() == QUIC_VERSION_99) { + return; + } + QuicEncryptedPacket encrypted( + AsChars(framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)), + QUIC_ARRAYSIZE(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_TRUE(QuicTextUtils::StartsWith( + framer_.detailed_error(), "delta_from_largest_observed too high")); +} + +TEST_P(QuicFramerTest, AckFrameTimeStampSecondDeltaTooHigh) { + // clang-format off + unsigned char 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 (ack frame) + // (no ack blocks, 1 byte largest observed, 1 byte block length) + 0x40, + // largest acked + 0x03, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x03, + // num timestamps. + 0x02, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + // Delta from largest observed. + 0x03, + // Delta time. + 0x10, 0x32, + }; + + unsigned char packet44[] = { + // type (short header, 4 byte packet number) + 0x32, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x56, 0x78, + + // frame type (ack frame) + // (no ack blocks, 1 byte largest observed, 1 byte block length) + 0x40, + // largest acked + 0x03, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x03, + // num timestamps. + 0x02, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + // Delta from largest observed. + 0x03, + // Delta time. + 0x10, 0x32, + }; + + unsigned char 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 (ack frame) + // (no ack blocks, 1 byte largest observed, 1 byte block length) + 0x40, + // largest acked + 0x03, + // Zero delta time. + 0x00, 0x00, + // first ack block length. + 0x03, + // num timestamps. + 0x02, + // Delta from largest observed. + 0x01, + // Delta time. + 0x10, 0x32, 0x54, 0x76, + // Delta from largest observed. + 0x03, + // Delta time. + 0x10, 0x32, + }; + // clang-format on + if (framer_.transport_version() == QUIC_VERSION_99) { + return; + } + QuicEncryptedPacket encrypted( + AsChars(framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)), + QUIC_ARRAYSIZE(packet), false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_TRUE(QuicTextUtils::StartsWith( + framer_.detailed_error(), "delta_from_largest_observed too high")); +} + TEST_P(QuicFramerTest, NewStopWaitingFrame) { if (version_.transport_version == QUIC_VERSION_99) { return; @@ -4293,24 +3968,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (stop waiting frame) - {"", - {0x06}}, - // least packet number awaiting an ack, delta from packet number. - {"Unable to read least unacked delta.", - {0x08, 0x00, 0x00, 0x00}} - }; - - PacketFragments packet39 = { - // public flags (8 byte connection_id) - {"", - {0x2C}}, - // connection_id - {"", - {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, - // packet number - {"", {0x12, 0x34, 0x56, 0x78}}, // frame type (stop waiting frame) {"", @@ -4338,7 +3995,7 @@ {0x00, 0x00, 0x00, 0x08}} }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -4358,12 +4015,10 @@ // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 ? packet39 - : packet)); + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); + std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -4393,20 +4048,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - // frame type (stop waiting frame) - 0x06, - // least packet number awaiting an ack, delta from packet number. - 0xA8, 0x9A, 0x78, 0x56, - 0x34, 0x13, - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x2C, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (stop waiting frame) 0x06, @@ -4428,7 +4069,7 @@ 0x57, 0x78, 0x9A, 0xA8, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -4443,13 +4084,10 @@ // clang-format on QuicEncryptedPacket encrypted( - AsChars(framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() == QUIC_VERSION_35 - ? packet - : packet39))), + AsChars(framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)), framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) : QUIC_ARRAYSIZE(packet), false); @@ -4469,31 +4107,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (rst stream frame) - {"", - {0x01}}, - // stream id - {"Unable to read stream_id.", - {0x04, 0x03, 0x02, 0x01}}, - // sent byte offset - {"Unable to read rst stream sent byte offset.", - {0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A}}, - // error code - {"Unable to read rst stream error code.", - {0x01, 0x00, 0x00, 0x00}} - }; - - PacketFragments packet39 = { - // 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 (rst stream frame) {"", @@ -4535,7 +4148,7 @@ {0x00, 0x00, 0x00, 0x01}} }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -4588,13 +4201,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -4622,34 +4232,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (connection close frame) - {"", - {0x02}}, - // error code - {"Unable to read connection close error code.", - {0x11, 0x00, 0x00, 0x00}}, - {"Unable to read connection close error details.", - { - // error details length - 0x0d, 0x00, - // error details - 'b', 'e', 'c', 'a', - 'u', 's', 'e', ' ', - 'I', ' ', 'c', 'a', - 'n'} - } - }; - - PacketFragments packet39 = { - // 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) {"", @@ -4697,7 +4279,7 @@ } }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -4759,13 +4341,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -4860,37 +4439,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (go away frame) - {"", - {0x03}}, - // error code - {"Unable to read go away error code.", - {0x09, 0x00, 0x00, 0x00}}, - // stream id - {"Unable to read last good stream id.", - {0x04, 0x03, 0x02, 0x01}}, - {"Unable to read goaway reason.", - { - // error details length - 0x0d, 0x00, - // error details - 'b', 'e', 'c', 'a', - 'u', 's', 'e', ' ', - 'I', ' ', 'c', 'a', - 'n'} - } - }; - - PacketFragments packet39 = { - // 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) {"", @@ -4946,7 +4494,7 @@ } }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -4980,12 +4528,9 @@ // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 ? packet39 - : packet)); + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -5019,28 +4564,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (window update frame) - {"", - {0x04}}, - // stream id - {"Unable to read stream_id.", - {0x04, 0x03, 0x02, 0x01}}, - // byte offset - {"Unable to read window byte_offset.", - {0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A}}, - }; - - PacketFragments packet39 = { - // 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 (window update frame) {"", @@ -5076,7 +4599,7 @@ 0x32, 0x10, 0x76, 0x54}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -5101,12 +4624,9 @@ // clang-format on PacketFragments& fragments = - framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 ? packet39 - : packet)); + framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 : packet); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -5159,7 +4679,8 @@ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - EXPECT_EQ(0u, visitor_.window_update_frame_.stream_id); + EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()), + visitor_.window_update_frame_.stream_id); EXPECT_EQ(kStreamOffset, visitor_.window_update_frame_.byte_offset); CheckFramingBoundaries(packet99, QUIC_INVALID_MAX_DATA_FRAME_DATA); @@ -5221,24 +4742,6 @@ {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, // packet number {"", - {0x78, 0x56, 0x34, 0x12}}, - // frame type (blocked frame) - {"", - {0x05}}, - // stream id - {"Unable to read stream_id.", - {0x04, 0x03, 0x02, 0x01}}, - }; - - PacketFragments packet39 = { - // 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 (blocked frame) {"", @@ -5266,7 +4769,7 @@ {0x01, 0x02, 0x03, 0x04}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -5309,13 +4812,10 @@ PacketFragments& fragments = framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 - : (framer_.transport_version() > QUIC_VERSION_43 - ? packet44 - : (framer_.transport_version() != QUIC_VERSION_35 - ? packet39 - : packet))); + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 + : (framer_.transport_version() > QUIC_VERSION_43 ? packet44 + : packet)); std::unique_ptr<QuicEncryptedPacket> encrypted( AssemblePacketFromFragments(fragments)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); @@ -5348,18 +4848,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ping frame) - 0x07, - }; - - unsigned char packet39[] = { - // 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 (ping frame) @@ -5378,7 +4866,7 @@ 0x07, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -5406,17 +4894,15 @@ QuicEncryptedPacket encrypted( AsChars(framer_.transport_version() == QUIC_VERSION_99 ? packet99 - : (framer_.transport_version() > QUIC_VERSION_46 - ? packet47 + : (framer_.transport_version() > QUIC_VERSION_44 + ? packet46 : framer_.transport_version() > QUIC_VERSION_43 ? packet44 - : (framer_.transport_version() == QUIC_VERSION_35 - ? packet - : packet39))), + : packet)), framer_.transport_version() == QUIC_VERSION_99 ? QUIC_ARRAYSIZE(packet99) - : (framer_.transport_version() > QUIC_VERSION_46 - ? QUIC_ARRAYSIZE(packet47) + : (framer_.transport_version() > QUIC_VERSION_44 + ? QUIC_ARRAYSIZE(packet46) : framer_.transport_version() > QUIC_VERSION_43 ? QUIC_ARRAYSIZE(packet44) : QUIC_ARRAYSIZE(packet)), @@ -5466,7 +4952,7 @@ {'m', 'e', 's', 's', 'a', 'g', 'e', '2'}}, }; - PacketFragments packet47 = { + PacketFragments packet46 = { // type (short header, 4 byte packet number) {"", {0x43}}, @@ -5495,7 +4981,7 @@ // clang-format on std::unique_ptr<QuicEncryptedPacket> encrypted(AssemblePacketFromFragments( - framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet45)); + framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45)); EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); @@ -5505,11 +4991,11 @@ PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); ASSERT_EQ(2u, visitor_.message_frames_.size()); - EXPECT_EQ(7u, visitor_.message_frames_[0]->message_data.length()); - EXPECT_EQ(8u, visitor_.message_frames_[1]->message_data.length()); + EXPECT_EQ(7u, visitor_.message_frames_[0]->message_length); + EXPECT_EQ(8u, visitor_.message_frames_[1]->message_length); CheckFramingBoundaries( - framer_.transport_version() > QUIC_VERSION_46 ? packet47 : packet45, + framer_.transport_version() > QUIC_VERSION_44 ? packet46 : packet45, QUIC_INVALID_MESSAGE_DATA); } @@ -5744,7 +5230,7 @@ QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); decrypter_ = new test::TestDecrypter(); framer_.SetAlternativeDecrypter( - ENCRYPTION_INITIAL, std::unique_ptr<QuicDecrypter>(decrypter_), false); + ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); // This packet cannot be decrypted because diversification nonce is missing. QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); @@ -5774,7 +5260,7 @@ QuicMakeUnique<NullDecrypter>(Perspective::IS_CLIENT)); decrypter_ = new test::TestDecrypter(); framer_.SetAlternativeDecrypter( - ENCRYPTION_INITIAL, std::unique_ptr<QuicDecrypter>(decrypter_), false); + ENCRYPTION_ZERO_RTT, std::unique_ptr<QuicDecrypter>(decrypter_), false); // This packet cannot be decrypted because diversification nonce is missing. QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); EXPECT_FALSE(framer_.ProcessPacket(encrypted)); @@ -5892,19 +5378,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (padding frame) - 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - unsigned char packet39[kMaxPacketSize] = { - // 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 (padding frame) @@ -5925,7 +5398,7 @@ 0x00, 0x00, 0x00, 0x00 }; - unsigned char packet47[kMaxPacketSize] = { + unsigned char packet46[kMaxPacketSize] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -5955,18 +5428,17 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } uint64_t header_size = GetPacketHeaderSize( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -5979,9 +5451,6 @@ } TEST_P(QuicFramerTest, BuildStreamFramePacketWithNewPaddingFrame) { - if (framer_.transport_version() == QUIC_VERSION_35) { - return; - } QuicPacketHeader header; header.destination_connection_id = FramerTestConnectionId(); header.reset_flag = false; @@ -6000,33 +5469,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // paddings - 0x00, 0x00, - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - // paddings - 0x00, 0x00, - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x28, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // paddings @@ -6075,7 +5517,7 @@ 0x00, 0x00, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -6138,14 +5580,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); @@ -6170,19 +5610,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (padding frame) - 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - unsigned char packet39[kMaxPacketSize] = { - // public flags (8 byte connection_id and 4 byte packet number) - 0x28, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (padding frame) @@ -6203,7 +5630,7 @@ 0x00, 0x00, 0x00, 0x00 }; - unsigned char packet47[kMaxPacketSize] = { + unsigned char packet46[kMaxPacketSize] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -6233,18 +5660,17 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } uint64_t header_size = GetPacketHeaderSize( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -6273,19 +5699,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, - - // frame type (padding frame) - 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - unsigned char packet39[kMaxPacketSize] = { - // public flags (8 byte connection_id and 2 byte packet number) - 0x18, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x56, 0x78, // frame type (padding frame) @@ -6306,7 +5719,7 @@ 0x00, 0x00, 0x00, 0x00 }; - unsigned char packet47[kMaxPacketSize] = { + unsigned char packet46[kMaxPacketSize] = { // type (short header, 2 byte packet number) 0x41, // connection_id @@ -6336,18 +5749,17 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } uint64_t header_size = GetPacketHeaderSize( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_2BYTE_PACKET_NUMBER); + !kIncludeDiversificationNonce, PACKET_2BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -6396,7 +5808,7 @@ 0x00, 0x00, 0x00, 0x00 }; - unsigned char packet47[kMaxPacketSize] = { + unsigned char packet46[kMaxPacketSize] = { // type (short header, 1 byte packet number) 0x40, // connection_id @@ -6426,8 +5838,8 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; } @@ -6435,7 +5847,8 @@ uint64_t header_size = GetPacketHeaderSize( framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER); + !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -6453,6 +5866,9 @@ header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; + if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) { + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, QuicStringPiece("hello world!")); @@ -6466,27 +5882,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (stream frame with fin and no length) - 0xDF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - - unsigned char packet39[] = { - // 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 (stream frame with fin and no length) @@ -6523,7 +5918,7 @@ 'r', 'l', 'd', '!', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -6574,14 +5969,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), p_size); @@ -6596,6 +5989,9 @@ header.long_packet_type = ZERO_RTT_PROTECTED; } header.packet_number = kPacketNumber; + if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) { + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, QuicStringPiece("hello world!")); @@ -6610,26 +6006,6 @@ // version tag QUIC_VERSION_BYTES, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (stream frame with fin and no length) - 0xDF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0x3A, - // data - 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', - }; - - unsigned char packet39[] = { - // public flags (version, 8 byte connection_id) - 0x2D, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // version tag - QUIC_VERSION_BYTES, - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (stream frame with fin and no length) @@ -6664,7 +6040,7 @@ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (long header with packet type ZERO_RTT_PROTECTED) 0xD3, // version tag @@ -6695,6 +6071,8 @@ 0x50, // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // length + 0x40, 0x1D, // packet number 0x12, 0x34, 0x56, 0x78, @@ -6718,14 +6096,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } test::CompareCharArraysWithHexError("constructed packet", data->data(), data->length(), AsChars(p), p_size); @@ -6896,27 +6272,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ack frame) - // (no ack blocks, 2 byte largest observed, 2 byte block length) - 0x45, - // largest acked - 0x34, 0x12, - // Zero delta time. - 0x00, 0x00, - // first ack block length. - 0x34, 0x12, - // num timestamps. - 0x00, - }; - - unsigned char packet39[] = { - // 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 (ack frame) @@ -6953,7 +6308,7 @@ 0x00, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -6999,14 +6354,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -7034,27 +6387,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ack frame) - // (no ack blocks, 4 byte largest observed, 4 byte block length) - 0x4A, - // largest acked - 0x78, 0x56, 0x34, 0x12, - // Zero delta time. - 0x00, 0x00, - // first ack block length. - 0x78, 0x56, 0x34, 0x12, - // num timestamps. - 0x00, - }; - - unsigned char packet39[] = { - // 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 (ack frame) @@ -7091,7 +6423,7 @@ 0x00, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -7138,14 +6470,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -7178,45 +6508,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ack frame) - // (has ack blocks, 2 byte largest observed, 2 byte block length) - 0x65, - // largest acked - 0x34, 0x12, - // Zero delta time. - 0x00, 0x00, - // num ack blocks ranges. - 0x04, - // first ack block length. - 0x01, 0x00, - // gap to next block. - 0x01, - // ack block length. - 0xaf, 0x0e, - // gap to next block. - 0xff, - // ack block length. - 0x00, 0x00, - // gap to next block. - 0x91, - // ack block length. - 0xea, 0x01, - // gap to next block. - 0x05, - // ack block length. - 0x04, 0x00, - // num timestamps. - 0x00, - }; - - unsigned char packet39[] = { - // 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 (ack frame) @@ -7289,7 +6580,7 @@ 0x00, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -7368,14 +6659,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -7411,99 +6700,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - // frame type (ack frame) - // (has ack blocks, 2 byte largest observed, 2 byte block length) - 0x65, - // largest acked - 0x34, 0x12, - // Zero delta time. - 0x00, 0x00, - // num ack blocks ranges. - 0xff, - // first ack block length. - 0xdd, 0x0f, - // 255 = 4 * 63 + 3 - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, - // num timestamps. - 0x00, - }; - - unsigned char packet39[] = { - // 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 (ack frame) // (has ack blocks, 2 byte largest observed, 2 byte block length) @@ -7684,7 +6880,7 @@ 0x00, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -7867,14 +7063,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -7906,20 +7100,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (stop waiting frame) - 0x06, - // least packet number awaiting an ack, delta from packet number. - 0x08, 0x00, 0x00, 0x00, - }; - - unsigned char packet39[] = { - // 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 (stop waiting frame) @@ -7930,18 +7110,12 @@ // clang-format on - unsigned char* p = packet; - if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; - } - std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); ASSERT_TRUE(data != nullptr); - test::CompareCharArraysWithHexError( - "constructed packet", data->data(), data->length(), AsChars(p), - framer_.transport_version() != QUIC_VERSION_35 ? QUIC_ARRAYSIZE(packet39) - : QUIC_ARRAYSIZE(packet)); + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet), + QUIC_ARRAYSIZE(packet)); } TEST_P(QuicFramerTest, BuildRstFramePacketQuic) { @@ -7967,25 +7141,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (rst stream frame) - 0x01, - // stream id - 0x04, 0x03, 0x02, 0x01, - // sent byte offset - 0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08, - // error code - 0x08, 0x07, 0x06, 0x05, - }; - - unsigned char packet39[] = { - // 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 (rst stream frame) @@ -8018,7 +7173,7 @@ 0x05, 0x06, 0x07, 0x08, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short packet, 4 byte packet number) 0x43, // connection_id @@ -8066,14 +7221,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); @@ -8107,27 +7260,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (connection close frame) - 0x02, - // error code - 0x08, 0x07, 0x06, 0x05, - // error details length - 0x0d, 0x00, - // error details - 'b', 'e', 'c', 'a', - 'u', 's', 'e', ' ', - 'I', ' ', 'c', 'a', - 'n', - }; - - unsigned char packet39[] = { - // 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) @@ -8164,7 +7296,7 @@ 'n', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -8214,14 +7346,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -8255,55 +7385,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (connection close frame) - 0x02, - // error code - 0x08, 0x07, 0x06, 0x05, - // error details length - 0x00, 0x01, - // error details (truncated to 256 bytes) - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - }; - - unsigned char packet39[] = { - // 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) @@ -8396,7 +7477,7 @@ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -8502,14 +7583,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -8669,29 +7748,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (go away frame) - 0x03, - // error code - 0x08, 0x07, 0x06, 0x05, - // stream id - 0x04, 0x03, 0x02, 0x01, - // error details length - 0x0d, 0x00, - // error details - 'b', 'e', 'c', 'a', - 'u', 's', 'e', ' ', - 'I', ' ', 'c', 'a', - 'n', - }; - - unsigned char packet39[] = { - // 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) @@ -8732,7 +7788,7 @@ 'n', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -8759,14 +7815,12 @@ unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -8801,57 +7855,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (go away frame) - 0x03, - // error code - 0x08, 0x07, 0x06, 0x05, - // stream id - 0x04, 0x03, 0x02, 0x01, - // error details length - 0x00, 0x01, - // error details (truncated to 256 bytes) - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', - }; - - unsigned char packet39[] = { - // 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) @@ -8948,7 +7951,7 @@ 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -9002,14 +8005,12 @@ unsigned char* p = packet; size_t p_size = QUIC_ARRAYSIZE(packet); - if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -9039,23 +8040,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (window update frame) - 0x04, - // stream id - 0x04, 0x03, 0x02, 0x01, - // byte offset - 0x88, 0x77, 0x66, 0x55, - 0x44, 0x33, 0x22, 0x11, - }; - - unsigned char packet39[] = { - // 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 (window update frame) @@ -9084,7 +8068,7 @@ 0x55, 0x66, 0x77, 0x88, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -9127,14 +8111,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } test::CompareCharArraysWithHexError("constructed packet", data->data(), @@ -9197,7 +8179,8 @@ header.packet_number = kPacketNumber; QuicWindowUpdateFrame window_update_frame; - window_update_frame.stream_id = 0; + window_update_frame.stream_id = + QuicUtils::GetInvalidStreamId(framer_.transport_version()); window_update_frame.byte_offset = 0x1122334455667788; QuicFrames frames = {QuicFrame(&window_update_frame)}; @@ -9236,12 +8219,11 @@ QuicBlockedFrame blocked_frame; if (framer_.transport_version() == QUIC_VERSION_99) { - // For V99, the stream ID must be 0 for the frame - // to be a BLOCKED frame. if non-0, it will be a + // For V99, the stream ID must be <invalid> for the frame + // to be a BLOCKED frame. if it's valid, it will be a // STREAM_BLOCKED frame. - // TODO(fkastenholz): This should be converted to use - // QuicUtils::GetInvalidStreamId to get the correct invalid stream id value. - blocked_frame.stream_id = 0; + blocked_frame.stream_id = + QuicUtils::GetInvalidStreamId(framer_.transport_version()); } else { blocked_frame.stream_id = kStreamId; } @@ -9256,20 +8238,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (blocked frame) - 0x05, - // stream id - 0x04, 0x03, 0x02, 0x01, - }; - - unsigned char packet39[] = { - // 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 (blocked frame) @@ -9292,7 +8260,7 @@ 0x01, 0x02, 0x03, 0x04, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short packet, 4 byte packet number) 0x43, // connection_id @@ -9314,7 +8282,7 @@ // packet number 0x12, 0x34, 0x56, 0x78, - // frame type (IETF_BLOCKED frame) wahoo + // frame type (IETF_BLOCKED frame) 0x14, // Offset kVarInt62EightBytes + 0x3a, 0x98, 0xFE, 0xDC, 0x32, 0x10, 0x76, 0x54 @@ -9329,14 +8297,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } test::CompareCharArraysWithHexError("constructed packet", data->data(), @@ -9359,18 +8325,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ping frame) - 0x07, - }; - - unsigned char packet39[] = { - // 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 (ping frame) @@ -9389,7 +8343,7 @@ 0x07, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -9417,12 +8371,10 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -9443,9 +8395,13 @@ header.reset_flag = false; header.version_flag = false; header.packet_number = kPacketNumber; + QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); - QuicMessageFrame frame(1, "message"); - QuicMessageFrame frame2(2, "message2"); + QuicMessageFrame frame(1); + MakeSpan(&allocator_, "message", &storage).SaveMemSlicesAsMessageData(&frame); + QuicMessageFrame frame2(2); + MakeSpan(&allocator_, "message2", &storage) + .SaveMemSlicesAsMessageData(&frame2); QuicFrames frames = {QuicFrame(&frame), QuicFrame(&frame2)}; // clang-format off @@ -9469,7 +8425,7 @@ 'm', 'e', 's', 's', 'a', 'g', 'e', '2' }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -9513,8 +8469,8 @@ unsigned char* p = packet45; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -9541,21 +8497,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ping frame) - 0x07, - // frame type (padding frame) - 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - unsigned char packet39[] = { - // 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 (ping frame) @@ -9580,7 +8521,7 @@ 0x00, 0x00, 0x00, 0x00 }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -9616,70 +8557,21 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; packet_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - packet_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + packet_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; packet_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; - packet_size = QUIC_ARRAYSIZE(packet39); } std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); - size_t length = - framer_.BuildConnectivityProbingPacket(header, buffer.get(), packet_size); + size_t length = framer_.BuildConnectivityProbingPacket( + header, buffer.get(), packet_size, ENCRYPTION_NONE); EXPECT_NE(0u, length); - QuicPacket data(buffer.release(), length, true, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); - - test::CompareCharArraysWithHexError("constructed packet", data.data(), - data.length(), AsChars(p), packet_size); -} - -// Test that the IETF connectivity probing packet is serialized correctly as a -// padded PING packet, v99 only. -TEST_P(QuicFramerTest, BuildIetfConnectivityProbingPacket) { - if (framer_.transport_version() != QUIC_VERSION_99) { - return; - } - QuicPacketHeader header; - header.destination_connection_id = FramerTestConnectionId(); - header.reset_flag = false; - header.version_flag = false; - header.packet_number = kPacketNumber; - - unsigned char 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_PING frame) - 0x01, - // frame type (padding frame) - 0x00, 0x00, 0x00, 0x00, 0x00}; - // clang-format on - - unsigned char* p = packet99; - size_t packet_size = QUIC_ARRAYSIZE(packet99); - - std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); - - size_t length = framer_.BuildIetfConnectivityProbingPacket( - header, buffer.get(), packet_size); - - EXPECT_NE(0u, length); - QuicPacket data(buffer.release(), length, true, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); + QuicPacket data(buffer.release(), length, true, header); test::CompareCharArraysWithHexError("constructed packet", data.data(), data.length(), AsChars(p), packet_size); @@ -9722,17 +8614,15 @@ MockRandom randomizer; size_t length = framer_.BuildPaddedPathChallengePacket( - header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer); + header, buffer.get(), QUIC_ARRAYSIZE(packet), &payload, &randomizer, + ENCRYPTION_NONE); EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); // Payload has the random bytes that were generated. Copy them into packet, // above, before checking that the generated packet is correct. EXPECT_EQ(kQuicPathFrameBufferSize, payload.size()); - QuicPacket data(buffer.release(), length, true, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); + QuicPacket data(buffer.release(), length, true, header); test::CompareCharArraysWithHexError("constructed packet", data.data(), data.length(), AsChars(packet), @@ -9777,12 +8667,9 @@ payloads.push_back(payload0); size_t length = framer_.BuildPathResponsePacket( header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, - /*is_padded=*/false); + /*is_padded=*/false, ENCRYPTION_NONE); EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); - QuicPacket data(buffer.release(), length, true, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); + QuicPacket data(buffer.release(), length, true, header); test::CompareCharArraysWithHexError("constructed packet", data.data(), data.length(), AsChars(packet), @@ -9825,12 +8712,9 @@ payloads.push_back(payload0); size_t length = framer_.BuildPathResponsePacket( header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, - /*is_padded=*/true); + /*is_padded=*/true, ENCRYPTION_NONE); EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); - QuicPacket data(buffer.release(), length, true, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); + QuicPacket data(buffer.release(), length, true, header); test::CompareCharArraysWithHexError("constructed packet", data.data(), data.length(), AsChars(packet), @@ -9878,12 +8762,9 @@ payloads.push_back(payload2); size_t length = framer_.BuildPathResponsePacket( header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, - /*is_padded=*/false); + /*is_padded=*/false, ENCRYPTION_NONE); EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); - QuicPacket data(buffer.release(), length, true, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); + QuicPacket data(buffer.release(), length, true, header); test::CompareCharArraysWithHexError("constructed packet", data.data(), data.length(), AsChars(packet), @@ -9933,12 +8814,9 @@ payloads.push_back(payload2); size_t length = framer_.BuildPathResponsePacket( header, buffer.get(), QUIC_ARRAYSIZE(packet), payloads, - /*is_padded=*/true); + /*is_padded=*/true, ENCRYPTION_NONE); EXPECT_EQ(length, QUIC_ARRAYSIZE(packet)); - QuicPacket data(buffer.release(), length, true, - header.destination_connection_id_length, - header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); + QuicPacket data(buffer.release(), length, true, header); test::CompareCharArraysWithHexError("constructed packet", data.data(), data.length(), AsChars(packet), @@ -9962,18 +8840,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ping frame) - 0x07, - }; - - unsigned char packet39[] = { - // 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 (ping frame) @@ -9992,7 +8858,7 @@ 0x07, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -10023,12 +8889,10 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } test::CompareCharArraysWithHexError( @@ -10248,21 +9112,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // redundancy - 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x28, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // redundancy @@ -10287,7 +9136,7 @@ 'm', 'n', 'o', 'p', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -10321,18 +9170,17 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> raw(new QuicPacket( AsChars(p), QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER)); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); @@ -10352,23 +9200,6 @@ // version tag 'Q', '.', '1', '0', // packet number - 0x78, 0x56, 0x34, 0x12, - - // redundancy - 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', - }; - - unsigned char packet39[] = { - // public flags (version, 8 byte connection_id) - 0x29, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // version tag - 'Q', '.', '1', '0', - // packet number 0x12, 0x34, 0x56, 0x78, // redundancy @@ -10397,7 +9228,7 @@ 'm', 'n', 'o', 'p', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (long header with packet type ZERO_RTT_PROTECTED) 0xD3, // version tag @@ -10439,12 +9270,10 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } std::unique_ptr<QuicPacket> raw(new QuicPacket( @@ -10453,7 +9282,8 @@ : QUIC_ARRAYSIZE(packet), false, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, kIncludeVersion, !kIncludeDiversificationNonce, - PACKET_4BYTE_PACKET_NUMBER)); + PACKET_4BYTE_PACKET_NUMBER, VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + VARIABLE_LENGTH_INTEGER_LENGTH_0)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_NONE, packet_number, *raw, buffer, kMaxPacketSize); @@ -10594,43 +9424,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - - // frame type (ack frame) - 0x40, - // least packet number awaiting an ack - 0xA0, 0x9A, 0x78, 0x56, - 0x34, 0x12, - // largest observed packet number - 0xBF, 0x9A, 0x78, 0x56, - 0x34, 0x12, - // num missing packets - 0x01, - // missing packet - 0xBE, 0x9A, 0x78, 0x56, - 0x34, 0x12, - }; - - unsigned char packet39[] = { - // 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 (stream frame with fin) @@ -10699,7 +9492,7 @@ 0x9A, 0xBE, }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -10790,14 +9583,12 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); EXPECT_TRUE(framer_.ProcessPacket(encrypted)); @@ -10844,7 +9635,11 @@ EXPECT_CALL(visitor, OnDecryptedPacket(_)).Times(1); EXPECT_CALL(visitor, OnError(_)).Times(0); EXPECT_CALL(visitor, OnStreamFrame(_)).Times(0); - EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1); + if (framer_.version().transport_version < QUIC_VERSION_47) { + EXPECT_CALL(visitor, OnStreamFrame(Truly(ExpectedStreamFrame))).Times(1); + } else { + EXPECT_CALL(visitor, OnCryptoFrame(_)).Times(1); + } EXPECT_CALL(visitor, OnPacketComplete()).Times(1); EXPECT_TRUE(framer_.ProcessPacket(*packet)); @@ -10927,31 +9722,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - // private flags - 0x00, - - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0x3A, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x2C, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // private flags 0x00, @@ -10992,7 +9762,7 @@ 'r', 'l', 'd', '!', }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // packet number @@ -11038,12 +9808,10 @@ unsigned char* p = packet; if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicFramerFuzzFunc(p, framer_.transport_version() > QUIC_VERSION_43 @@ -11127,7 +9895,7 @@ header.packet_number = kPacketNumber; QuicBlockedFrame frame; - frame.stream_id = 0; + frame.stream_id = QuicUtils::GetInvalidStreamId(framer_.transport_version()); frame.offset = kStreamOffset; QuicFrames frames = {QuicFrame(&frame)}; @@ -11242,7 +10010,7 @@ QUIC_ARRAYSIZE(packet99)); } -TEST_P(QuicFramerTest, MaxStreamIdFrame) { +TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrame) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -11259,12 +10027,12 @@ // packet number {"", {0x12, 0x34, 0x9A, 0xBC}}, - // frame type (IETF_MAX_STREAM_ID) + // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) {"", {0x12}}, - // max. stream id - {"Can not read MAX_STREAM_ID stream id.", - {kVarInt62OneByte + 0x01}}, + // max. streams + {"Can not read MAX_STREAMS stream count.", + {kVarInt62OneByte + 0x03}}, }; // clang-format on @@ -11278,26 +10046,173 @@ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - EXPECT_EQ(0x1u, visitor_.max_stream_id_frame_.max_stream_id); - + // This test is a server receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a server-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) | 0x1 = 0x9 + // count-to-id server inited, bidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/true, 3), + visitor_.max_stream_id_frame_.max_stream_id); CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); } -TEST_P(QuicFramerTest, BuildMaxStreamIdPacket) { +TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrame) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; } - QuicPacketHeader header; - header.destination_connection_id = FramerTestConnectionId(); - header.reset_flag = false; - header.version_flag = false; - header.packet_number = kPacketNumber; + // clang-format off + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // Test runs in client mode, no connection id + // packet number + {"", + {0x12, 0x34, 0x9A, 0xBC}}, + // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) + {"", + {0x12}}, + // max. streams + {"Can not read MAX_STREAMS stream count.", + {kVarInt62OneByte + 0x03}}, + }; + // clang-format on - QuicMaxStreamIdFrame frame; - frame.max_stream_id = kTestQuicStreamId; - QuicFrames frames = {QuicFrame(frame)}; + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet99)); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a client receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a client-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) = 0xc + // It is not 8 because a client-initiated, bidi stream ID's + // low bits are 00 - which means that the old crypto stream + // falls into this category, and the first stream is streamid=4, + // not streamid=0. + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/true, 3), + visitor_.max_stream_id_frame_.max_stream_id); + + CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); +} + +TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrame) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x9A, 0xBC}}, + // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL) + {"", + {0x13}}, + // max. streams + {"Can not read MAX_STREAMS stream count.", + {kVarInt62OneByte + 0x03}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet99)); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a server receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a server-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) | 0x1 | 0x2 = 0xb + // count-to-id server inited, unidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/false, 3), + visitor_.max_stream_id_frame_.max_stream_id); + + CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); +} + +TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrame) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // Test runs in client mode, no connection id + // packet number + {"", + {0x12, 0x34, 0x9A, 0xBC}}, + // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL) + {"", + {0x13}}, + // max. streams + {"Can not read MAX_STREAMS stream count.", + {kVarInt62OneByte + 0x03}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet99)); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a client receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a client-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) | 0x02= 0xa + // count-to-id client/unidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/false, 3), + visitor_.max_stream_id_frame_.max_stream_id); + + CheckFramingBoundaries(packet99, QUIC_MAX_STREAM_ID_DATA); +} + +// The following four tests ensure that the framer can deserialize a stream +// count that is large enough to cause the resulting stream ID to exceed the +// current implementation limit(32 bits). The intent is that when this happens, +// the stream limit is pegged to the maximum supported value. There are four +// tests, for the four combinations of uni- and bi-directional, server- and +// client- initiated. +TEST_P(QuicFramerTest, ServerBiDiMaxStreamsFrameTooBig) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } // clang-format off unsigned char packet99[] = { @@ -11306,24 +10221,206 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x12, 0x34, 0x56, 0x78, - - // frame type (IETF_MAX_STREAM_ID frame) + 0x12, 0x34, 0x9A, 0xBC, + // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) 0x12, - // Max stream id - kVarInt62OneByte + 0x01 + + // max. streams. Max stream ID allowed is 0xffffffff + // This encodes a count of 0x40000000, leading to stream + // IDs in the range 0x1 00000000 to 0x1 00000003. + kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 }; // clang-format on - std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); - ASSERT_TRUE(data != nullptr); + QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), + false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet99), - QUIC_ARRAYSIZE(packet99)); + // This test is a server receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a server-initiated + // stream ID. The expected Stream ID is + // 0xfffffffc | 0x01 --> 0xfffffffd + // maxid server inited, bidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/true, 0x40000000), + visitor_.max_stream_id_frame_.max_stream_id); } -TEST_P(QuicFramerTest, StreamIdBlockedFrame) { +TEST_P(QuicFramerTest, ClientBiDiMaxStreamsFrameTooBig) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x43, + // Test runs in client mode, no connection id + // packet number + 0x12, 0x34, 0x9A, 0xBC, + // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) + 0x12, + + // max. streams. Max stream ID allowed is 0xffffffff + // This encodes a count of 0x40000000, leading to stream + // IDs in the range 0x1 00000000 to 0x1 00000003. + kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), + false); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a client receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a client-initiated + // stream ID. The expected Stream ID is + // 0xfffffffc --> 0xfffffffc + // max id bidi/client-inited + // TODO(fkastenholz): Change -2 to -1 when stream id 0 is no longer + // special. + // Subtract 1 because client/bidi stream ids start counting at + // 4, not 0. If we didn;t subtract 1, the resulting math would wrap to stream + // id 0, not 0xfffffffc. + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/true, (0x40000000 - 1)), + visitor_.max_stream_id_frame_.max_stream_id); +} + +TEST_P(QuicFramerTest, ServerUniDiMaxStreamsFrameTooBig) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x43, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x9A, 0xBC, + // frame type (IETF_MAX_STREAMS_UNIDIRECTIONAL) + 0x13, + + // max. streams. Max stream ID allowed is 0xffffffff + // This encodes a count of 0x40000000, leading to stream + // IDs in the range 0x1 00000000 to 0x1 00000003. + kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), + false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a server receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a server-initiated + // stream ID. The expected Stream ID is + // 0xfffffffc | 0x1 | 0x2 = 0xffffffff + // maxid server inited, unidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/false, 0x40000000), + visitor_.max_stream_id_frame_.max_stream_id); +} + +TEST_P(QuicFramerTest, ClientUniDiMaxStreamsFrameTooBig) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x43, + // Test runs in client mode, no connection id + // packet number + 0x12, 0x34, 0x9A, 0xBC, + // frame type (IETF_MAX_STREAMS_UNDIRECTIONAL) + 0x13, + + // max. streams. Max stream ID allowed is 0xffffffff + // This encodes a count of 0x40000000, leading to stream + // IDs in the range 0x1 00000000 to 0x1 00000003. + kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), + false); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a client receiving a MAX_STREAMS frame. The + // stream ID that it generates should be a client-initiated + // stream ID. The expected Stream ID is + // 0xfffffffc | 0x02= 0xfffffffe + // maxid client/unidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/false, 0x40000000), + visitor_.max_stream_id_frame_.max_stream_id); +} + +// Check that a stream count of 0 is rejected. +// Directionality and intiation are not important for +// this test. +TEST_P(QuicFramerTest, MaxStreamsFrameZeroCount) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x43, + // connection_id + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // packet number + 0x12, 0x34, 0x9A, 0xBC, + // frame type (IETF_MAX_STREAMS_BIDIRECTIONAL) + 0x12, + // max. streams == 0. + kVarInt62OneByte + 0x00 + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), + false); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + EXPECT_EQ(QUIC_MAX_STREAM_ID_DATA, framer_.error()); + EXPECT_EQ(framer_.detailed_error(), + "MAX_STREAMS stream count of 0 not supported."); +} + +TEST_P(QuicFramerTest, ServerBiDiStreamsBlockedFrame) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -11340,12 +10437,12 @@ // packet number {"", {0x12, 0x34, 0x9A, 0xBC}}, - // frame type (IETF_STREAM_ID_BLOCKED frame) + // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) {"", {0x16}}, // stream id - {"Can not read STREAM_ID_BLOCKED stream id.", - {kVarInt62OneByte + 0x01}}, + {"Can not read STREAMS_BLOCKED stream id.", + {kVarInt62OneByte + 0x03}}, }; // clang-format on @@ -11359,12 +10456,234 @@ *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); - EXPECT_EQ(0x1u, visitor_.stream_id_blocked_frame_.stream_id); + // This test is a server receiving a STREAMS_BLOCKED frame. The + // stream ID that it generates should be a client-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) = 0xc + // count-to-id client inited, bidi + // It is not 8 because a client-initiated, bidi stream ID's + // low bits are 00 - which means that the old crypto stream + // falls into this category, and the first stream is streamid=4, + // not streamid=0. + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/true, 3), + visitor_.stream_id_blocked_frame_.stream_id); CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); } -TEST_P(QuicFramerTest, BuildStreamIdBlockedPacket) { +TEST_P(QuicFramerTest, ClientBiDiStreamsBlockedFrame) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // Test runs in client mode, no connection id + // packet number + {"", + {0x12, 0x34, 0x9A, 0xBC}}, + // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) + {"", + {0x16}}, + // stream id + {"Can not read STREAMS_BLOCKED stream id.", + {kVarInt62OneByte + 0x03}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet99)); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a client receiving a STREAMS_BLOCKED frame. The + // stream ID that it generates should be a server-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) | 0x01 = 0x9 + // count-to-id server inited, bidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/true, 3), + visitor_.stream_id_blocked_frame_.stream_id); + + CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); +} + +TEST_P(QuicFramerTest, ServerUniDiStreamsBlockedFrame) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // connection_id + {"", + {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10}}, + // packet number + {"", + {0x12, 0x34, 0x9A, 0xBC}}, + // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) + {"", + {0x17}}, + // stream id + {"Can not read STREAMS_BLOCKED stream id.", + {kVarInt62OneByte + 0x03}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet99)); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a server receiving a STREAMS_BLOCKED frame. The + // stream ID that it generates should be a client-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) | 0x2 = 0xa + // count-to-id client inited, unidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/false, 3), + visitor_.stream_id_blocked_frame_.stream_id); + + CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); +} + +TEST_P(QuicFramerTest, ClientUniDiStreamsBlockedFrame) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + PacketFragments packet99 = { + // type (short header, 4 byte packet number) + {"", + {0x43}}, + // Test runs in client mode, no connection id + // packet number + {"", + {0x12, 0x34, 0x9A, 0xBC}}, + // frame type (IETF_STREAMS_BLOCKED_UNIDIRECTIONAL frame) + {"", + {0x17}}, + // stream id + {"Can not read STREAMS_BLOCKED stream id.", + {kVarInt62OneByte + 0x03}}, + }; + // clang-format on + + std::unique_ptr<QuicEncryptedPacket> encrypted( + AssemblePacketFromFragments(packet99)); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_TRUE(framer_.ProcessPacket(*encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + EXPECT_TRUE(CheckDecryption( + *encrypted, !kIncludeVersion, !kIncludeDiversificationNonce, + PACKET_0BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID)); + + // This test is a client receiving a STREAMS_BLOCKED frame. The + // stream ID that it generates should be a server-initiated + // stream ID. The expected Stream ID is + // ((0x3-1) * 4) | 0x01 | 0x2 = 0xb + // count-to-id server inited, bidi + EXPECT_EQ(GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/false, 3), + visitor_.stream_id_blocked_frame_.stream_id); + + CheckFramingBoundaries(packet99, QUIC_STREAM_ID_BLOCKED_DATA); +} + +// Check that when we get a STREAMS_BLOCKED frame that specifies too large +// a stream count, we reject with an appropriate error. There is no need to +// check for different combinations of Uni/Bi directional and client/server +// initiated; the logic does not take these into account. +TEST_P(QuicFramerTest, StreamsBlockedFrameTooBig) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x43, + // Test runs in client mode, no connection id + // packet number + 0x12, 0x34, 0x9A, 0xBC, + // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL) + 0x17, + + // max. streams. Max stream ID allowed is 0xffffffff + // This encodes a count of 0x40000000, leading to stream + // IDs in the range 0x1 00000000 to 0x1 00000003. + kVarInt62EightBytes + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01 + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), + false); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error()); + EXPECT_EQ(framer_.detailed_error(), + "STREAMS_BLOCKED stream count exceeds implementation limit."); +} + +// Test that count==0 is rejected. +TEST_P(QuicFramerTest, StreamsBlockedFrameZeroCount) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // clang-format off + unsigned char packet99[] = { + // type (short header, 4 byte packet number) + 0x43, + // Test runs in client mode, no connection id + // packet number + 0x12, 0x34, 0x9A, 0xBC, + // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL) + 0x17, + + // max. streams = 0 + kVarInt62OneByte + 0x00 + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet99), QUIC_ARRAYSIZE(packet99), + false); + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + EXPECT_FALSE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_STREAM_ID_BLOCKED_DATA, framer_.error()); + EXPECT_EQ(framer_.detailed_error(), + "STREAMS_BLOCKED stream count 0 not supported."); +} + +TEST_P(QuicFramerTest, BuildServerBiDiStreamsBlockedPacket) { // This test only for version 99. if (framer_.transport_version() != QUIC_VERSION_99) { return; @@ -11377,7 +10696,13 @@ header.packet_number = kPacketNumber; QuicStreamIdBlockedFrame frame; - frame.stream_id = kTestQuicStreamId; + // A server building a STREAMS_BLOCKED frame generates + // a server-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 01 + // Expected value is 0x8u | 0x1u; + frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/true, 3); + QuicFrames frames = {QuicFrame(frame)}; // clang-format off @@ -11389,10 +10714,332 @@ // packet number 0x12, 0x34, 0x56, 0x78, - // frame type (IETF_STREAM_ID_BLOCKED frame) + // frame type (IETF_STREAMS_BLOCKED_BIDIRECTIONAL frame) 0x16, - // Max stream id - kVarInt62OneByte + 0x01 + // Stream count + kVarInt62OneByte + 0x03 + }; + // clang-format on + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet99), + QUIC_ARRAYSIZE(packet99)); +} + +TEST_P(QuicFramerTest, BuildClientBiDiStreamsBlockedPacket) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // This test runs in client mode. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicStreamIdBlockedFrame frame; + // A client building a STREAMS_BLOCKED frame generates + // a client-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 00. Expected value is 0x8 + frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/true, 3); + QuicFrames frames = {QuicFrame(frame)}; + + // clang-format off + unsigned char 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_STREAMS_BLOCKED_BIDIRECTIONAL frame) + 0x16, + // Stream count + kVarInt62OneByte + 0x03 + }; + // clang-format on + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet99), + QUIC_ARRAYSIZE(packet99)); +} + +TEST_P(QuicFramerTest, BuildServerUniStreamsBlockedPacket) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicStreamIdBlockedFrame frame; + // A server building a STREAMS_BLOCKED frame generates + // a server-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 11. Expected value is 0xb + frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/false, 3); + QuicFrames frames = {QuicFrame(frame)}; + + // clang-format off + unsigned char 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_STREAMS_BLOCKED_UNIDIRECTIONAL frame) + 0x17, + // Stream count + kVarInt62OneByte + 0x03 + }; + // clang-format on + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet99), + QUIC_ARRAYSIZE(packet99)); +} + +TEST_P(QuicFramerTest, BuildClientUniDiStreamsBlockedPacket) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // This test runs in client mode. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicStreamIdBlockedFrame frame; + // A client building a STREAMS_BLOCKED frame generates + // a client-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 10. Expected value is 0xa + frame.stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/false, 3); + QuicFrames frames = {QuicFrame(frame)}; + + // clang-format off + unsigned char 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_STREAMS_BLOCKED_UNIDIRECTIONAL frame) + 0x17, + // Stream count + kVarInt62OneByte + 0x03 + }; + // clang-format on + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet99), + QUIC_ARRAYSIZE(packet99)); +} + +TEST_P(QuicFramerTest, BuildServerBiDiMaxStreamsPacket) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicMaxStreamIdFrame frame; + // A server building a MAX_STREAMS frame generates + // a client-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 00. Expected value is 0xc + // because streamid==0 is special and the first client/bidi + // stream is 4, not 0. + frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/true, 3); + QuicFrames frames = {QuicFrame(frame)}; + + // clang-format off + unsigned char 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_MAX_STREAMS_BIDIRECTIONAL frame) + 0x12, + // Stream count + kVarInt62OneByte + 0x03 + }; + // clang-format on + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet99), + QUIC_ARRAYSIZE(packet99)); +} + +TEST_P(QuicFramerTest, BuildClientBiDiMaxStreamsPacket) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // This test runs in client mode. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicMaxStreamIdFrame frame; + // A client building a MAX_STREAMS frame generates + // a server-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 01. Expected value is 0x9 + frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/true, 3); + QuicFrames frames = {QuicFrame(frame)}; + + // clang-format off + unsigned char 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_MAX_STREAMS_BIDIRECTIONAL frame) + 0x12, + // Stream count + kVarInt62OneByte + 0x03 + }; + // clang-format on + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet99), + QUIC_ARRAYSIZE(packet99)); +} + +TEST_P(QuicFramerTest, BuildServerUniMaxStreamsPacket) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicMaxStreamIdFrame frame; + // A server building a MAX_STREAMS frame generates + // a client-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 10. Expected value is 0xa + frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_CLIENT, + /*bidirectional=*/false, 3); + QuicFrames frames = {QuicFrame(frame)}; + + // clang-format off + unsigned char 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_MAX_STREAMS_UNIDIRECTIONAL frame) + 0x13, + // Stream count + kVarInt62OneByte + 0x03 + }; + // clang-format on + + std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); + ASSERT_TRUE(data != nullptr); + + test::CompareCharArraysWithHexError("constructed packet", data->data(), + data->length(), AsChars(packet99), + QUIC_ARRAYSIZE(packet99)); +} + +TEST_P(QuicFramerTest, BuildClientUniDiMaxStreamsPacket) { + // This test only for version 99. + if (framer_.transport_version() != QUIC_VERSION_99) { + return; + } + + // This test runs in client mode. + QuicFramerPeer::SetPerspective(&framer_, Perspective::IS_CLIENT); + + QuicPacketHeader header; + header.destination_connection_id = FramerTestConnectionId(); + header.reset_flag = false; + header.version_flag = false; + header.packet_number = kPacketNumber; + + QuicMaxStreamIdFrame frame; + // A client building a MAX_STREAMS frame generates + // a server-initiated stream ID. This test is bidirectional. + // The low two bits of the stream ID are 11. Expected value is 0xb + frame.max_stream_id = GetNthStreamid(QUIC_VERSION_99, Perspective::IS_SERVER, + /*bidirectional=*/false, 3); + QuicFrames frames = {QuicFrame(frame)}; + + // clang-format off + unsigned char 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_MAX_STREAMS_UNIDIRECTIONAL frame) + 0x13, + // Stream count + kVarInt62OneByte + 0x03 }; // clang-format on @@ -11901,14 +11548,14 @@ framer_.transport_version(), QuicFrame(&new_connection_id))); QuicMaxStreamIdFrame max_stream_id(6, 3); - EXPECT_EQ(QuicFramer::GetMaxStreamIdFrameSize(framer_.transport_version(), - max_stream_id), + EXPECT_EQ(QuicFramer::GetMaxStreamsFrameSize(framer_.transport_version(), + max_stream_id), QuicFramer::GetRetransmittableControlFrameSize( framer_.transport_version(), QuicFrame(max_stream_id))); QuicStreamIdBlockedFrame stream_id_blocked(7, 3); - EXPECT_EQ(QuicFramer::GetStreamIdBlockedFrameSize(framer_.transport_version(), - stream_id_blocked), + EXPECT_EQ(QuicFramer::GetStreamsBlockedFrameSize(framer_.transport_version(), + stream_id_blocked), QuicFramer::GetRetransmittableControlFrameSize( framer_.transport_version(), QuicFrame(stream_id_blocked))); @@ -12658,26 +12305,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ack frame) - 0x45, - // largest observed - 0x00, 0x00, - // Zero delta time. - 0x00, 0x00, - // first ack block length. - 0x00, 0x00, - // num timestamps. - 0x00 - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x2C, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) @@ -12712,7 +12339,7 @@ 0x00 }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -12758,21 +12385,14 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); - if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) && - framer_.transport_version() != QUIC_VERSION_99) { - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - return; - } EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(framer_.detailed_error(), "Largest acked is 0."); } @@ -12785,26 +12405,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ack frame) - 0x45, - // largest observed - 0x02, 0x00, - // Zero delta time. - 0x00, 0x00, - // first ack block length. - 0x03, 0x00, - // num timestamps. - 0x00 - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x2C, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) @@ -12839,7 +12439,7 @@ 0x00 }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -12885,22 +12485,15 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); - if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) && - framer_.transport_version() != QUIC_VERSION_99) { - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - return; - } EXPECT_FALSE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(framer_.detailed_error(), "Underflow with first ack block length 3 largest acked is 2."); @@ -12914,36 +12507,6 @@ // connection_id 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, // packet number - 0x78, 0x56, 0x34, 0x12, - - // frame type (ack frame) - 0x60, - // largest observed - 0x0A, - // Zero delta time. - 0x00, 0x00, - // Num of ack blocks - 0x02, - // first ack block length. - 0x02, - // gap to next block - 0x01, - // ack block length - 0x01, - // gap to next block - 0x01, - // ack block length - 0x06, - // num timestamps. - 0x00 - }; - - unsigned char packet39[] = { - // public flags (8 byte connection_id) - 0x2C, - // connection_id - 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, - // packet number 0x12, 0x34, 0x56, 0x78, // frame type (ack frame) @@ -12998,7 +12561,7 @@ 0x00 }; - unsigned char packet47[] = { + unsigned char packet46[] = { // type (short header, 4 byte packet number) 0x43, // connection_id @@ -13062,22 +12625,15 @@ if (framer_.transport_version() == QUIC_VERSION_99) { p = packet99; p_size = QUIC_ARRAYSIZE(packet99); - } else if (framer_.transport_version() > QUIC_VERSION_46) { - p = packet47; - p_size = QUIC_ARRAYSIZE(packet47); + } else if (framer_.transport_version() > QUIC_VERSION_44) { + p = packet46; + p_size = QUIC_ARRAYSIZE(packet46); } else if (framer_.transport_version() > QUIC_VERSION_43) { p = packet44; p_size = QUIC_ARRAYSIZE(packet44); - } else if (framer_.transport_version() != QUIC_VERSION_35) { - p = packet39; } QuicEncryptedPacket encrypted(AsChars(p), p_size, false); - if (!GetQuicReloadableFlag(quic_disallow_peer_ack_0) && - framer_.transport_version() != QUIC_VERSION_99) { - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - return; - } EXPECT_FALSE(framer_.ProcessPacket(encrypted)); if (framer_.transport_version() == QUIC_VERSION_99) { EXPECT_EQ(framer_.detailed_error(), @@ -13088,6 +12644,242 @@ } } +TEST_P(QuicFramerTest, CoalescedPacket) { + if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { + return; + } + // clang-format off + unsigned char packet[] = { + // first coalesced packet + // public flags (long header with packet type ZERO_RTT_PROTECTED and + // 4-byte packet number) + 0xD3, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x50, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x1E, + // packet number + 0x12, 0x34, 0x56, 0x78, + // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) + 0x08 | 0x01 | 0x02 | 0x04, + // stream id + kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, + // offset + kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + kVarInt62OneByte + 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + // second coalesced packet + // public flags (long header with packet type ZERO_RTT_PROTECTED and + // 4-byte packet number) + 0xD3, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x50, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x1E, + // packet number + 0x12, 0x34, 0x56, 0x79, + // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) + 0x08 | 0x01 | 0x02 | 0x04, + // stream id + kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, + // offset + kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + kVarInt62OneByte + 0x0c, + // data + 'H', 'E', 'L', 'L', + 'O', '_', 'W', 'O', + 'R', 'L', 'D', '?', + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_TRUE(framer_.ProcessPacket(encrypted)); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + + ASSERT_EQ(1u, visitor_.stream_frames_.size()); + EXPECT_EQ(0u, visitor_.ack_frames_.size()); + + // Stream ID should be the last 3 bytes of kStreamId. + EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); + EXPECT_TRUE(visitor_.stream_frames_[0]->fin); + EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); + CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); + + ASSERT_EQ(visitor_.coalesced_packets_.size(), 1); + EXPECT_TRUE(framer_.ProcessPacket(*visitor_.coalesced_packets_[0].get())); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + + ASSERT_EQ(2u, visitor_.stream_frames_.size()); + EXPECT_EQ(0u, visitor_.ack_frames_.size()); + + // Stream ID should be the last 3 bytes of kStreamId. + EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[1]->stream_id); + EXPECT_TRUE(visitor_.stream_frames_[1]->fin); + EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[1]->offset); + CheckStreamFrameData("HELLO_WORLD?", visitor_.stream_frames_[1].get()); +} + +TEST_P(QuicFramerTest, MismatchedCoalescedPacket) { + if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { + return; + } + // clang-format off + unsigned char packet[] = { + // first coalesced packet + // public flags (long header with packet type ZERO_RTT_PROTECTED and + // 4-byte packet number) + 0xD3, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x50, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x1E, + // packet number + 0x12, 0x34, 0x56, 0x78, + // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) + 0x08 | 0x01 | 0x02 | 0x04, + // stream id + kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, + // offset + kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + kVarInt62OneByte + 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + // second coalesced packet + // public flags (long header with packet type ZERO_RTT_PROTECTED and + // 4-byte packet number) + 0xD3, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x50, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x11, + // long header packet length + 0x1E, + // packet number + 0x12, 0x34, 0x56, 0x79, + // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) + 0x08 | 0x01 | 0x02 | 0x04, + // stream id + kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, + // offset + kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + kVarInt62OneByte + 0x0c, + // data + 'H', 'E', 'L', 'L', + 'O', '_', 'W', 'O', + 'R', 'L', 'D', '?', + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), + "Server: Received mismatched coalesced header.*"); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + + ASSERT_EQ(1u, visitor_.stream_frames_.size()); + EXPECT_EQ(0u, visitor_.ack_frames_.size()); + + // Stream ID should be the last 3 bytes of kStreamId. + EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); + EXPECT_TRUE(visitor_.stream_frames_[0]->fin); + EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); + CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); + + ASSERT_EQ(visitor_.coalesced_packets_.size(), 0); +} + +TEST_P(QuicFramerTest, InvalidCoalescedPacket) { + if (!QuicVersionHasLongHeaderLengths(framer_.transport_version())) { + return; + } + // clang-format off + unsigned char packet[] = { + // first coalesced packet + // public flags (long header with packet type ZERO_RTT_PROTECTED and + // 4-byte packet number) + 0xD3, + // version + QUIC_VERSION_BYTES, + // destination connection ID length + 0x50, + // destination connection ID + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, + // long header packet length + 0x1E, + // packet number + 0x12, 0x34, 0x56, 0x78, + // frame type (IETF_STREAM frame with FIN, LEN, and OFFSET bits set) + 0x08 | 0x01 | 0x02 | 0x04, + // stream id + kVarInt62FourBytes + 0x00, 0x02, 0x03, 0x04, + // offset + kVarInt62EightBytes + 0x3A, 0x98, 0xFE, 0xDC, + 0x32, 0x10, 0x76, 0x54, + // data length + kVarInt62OneByte + 0x0c, + // data + 'h', 'e', 'l', 'l', + 'o', ' ', 'w', 'o', + 'r', 'l', 'd', '!', + // second coalesced packet + // public flags (long header with packet type ZERO_RTT_PROTECTED and + // 4-byte packet number) + 0xD3, + // version would be here but we cut off the invalid coalesced header. + }; + // clang-format on + + QuicEncryptedPacket encrypted(AsChars(packet), QUIC_ARRAYSIZE(packet), false); + EXPECT_QUIC_PEER_BUG(EXPECT_TRUE(framer_.ProcessPacket(encrypted)), + "Server: Failed to parse received coalesced header.*"); + + EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); + ASSERT_TRUE(visitor_.header_.get()); + + ASSERT_EQ(1u, visitor_.stream_frames_.size()); + EXPECT_EQ(0u, visitor_.ack_frames_.size()); + + // Stream ID should be the last 3 bytes of kStreamId. + EXPECT_EQ(0x00FFFFFF & kStreamId, visitor_.stream_frames_[0]->stream_id); + EXPECT_TRUE(visitor_.stream_frames_[0]->fin); + EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); + CheckStreamFrameData("hello world!", visitor_.stream_frames_[0].get()); + + ASSERT_EQ(visitor_.coalesced_packets_.size(), 0); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_ietf_framer_test.cc b/quic/core/quic_ietf_framer_test.cc index d35800a..100fe8d 100644 --- a/quic/core/quic_ietf_framer_test.cc +++ b/quic/core/quic_ietf_framer_test.cc
@@ -45,9 +45,12 @@ namespace { const size_t kNormalPacketBufferSize = 1400; -// several different stream ids, should be encoded +// Several different stream ids, should be encoded // in 8, 4, 2, and 1 byte, respectively. Last one // checks that value==0 works. +// All stream IDs end in 0x0, so the client/server- initiated +// and Uni/Bi-directional bits are available to alter, as any +// given test may wish. const QuicIetfStreamId kStreamId8 = UINT64_C(0x3EDCBA9876543210); const QuicIetfStreamId kStreamId4 = UINT64_C(0x36543210); const QuicIetfStreamId kStreamId2 = UINT64_C(0x3210); @@ -110,6 +113,8 @@ bool OnPacketHeader(const QuicPacketHeader& header) override { return true; } + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {} + bool OnStreamFrame(const QuicStreamFrame& frame) override { return true; } bool OnCryptoFrame(const QuicCryptoFrame& frame) override { return true; } @@ -452,6 +457,129 @@ EXPECT_EQ(receive_frame.byte_offset, transmit_frame.byte_offset); } + void TryMaxStreamsFrame(QuicStreamId stream_id, + bool unidirectional, + bool stream_id_server_initiated) { + if (!unidirectional && !stream_id_server_initiated && stream_id == 0) { + // For bidirectional, client initiated, streams, 0 is not allowed, + // it's used for the crypto stream and is not included in the counting. + return; + } + + char packet_buffer[kNormalPacketBufferSize]; + memset(packet_buffer, 0, sizeof(packet_buffer)); + + Perspective old_perspective = framer_.perspective(); + // Set up the writer and transmit QuicMaxStreamIdFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + if (stream_id_server_initiated) { + stream_id |= 0x01; + } + if (unidirectional) { + stream_id |= 0x02; + } + + // Set the perspective of the sender. If the stream id is supposed to + // be server-initiated, then the sender of the MAX_STREAMS should be + // a client, and vice versa. Do this prior to constructing the frame or + // generating the packet, so that any internal dependencies are satisfied. + QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated) + ? Perspective::IS_CLIENT + : Perspective::IS_SERVER); + QuicMaxStreamIdFrame transmit_frame(0, stream_id); + + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendMaxStreamsFrame(&framer_, transmit_frame, + &writer)); + + // Check that buffer length is in the expected range + EXPECT_LE(1u, writer.length()); + EXPECT_GE(8u, writer.length()); + + // Set the perspective for the receiver. + QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated) + ? Perspective::IS_SERVER + : Perspective::IS_CLIENT); + + // Set up reader and empty receive QuicPaddingFrame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicMaxStreamIdFrame receive_frame; + + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessMaxStreamsFrame( + &framer_, &reader, &receive_frame, + (unidirectional) ? IETF_MAX_STREAMS_UNIDIRECTIONAL + : IETF_MAX_STREAMS_BIDIRECTIONAL)) + << " Error: " << framer_.detailed_error(); + + // Now check that received and sent data are equivalent + EXPECT_EQ(stream_id, receive_frame.max_stream_id); + EXPECT_EQ(transmit_frame.max_stream_id, receive_frame.max_stream_id); + QuicFramerPeer::SetPerspective(&framer_, old_perspective); + } + + void TryStreamsBlockedFrame(QuicStreamId stream_id, + bool unidirectional, + bool stream_id_server_initiated) { + if (!unidirectional && !stream_id_server_initiated && stream_id == 0) { + // For bidirectional, client initiated, streams, 0 is not allowed, + // it's used for the crypto stream and is not included in the counting. + return; + } + + char packet_buffer[kNormalPacketBufferSize]; + memset(packet_buffer, 0, sizeof(packet_buffer)); + + Perspective old_perspective = framer_.perspective(); + // Set up the writer and transmit QuicMaxStreamIdFrame + QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, + NETWORK_BYTE_ORDER); + if (stream_id_server_initiated) { + stream_id |= 0x01; + } + if (unidirectional) { + stream_id |= 0x02; + } + + // Set the perspective of the sender. If the stream id is supposed to + // be server-initiated, then the sender of the MAX_STREAMS should be + // a client, and vice versa. Do this prior to constructing the frame or + // generating the packet, so that any internal dependencies are satisfied. + QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated) + ? Perspective::IS_SERVER + : Perspective::IS_CLIENT); + QuicStreamIdBlockedFrame transmit_frame(0, stream_id); + + // Add the frame. + EXPECT_TRUE(QuicFramerPeer::AppendStreamsBlockedFrame( + &framer_, transmit_frame, &writer)); + + // Check that buffer length is in the expected range + EXPECT_LE(1u, writer.length()); + EXPECT_GE(8u, writer.length()); + + // Set the perspective for the receiver. + QuicFramerPeer::SetPerspective(&framer_, (stream_id_server_initiated) + ? Perspective::IS_CLIENT + : Perspective::IS_SERVER); + + // Set up reader and empty receive QuicPaddingFrame. + QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); + QuicStreamIdBlockedFrame receive_frame; + + // Deframe it + EXPECT_TRUE(QuicFramerPeer::ProcessStreamsBlockedFrame( + &framer_, &reader, &receive_frame, + (unidirectional) ? IETF_STREAMS_BLOCKED_UNIDIRECTIONAL + : IETF_STREAMS_BLOCKED_BIDIRECTIONAL)); + + // Now check that received and sent data are equivalent + EXPECT_EQ(stream_id, receive_frame.stream_id); + EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); + QuicFramerPeer::SetPerspective(&framer_, old_perspective); + } + QuicTime start_; QuicFramer framer_; test::TestQuicVisitor visitor_; @@ -1082,7 +1210,8 @@ // Now check that the received data equals the sent data. EXPECT_EQ(transmit_frame.byte_offset, window_size); EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset); - EXPECT_EQ(0u, receive_frame.stream_id); + EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()), + receive_frame.stream_id); } } @@ -1128,38 +1257,21 @@ } } -TEST_F(QuicIetfFramerTest, MaxStreamIdFrame) { - char packet_buffer[kNormalPacketBufferSize]; +TEST_F(QuicIetfFramerTest, MaxStreamsFrame) { QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, kStreamId0}; for (QuicIetfStreamId stream_id : stream_ids) { - memset(packet_buffer, 0, sizeof(packet_buffer)); - - // Set up the writer and transmit QuicMaxStreamIdFrame - QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); - QuicMaxStreamIdFrame transmit_frame(0, stream_id); - - // Add the frame. - EXPECT_TRUE(QuicFramerPeer::AppendMaxStreamIdFrame(&framer_, transmit_frame, - &writer)); - - // Check that buffer length is in the expected range - EXPECT_LE(1u, writer.length()); - EXPECT_GE(8u, writer.length()); - - // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); - QuicMaxStreamIdFrame receive_frame; - - // Deframe it - EXPECT_TRUE(QuicFramerPeer::ProcessMaxStreamIdFrame(&framer_, &reader, - &receive_frame)); - - // Now check that received and sent data are equivalent - EXPECT_EQ(stream_id, receive_frame.max_stream_id); - EXPECT_EQ(transmit_frame.max_stream_id, receive_frame.max_stream_id); + // Cover all four combinations of uni/bi-directional and + // server-/client- initiation. + TryMaxStreamsFrame(stream_id, /*unidirectional=*/true, + /*stream_id_server_initiated=*/true); + TryMaxStreamsFrame(stream_id, /*unidirectional=*/true, + /*stream_id_server_initiated=*/false); + TryMaxStreamsFrame(stream_id, /*unidirectional=*/false, + /*stream_id_server_initiated=*/true); + TryMaxStreamsFrame(stream_id, /*unidirectional=*/false, + /*stream_id_server_initiated=*/false); } } @@ -1174,7 +1286,8 @@ // Set up the writer and transmit QuicBlockedFrame QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, NETWORK_BYTE_ORDER); - QuicBlockedFrame transmit_frame(0, 0, offset); + QuicBlockedFrame transmit_frame( + 0, QuicUtils::GetInvalidStreamId(framer_.transport_version()), offset); // Add the frame. EXPECT_TRUE(QuicFramerPeer::AppendIetfBlockedFrame(&framer_, transmit_frame, @@ -1193,7 +1306,8 @@ &receive_frame)); // Check that received and sent data are equivalent - EXPECT_EQ(0u, receive_frame.stream_id); + EXPECT_EQ(QuicUtils::GetInvalidStreamId(framer_.transport_version()), + receive_frame.stream_id); EXPECT_EQ(offset, receive_frame.offset); EXPECT_EQ(transmit_frame.offset, receive_frame.offset); } @@ -1241,38 +1355,23 @@ } } -TEST_F(QuicIetfFramerTest, StreamIdBlockedFrame) { - char packet_buffer[kNormalPacketBufferSize]; +TEST_F(QuicIetfFramerTest, StreamsBlockedFrame) { QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, kStreamId0}; for (QuicIetfStreamId stream_id : stream_ids) { - memset(packet_buffer, 0, sizeof(packet_buffer)); - - // Set up the writer and transmit QuicStreamIdBlockedFrame - QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, - NETWORK_BYTE_ORDER); - QuicStreamIdBlockedFrame transmit_frame(0, stream_id); - - // Add the frame. - EXPECT_TRUE(QuicFramerPeer::AppendStreamIdBlockedFrame( - &framer_, transmit_frame, &writer)); - - // Check that buffer length is in the expected range - EXPECT_LE(1u, writer.length()); - EXPECT_GE(8u, writer.length()); - - // Set up reader and empty receive QuicPaddingFrame. - QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); - QuicStreamIdBlockedFrame receive_frame; - - // Deframe it - EXPECT_TRUE(QuicFramerPeer::ProcessStreamIdBlockedFrame(&framer_, &reader, - &receive_frame)); - - // Now check that received == sent - EXPECT_EQ(stream_id, receive_frame.stream_id); - EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); + TryStreamsBlockedFrame(stream_id, + /*unidirectional=*/false, + /*stream_id_server_initiated=*/false); + TryStreamsBlockedFrame(stream_id, + /*unidirectional=*/false, + /*stream_id_server_initiated=*/true); + TryStreamsBlockedFrame(stream_id, + /*unidirectional=*/true, + /*stream_id_server_initiated=*/false); + TryStreamsBlockedFrame(stream_id, + /*unidirectional=*/true, + /*stream_id_server_initiated=*/true); } }
diff --git a/quic/core/quic_interval.h b/quic/core/quic_interval.h new file mode 100644 index 0000000..d5bf171 --- /dev/null +++ b/quic/core/quic_interval.h
@@ -0,0 +1,379 @@ +// 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_QUIC_CORE_QUIC_INTERVAL_H_ +#define QUICHE_QUIC_CORE_QUIC_INTERVAL_H_ + +// An QuicInterval<T> is a data structure used to represent a contiguous, +// mutable range over an ordered type T. Supported operations include testing a +// value to see whether it is included in the QuicInterval, comparing two +// QuicIntervals, and performing their union, intersection, and difference. For +// the purposes of this library, an "ordered type" is any type that induces a +// total order on its values via its less-than operator (operator<()). Examples +// of such types are basic arithmetic types like int and double as well as class +// types like string. +// +// An QuicInterval<T> is represented using the usual C++ STL convention, namely +// as the half-open QuicInterval [min, max). A point p is considered to be +// contained in the QuicInterval iff p >= min && p < max. One consequence of +// this definition is that for any non-empty QuicInterval, min is contained in +// the QuicInterval but max is not. There is no canonical representation for the +// empty QuicInterval; rather, any QuicInterval where max <= min is regarded as +// empty. As a consequence, two empty QuicIntervals will still compare as equal +// despite possibly having different underlying min() or max() values. Also +// beware of the terminology used here: the library uses the terms "min" and +// "max" rather than "begin" and "end" as is conventional for the STL. +// +// T is required to be default- and copy-constructable, to have an assignment +// operator, and the full complement of comparison operators (<, <=, ==, !=, >=, +// >). A difference operator (operator-()) is required if +// QuicInterval<T>::Length is used. +// +// QuicInterval supports operator==. Two QuicIntervals are considered equal if +// either they are both empty or if their corresponding min and max fields +// compare equal. QuicInterval also provides an operator<. Unfortunately, +// operator< is currently buggy because its behavior is inconsistent with +// operator==: two empty ranges with different representations may be regarded +// as equal by operator== but regarded as different by operator<. Bug 9240050 +// has been created to address this. +// +// +// Examples: +// QuicInterval<int> r1(0, 100); // The QuicInterval [0, 100). +// EXPECT_TRUE(r1.Contains(0)); +// EXPECT_TRUE(r1.Contains(50)); +// EXPECT_FALSE(r1.Contains(100)); // 100 is just outside the QuicInterval. +// +// QuicInterval<int> r2(50, 150); // The QuicInterval [50, 150). +// EXPECT_TRUE(r1.Intersects(r2)); +// EXPECT_FALSE(r1.Contains(r2)); +// EXPECT_TRUE(r1.IntersectWith(r2)); // Mutates r1. +// EXPECT_EQ(QuicInterval<int>(50, 100), r1); // r1 is now [50, 100). +// +// QuicInterval<int> r3(1000, 2000); // The QuicInterval [1000, 2000). +// EXPECT_TRUE(r1.IntersectWith(r3)); // Mutates r1. +// EXPECT_TRUE(r1.Empty()); // Now r1 is empty. +// EXPECT_FALSE(r1.Contains(r1.min())); // e.g. doesn't contain its own min. + +#include <stddef.h> +#include <algorithm> +#include <ostream> +#include <string> +#include <type_traits> +#include <utility> +#include <vector> + +namespace quic { + +template <typename T> +class QuicInterval { + private: + // Type trait for deriving the return type for QuicInterval::Length. If + // operator-() is not defined for T, then the return type is void. This makes + // the signature for Length compile so that the class can be used for such T, + // but code that calls Length would still generate a compilation error. + template <typename U> + class DiffTypeOrVoid { + private: + template <typename V> + static auto f(const V* v) -> decltype(*v - *v); + template <typename V> + static void f(...); + + public: + using type = typename std::decay<decltype(f<U>(nullptr))>::type; + }; + + public: + // Construct an QuicInterval representing an empty QuicInterval. + QuicInterval() : min_(), max_() {} + + // Construct an QuicInterval representing the QuicInterval [min, max). If min + // < max, the constructed object will represent the non-empty QuicInterval + // containing all values from min up to (but not including) max. On the other + // hand, if min >= max, the constructed object will represent the empty + // QuicInterval. + QuicInterval(const T& min, const T& max) : min_(min), max_(max) {} + + template <typename U1, + typename U2, + typename = typename std::enable_if< + std::is_convertible<U1, T>::value && + std::is_convertible<U2, T>::value>::type> + QuicInterval(U1&& min, U2&& max) + : min_(std::forward<U1>(min)), max_(std::forward<U2>(max)) {} + + const T& min() const { return min_; } + const T& max() const { return max_; } + void SetMin(const T& t) { min_ = t; } + void SetMax(const T& t) { max_ = t; } + + void Set(const T& min, const T& max) { + SetMin(min); + SetMax(max); + } + + void Clear() { *this = {}; } + + bool Empty() const { return min() >= max(); } + + // Returns the length of this QuicInterval. The value returned is zero if + // Empty() is true; otherwise the value returned is max() - min(). + typename DiffTypeOrVoid<T>::type Length() const { + return (Empty() ? min() : max()) - min(); + } + + // Returns true iff t >= min() && t < max(). + bool Contains(const T& t) const { return min() <= t && max() > t; } + + // Returns true iff *this and i are non-empty, and *this includes i. "*this + // includes i" means that for all t, if i.Contains(t) then this->Contains(t). + // Note the unintuitive consequence of this definition: this method always + // returns false when i is the empty QuicInterval. + bool Contains(const QuicInterval& i) const { + return !Empty() && !i.Empty() && min() <= i.min() && max() >= i.max(); + } + + // Returns true iff there exists some point t for which this->Contains(t) && + // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty. + bool Intersects(const QuicInterval& i) const { + return !Empty() && !i.Empty() && min() < i.max() && max() > i.min(); + } + + // Returns true iff there exists some point t for which this->Contains(t) && + // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty. + // Furthermore, if the intersection is non-empty and the out pointer is not + // null, this method stores the calculated intersection in *out. + bool Intersects(const QuicInterval& i, QuicInterval* out) const; + + // Sets *this to be the intersection of itself with i. Returns true iff + // *this was modified. + bool IntersectWith(const QuicInterval& i); + + // Calculates the smallest QuicInterval containing both *this i, and updates + // *this to represent that QuicInterval, and returns true iff *this was + // modified. + bool SpanningUnion(const QuicInterval& i); + + // Determines the difference between two QuicIntervals by finding all points + // that are contained in *this but not in i, coalesces those points into the + // largest possible contiguous QuicIntervals, and appends those QuicIntervals + // to the *difference vector. Intuitively this can be thought of as "erasing" + // i from *this. This will either completely erase *this (leaving nothing + // behind), partially erase some of *this from the left or right side (leaving + // some residual behind), or erase a hole in the middle of *this (leaving + // behind an QuicInterval on either side). Therefore, 0, 1, or 2 QuicIntervals + // will be appended to *difference. The method returns true iff the + // intersection of *this and i is non-empty. The caller owns the vector and + // the QuicInterval* pointers inside it. The difference vector is required to + // be non-null. + bool Difference(const QuicInterval& i, + std::vector<QuicInterval*>* difference) const; + + // Determines the difference between two QuicIntervals as in + // Difference(QuicInterval&, vector*), but stores the results directly in out + // parameters rather than dynamically allocating an QuicInterval* and + // appending it to a vector. If two results are generated, the one with the + // smaller value of min() will be stored in *lo and the other in *hi. + // Otherwise (if fewer than two results are generated), unused arguments will + // be set to the empty QuicInterval (it is possible that *lo will be empty and + // *hi non-empty). The method returns true iff the intersection of *this and i + // is non-empty. + bool Difference(const QuicInterval& i, + QuicInterval* lo, + QuicInterval* hi) const; + + friend bool operator==(const QuicInterval& a, const QuicInterval& b) { + bool ae = a.Empty(); + bool be = b.Empty(); + if (ae && be) + return true; // All empties are equal. + if (ae != be) + return false; // Empty cannot equal nonempty. + return a.min() == b.min() && a.max() == b.max(); + } + + friend bool operator!=(const QuicInterval& a, const QuicInterval& b) { + return !(a == b); + } + + // Defines a comparator which can be used to induce an order on QuicIntervals, + // so that, for example, they can be stored in an ordered container such as + // std::set. The ordering is arbitrary, but does provide the guarantee that, + // for non-empty QuicIntervals X and Y, if X contains Y, then X <= Y. + // TODO(kosak): The current implementation of this comparator has a problem + // because the ordering it induces is inconsistent with that of Equals(). In + // particular, this comparator does not properly consider all empty + // QuicIntervals equivalent. Bug 9240050 has been created to track this. + friend bool operator<(const QuicInterval& a, const QuicInterval& b) { + return a.min() < b.min() || (!(b.min() < a.min()) && b.max() < a.max()); + } + + private: + T min_; // Inclusive lower bound. + T max_; // Exclusive upper bound. +}; + +// Constructs an QuicInterval by deducing the types from the function arguments. +template <typename T> +QuicInterval<T> MakeQuicInterval(T&& lhs, T&& rhs) { + return QuicInterval<T>(std::forward<T>(lhs), std::forward<T>(rhs)); +} + +// Note: ideally we'd use +// decltype(out << "[" << i.min() << ", " << i.max() << ")") +// as return type of the function, but as of July 2017 this triggers g++ +// "sorry, unimplemented: string literal in function template signature" error. +template <typename T> +auto operator<<(std::ostream& out, const QuicInterval<T>& i) + -> decltype(out << i.min()) { + return out << "[" << i.min() << ", " << i.max() << ")"; +} + +//============================================================================== +// Implementation details: Clients can stop reading here. + +template <typename T> +bool QuicInterval<T>::Intersects(const QuicInterval& i, + QuicInterval* out) const { + if (!Intersects(i)) + return false; + if (out != nullptr) { + *out = QuicInterval(std::max(min(), i.min()), std::min(max(), i.max())); + } + return true; +} + +template <typename T> +bool QuicInterval<T>::IntersectWith(const QuicInterval& i) { + if (Empty()) + return false; + bool modified = false; + if (i.min() > min()) { + SetMin(i.min()); + modified = true; + } + if (i.max() < max()) { + SetMax(i.max()); + modified = true; + } + return modified; +} + +template <typename T> +bool QuicInterval<T>::SpanningUnion(const QuicInterval& i) { + if (i.Empty()) + return false; + if (Empty()) { + *this = i; + return true; + } + bool modified = false; + if (i.min() < min()) { + SetMin(i.min()); + modified = true; + } + if (i.max() > max()) { + SetMax(i.max()); + modified = true; + } + return modified; +} + +template <typename T> +bool QuicInterval<T>::Difference(const QuicInterval& i, + std::vector<QuicInterval*>* difference) const { + if (Empty()) { + // <empty> - <i> = <empty> + return false; + } + if (i.Empty()) { + // <this> - <empty> = <this> + difference->push_back(new QuicInterval(*this)); + return false; + } + if (min() < i.max() && min() >= i.min() && max() > i.max()) { + // [------ this ------) + // [------ i ------) + // [-- result ---) + difference->push_back(new QuicInterval(i.max(), max())); + return true; + } + if (max() > i.min() && max() <= i.max() && min() < i.min()) { + // [------ this ------) + // [------ i ------) + // [- result -) + difference->push_back(new QuicInterval(min(), i.min())); + return true; + } + if (min() < i.min() && max() > i.max()) { + // [------- this --------) + // [---- i ----) + // [ R1 ) [ R2 ) + // There are two results: R1 and R2. + difference->push_back(new QuicInterval(min(), i.min())); + difference->push_back(new QuicInterval(i.max(), max())); + return true; + } + if (min() >= i.min() && max() <= i.max()) { + // [--- this ---) + // [------ i --------) + // Intersection is <this>, so difference yields the empty QuicInterval. + // Nothing is appended to *difference. + return true; + } + // No intersection. Append <this>. + difference->push_back(new QuicInterval(*this)); + return false; +} + +template <typename T> +bool QuicInterval<T>::Difference(const QuicInterval& i, + QuicInterval* lo, + QuicInterval* hi) const { + // Initialize *lo and *hi to empty + *lo = {}; + *hi = {}; + if (Empty()) + return false; + if (i.Empty()) { + *lo = *this; + return false; + } + if (min() < i.max() && min() >= i.min() && max() > i.max()) { + // [------ this ------) + // [------ i ------) + // [-- result ---) + *hi = QuicInterval(i.max(), max()); + return true; + } + if (max() > i.min() && max() <= i.max() && min() < i.min()) { + // [------ this ------) + // [------ i ------) + // [- result -) + *lo = QuicInterval(min(), i.min()); + return true; + } + if (min() < i.min() && max() > i.max()) { + // [------- this --------) + // [---- i ----) + // [ R1 ) [ R2 ) + // There are two results: R1 and R2. + *lo = QuicInterval(min(), i.min()); + *hi = QuicInterval(i.max(), max()); + return true; + } + if (min() >= i.min() && max() <= i.max()) { + // [--- this ---) + // [------ i --------) + // Intersection is <this>, so difference yields the empty QuicInterval. + return true; + } + *lo = *this; // No intersection. + return false; +} + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_INTERVAL_H_
diff --git a/quic/core/quic_interval_set.h b/quic/core/quic_interval_set.h new file mode 100644 index 0000000..937412a --- /dev/null +++ b/quic/core/quic_interval_set.h
@@ -0,0 +1,883 @@ +// 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_QUIC_CORE_QUIC_INTERVAL_SET_H_ +#define QUICHE_QUIC_CORE_QUIC_INTERVAL_SET_H_ + +// QuicIntervalSet<T> is a data structure used to represent a sorted set of +// non-empty, non-adjacent, and mutually disjoint intervals. Mutations to an +// interval set preserve these properties, altering the set as needed. For +// example, adding [2, 3) to a set containing only [1, 2) would result in the +// set containing the single interval [1, 3). +// +// Supported operations include testing whether an Interval is contained in the +// QuicIntervalSet, comparing two QuicIntervalSets, and performing +// QuicIntervalSet union, intersection, and difference. +// +// QuicIntervalSet maintains the minimum number of entries needed to represent +// the set of underlying intervals. When the QuicIntervalSet is modified (e.g. +// due to an Add operation), other interval entries may be coalesced, removed, +// or otherwise modified in order to maintain this invariant. The intervals are +// maintained in sorted order, by ascending min() value. +// +// The reader is cautioned to beware of the terminology used here: this library +// uses the terms "min" and "max" rather than "begin" and "end" as is +// conventional for the STL. The terminology [min, max) refers to the half-open +// interval which (if the interval is not empty) contains min but does not +// contain max. An interval is considered empty if min >= max. +// +// T is required to be default- and copy-constructible, to have an assignment +// operator, a difference operator (operator-()), and the full complement of +// comparison operators (<, <=, ==, !=, >=, >). These requirements are inherited +// from value_type. +// +// QuicIntervalSet has constant-time move operations. +// +// +// Examples: +// QuicIntervalSet<int> intervals; +// intervals.Add(Interval<int>(10, 20)); +// intervals.Add(Interval<int>(30, 40)); +// // intervals contains [10,20) and [30,40). +// intervals.Add(Interval<int>(15, 35)); +// // intervals has been coalesced. It now contains the single range [10,40). +// EXPECT_EQ(1, intervals.Size()); +// EXPECT_TRUE(intervals.Contains(Interval<int>(10, 40))); +// +// intervals.Difference(Interval<int>(10, 20)); +// // intervals should now contain the single range [20, 40). +// EXPECT_EQ(1, intervals.Size()); +// EXPECT_TRUE(intervals.Contains(Interval<int>(20, 40))); + +#include <stddef.h> +#include <algorithm> +#include <initializer_list> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "net/third_party/quiche/src/quic/core/quic_interval.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" + +namespace quic { + +template <typename T> +class QuicIntervalSet { + public: + typedef QuicInterval<T> value_type; + + private: + struct IntervalLess { + bool operator()(const value_type& a, const value_type& b) const; + }; + typedef std::set<value_type, IntervalLess> Set; + + public: + typedef typename Set::const_iterator const_iterator; + typedef typename Set::const_reverse_iterator const_reverse_iterator; + + // Instantiates an empty QuicIntervalSet. + QuicIntervalSet() {} + + // Instantiates an QuicIntervalSet containing exactly one initial half-open + // interval [min, max), unless the given interval is empty, in which case the + // QuicIntervalSet will be empty. + explicit QuicIntervalSet(const value_type& interval) { Add(interval); } + + // Instantiates an QuicIntervalSet containing the half-open interval [min, + // max). + QuicIntervalSet(const T& min, const T& max) { Add(min, max); } + + QuicIntervalSet(std::initializer_list<value_type> il) { assign(il); } + + // Clears this QuicIntervalSet. + void Clear() { intervals_.clear(); } + + // Returns the number of disjoint intervals contained in this QuicIntervalSet. + size_t Size() const { return intervals_.size(); } + + // Returns the smallest interval that contains all intervals in this + // QuicIntervalSet, or the empty interval if the set is empty. + value_type SpanningInterval() const; + + // Adds "interval" to this QuicIntervalSet. Adding the empty interval has no + // effect. + void Add(const value_type& interval); + + // Adds the interval [min, max) to this QuicIntervalSet. Adding the empty + // interval has no effect. + void Add(const T& min, const T& max) { Add(value_type(min, max)); } + + // DEPRECATED(kosak). Use Union() instead. This method merges all of the + // values contained in "other" into this QuicIntervalSet. + void Add(const QuicIntervalSet& other); + + // Returns true if this QuicIntervalSet is empty. + bool Empty() const { return intervals_.empty(); } + + // Returns true if any interval in this QuicIntervalSet contains the indicated + // value. + bool Contains(const T& value) const; + + // Returns true if there is some interval in this QuicIntervalSet that wholly + // contains the given interval. An interval O "wholly contains" a non-empty + // interval I if O.Contains(p) is true for every p in I. This is the same + // definition used by value_type::Contains(). This method returns false on + // the empty interval, due to a (perhaps unintuitive) convention inherited + // from value_type. + // Example: + // Assume an QuicIntervalSet containing the entries { [10,20), [30,40) }. + // Contains(Interval(15, 16)) returns true, because [10,20) contains + // [15,16). However, Contains(Interval(15, 35)) returns false. + bool Contains(const value_type& interval) const; + + // Returns true if for each interval in "other", there is some (possibly + // different) interval in this QuicIntervalSet which wholly contains it. See + // Contains(const value_type& interval) for the meaning of "wholly contains". + // Perhaps unintuitively, this method returns false if "other" is the empty + // set. The algorithmic complexity of this method is O(other.Size() * + // log(this->Size())). The method could be rewritten to run in O(other.Size() + // + this->Size()), and this alternative could be implemented as a free + // function using the public API. + bool Contains(const QuicIntervalSet<T>& other) const; + + // Returns true if there is some interval in this QuicIntervalSet that wholly + // contains the interval [min, max). See Contains(const value_type&). + bool Contains(const T& min, const T& max) const { + return Contains(value_type(min, max)); + } + + // Returns true if for some interval in "other", there is some interval in + // this QuicIntervalSet that intersects with it. See value_type::Intersects() + // for the definition of interval intersection. + bool Intersects(const QuicIntervalSet& other) const; + + // Returns an iterator to the value_type in the QuicIntervalSet that contains + // the given value. In other words, returns an iterator to the unique interval + // [min, max) in the QuicIntervalSet that has the property min <= value < max. + // If there is no such interval, this method returns end(). + const_iterator Find(const T& value) const; + + // Returns an iterator to the value_type in the QuicIntervalSet that wholly + // contains the given interval. In other words, returns an iterator to the + // unique interval outer in the QuicIntervalSet that has the property that + // outer.Contains(interval). If there is no such interval, or if interval is + // empty, returns end(). + const_iterator Find(const value_type& interval) const; + + // Returns an iterator to the value_type in the QuicIntervalSet that wholly + // contains [min, max). In other words, returns an iterator to the unique + // interval outer in the QuicIntervalSet that has the property that + // outer.Contains(Interval<T>(min, max)). If there is no such interval, or if + // interval is empty, returns end(). + const_iterator Find(const T& min, const T& max) const { + return Find(value_type(min, max)); + } + + // Returns an iterator pointing to the first value_type which contains or + // goes after the given value. + // + // Example: + // [10, 20) [30, 40) + // ^ LowerBound(10) + // ^ LowerBound(15) + // ^ LowerBound(20) + // ^ LowerBound(25) + const_iterator LowerBound(const T& value) const; + + // Returns an iterator pointing to the first value_type which goes after + // the given value. + // + // Example: + // [10, 20) [30, 40) + // ^ UpperBound(10) + // ^ UpperBound(15) + // ^ UpperBound(20) + // ^ UpperBound(25) + const_iterator UpperBound(const T& value) const; + + // Returns true if every value within the passed interval is not Contained + // within the QuicIntervalSet. + // Note that empty intervals are always considered disjoint from the + // QuicIntervalSet (even though the QuicIntervalSet doesn't `Contain` them). + bool IsDisjoint(const value_type& interval) const; + + // Merges all the values contained in "other" into this QuicIntervalSet. + void Union(const QuicIntervalSet& other); + + // Modifies this QuicIntervalSet so that it contains only those values that + // are currently present both in *this and in the QuicIntervalSet "other". + void Intersection(const QuicIntervalSet& other); + + // Mutates this QuicIntervalSet so that it contains only those values that are + // currently in *this but not in "interval". + void Difference(const value_type& interval); + + // Mutates this QuicIntervalSet so that it contains only those values that are + // currently in *this but not in the interval [min, max). + void Difference(const T& min, const T& max); + + // Mutates this QuicIntervalSet so that it contains only those values that are + // currently in *this but not in the QuicIntervalSet "other". + void Difference(const QuicIntervalSet& other); + + // Mutates this QuicIntervalSet so that it contains only those values that are + // in [min, max) but not currently in *this. + void Complement(const T& min, const T& max); + + // QuicIntervalSet's begin() iterator. The invariants of QuicIntervalSet + // guarantee that for each entry e in the set, e.min() < e.max() (because the + // entries are non-empty) and for each entry f that appears later in the set, + // e.max() < f.min() (because the entries are ordered, pairwise-disjoint, and + // non-adjacent). Modifications to this QuicIntervalSet invalidate these + // iterators. + const_iterator begin() const { return intervals_.begin(); } + + // QuicIntervalSet's end() iterator. + const_iterator end() const { return intervals_.end(); } + + // QuicIntervalSet's rbegin() and rend() iterators. Iterator invalidation + // semantics are the same as those for begin() / end(). + const_reverse_iterator rbegin() const { return intervals_.rbegin(); } + + const_reverse_iterator rend() const { return intervals_.rend(); } + + template <typename Iter> + void assign(Iter first, Iter last) { + Clear(); + for (; first != last; ++first) + Add(*first); + } + + void assign(std::initializer_list<value_type> il) { + assign(il.begin(), il.end()); + } + + // Returns a human-readable representation of this set. This will typically be + // (though is not guaranteed to be) of the form + // "[a1, b1) [a2, b2) ... [an, bn)" + // where the intervals are in the same order as given by traversal from + // begin() to end(). This representation is intended for human consumption; + // computer programs should not rely on the output being in exactly this form. + string ToString() const; + + QuicIntervalSet& operator=(std::initializer_list<value_type> il) { + assign(il.begin(), il.end()); + return *this; + } + + // Swap this QuicIntervalSet with *other. This is a constant-time operation. + void Swap(QuicIntervalSet<T>* other) { intervals_.swap(other->intervals_); } + + friend bool operator==(const QuicIntervalSet& a, const QuicIntervalSet& b) { + return a.Size() == b.Size() && + std::equal(a.begin(), a.end(), b.begin(), NonemptyIntervalEq()); + } + + friend bool operator!=(const QuicIntervalSet& a, const QuicIntervalSet& b) { + return !(a == b); + } + + private: + // Simple member-wise equality, since all intervals are non-empty. + struct NonemptyIntervalEq { + bool operator()(const value_type& a, const value_type& b) const { + return a.min() == b.min() && a.max() == b.max(); + } + }; + + // Removes overlapping ranges and coalesces adjacent intervals as needed. + void Compact(const typename Set::iterator& begin, + const typename Set::iterator& end); + + // Returns true if this set is valid (i.e. all intervals in it are non-empty, + // non-adjacent, and mutually disjoint). Currently this is used as an + // integrity check by the Intersection() and Difference() methods, but is only + // invoked for debug builds (via DCHECK). + bool Valid() const; + + // Finds the first interval that potentially intersects 'other'. + const_iterator FindIntersectionCandidate(const QuicIntervalSet& other) const; + + // Finds the first interval that potentially intersects 'interval'. + const_iterator FindIntersectionCandidate(const value_type& interval) const; + + // Helper for Intersection() and Difference(): Finds the next pair of + // intervals from 'x' and 'y' that intersect. 'mine' is an iterator + // over x->intervals_. 'theirs' is an iterator over y.intervals_. 'mine' + // and 'theirs' are advanced until an intersecting pair is found. + // Non-intersecting intervals (aka "holes") from x->intervals_ can be + // optionally erased by "on_hole". + template <typename X, typename Func> + static bool FindNextIntersectingPairImpl(X* x, + const QuicIntervalSet& y, + const_iterator* mine, + const_iterator* theirs, + Func on_hole); + + // The variant of the above method that doesn't mutate this QuicIntervalSet. + bool FindNextIntersectingPair(const QuicIntervalSet& other, + const_iterator* mine, + const_iterator* theirs) const { + return FindNextIntersectingPairImpl( + this, other, mine, theirs, + [](const QuicIntervalSet*, const_iterator, const_iterator) {}); + } + + // The variant of the above method that mutates this QuicIntervalSet by + // erasing holes. + bool FindNextIntersectingPairAndEraseHoles(const QuicIntervalSet& other, + const_iterator* mine, + const_iterator* theirs) { + return FindNextIntersectingPairImpl( + this, other, mine, theirs, + [](QuicIntervalSet* x, const_iterator from, const_iterator to) { + x->intervals_.erase(from, to); + }); + } + + // The representation for the intervals. The intervals in this set are + // non-empty, pairwise-disjoint, non-adjacent and ordered in ascending order + // by min(). + Set intervals_; +}; + +template <typename T> +auto operator<<(std::ostream& out, const QuicIntervalSet<T>& seq) + -> decltype(out << *seq.begin()) { + out << "{"; + for (const auto& interval : seq) { + out << " " << interval; + } + out << " }"; + + return out; +} + +template <typename T> +void swap(QuicIntervalSet<T>& x, QuicIntervalSet<T>& y); + +//============================================================================== +// Implementation details: Clients can stop reading here. + +template <typename T> +typename QuicIntervalSet<T>::value_type QuicIntervalSet<T>::SpanningInterval() + const { + value_type result; + if (!intervals_.empty()) { + result.SetMin(intervals_.begin()->min()); + result.SetMax(intervals_.rbegin()->max()); + } + return result; +} + +template <typename T> +void QuicIntervalSet<T>::Add(const value_type& interval) { + if (interval.Empty()) + return; + std::pair<typename Set::iterator, bool> ins = intervals_.insert(interval); + if (!ins.second) { + // This interval already exists. + return; + } + // Determine the minimal range that will have to be compacted. We know that + // the QuicIntervalSet was valid before the addition of the interval, so only + // need to start with the interval itself (although Compact takes an open + // range so begin needs to be the interval to the left). We don't know how + // many ranges this interval may cover, so we need to find the appropriate + // interval to end with on the right. + typename Set::iterator begin = ins.first; + if (begin != intervals_.begin()) + --begin; + const value_type target_end(interval.max(), interval.max()); + const typename Set::iterator end = intervals_.upper_bound(target_end); + Compact(begin, end); +} + +template <typename T> +void QuicIntervalSet<T>::Add(const QuicIntervalSet& other) { + for (const_iterator it = other.begin(); it != other.end(); ++it) { + Add(*it); + } +} + +template <typename T> +bool QuicIntervalSet<T>::Contains(const T& value) const { + value_type tmp(value, value); + // Find the first interval with min() > value, then move back one step + const_iterator it = intervals_.upper_bound(tmp); + if (it == intervals_.begin()) + return false; + --it; + return it->Contains(value); +} + +template <typename T> +bool QuicIntervalSet<T>::Contains(const value_type& interval) const { + // Find the first interval with min() > value, then move back one step. + const_iterator it = intervals_.upper_bound(interval); + if (it == intervals_.begin()) + return false; + --it; + return it->Contains(interval); +} + +template <typename T> +bool QuicIntervalSet<T>::Contains(const QuicIntervalSet<T>& other) const { + if (!SpanningInterval().Contains(other.SpanningInterval())) { + return false; + } + + for (const_iterator i = other.begin(); i != other.end(); ++i) { + // If we don't contain the interval, can return false now. + if (!Contains(*i)) { + return false; + } + } + return true; +} + +// This method finds the interval that Contains() "value", if such an interval +// exists in the QuicIntervalSet. The way this is done is to locate the +// "candidate interval", the only interval that could *possibly* contain value, +// and test it using Contains(). The candidate interval is the interval with the +// largest min() having min() <= value. +// +// Determining the candidate interval takes a couple of steps. First, since the +// underlying std::set stores intervals, not values, we need to create a "probe +// interval" suitable for use as a search key. The probe interval used is +// [value, value). Now we can restate the problem as finding the largest +// interval in the QuicIntervalSet that is <= the probe interval. +// +// This restatement only works if the set's comparator behaves in a certain way. +// In particular it needs to order first by ascending min(), and then by +// descending max(). The comparator used by this library is defined in exactly +// this way. To see why descending max() is required, consider the following +// example. Assume an QuicIntervalSet containing these intervals: +// +// [0, 5) [10, 20) [50, 60) +// +// Consider searching for the value 15. The probe interval [15, 15) is created, +// and [10, 20) is identified as the largest interval in the set <= the probe +// interval. This is the correct interval needed for the Contains() test, which +// will then return true. +// +// Now consider searching for the value 30. The probe interval [30, 30) is +// created, and again [10, 20] is identified as the largest interval <= the +// probe interval. This is again the correct interval needed for the Contains() +// test, which in this case returns false. +// +// Finally, consider searching for the value 10. The probe interval [10, 10) is +// created. Here the ordering relationship between [10, 10) and [10, 20) becomes +// vitally important. If [10, 10) were to come before [10, 20), then [0, 5) +// would be the largest interval <= the probe, leading to the wrong choice of +// interval for the Contains() test. Therefore [10, 10) needs to come after +// [10, 20). The simplest way to make this work in the general case is to order +// by ascending min() but descending max(). In this ordering, the empty interval +// is larger than any non-empty interval with the same min(). The comparator +// used by this library is careful to induce this ordering. +// +// Another detail involves the choice of which std::set method to use to try to +// find the candidate interval. The most appropriate entry point is +// set::upper_bound(), which finds the smallest interval which is > the probe +// interval. The semantics of upper_bound() are slightly different from what we +// want (namely, to find the largest interval which is <= the probe interval) +// but they are close enough; the interval found by upper_bound() will always be +// one step past the interval we are looking for (if it exists) or at begin() +// (if it does not). Getting to the proper interval is a simple matter of +// decrementing the iterator. +template <typename T> +typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::Find( + const T& value) const { + value_type tmp(value, value); + const_iterator it = intervals_.upper_bound(tmp); + if (it == intervals_.begin()) + return intervals_.end(); + --it; + if (it->Contains(value)) + return it; + else + return intervals_.end(); +} + +// This method finds the interval that Contains() the interval "probe", if such +// an interval exists in the QuicIntervalSet. The way this is done is to locate +// the "candidate interval", the only interval that could *possibly* contain +// "probe", and test it using Contains(). The candidate interval is the largest +// interval that is <= the probe interval. +// +// The search for the candidate interval only works if the comparator used +// behaves in a certain way. In particular it needs to order first by ascending +// min(), and then by descending max(). The comparator used by this library is +// defined in exactly this way. To see why descending max() is required, +// consider the following example. Assume an QuicIntervalSet containing these +// intervals: +// +// [0, 5) [10, 20) [50, 60) +// +// Consider searching for the probe [15, 17). [10, 20) is the largest interval +// in the set which is <= the probe interval. This is the correct interval +// needed for the Contains() test, which will then return true, because [10, 20) +// contains [15, 17). +// +// Now consider searching for the probe [30, 32). Again [10, 20] is the largest +// interval <= the probe interval. This is again the correct interval needed for +// the Contains() test, which in this case returns false, because [10, 20) does +// not contain [30, 32). +// +// Finally, consider searching for the probe [10, 12). Here the ordering +// relationship between [10, 12) and [10, 20) becomes vitally important. If +// [10, 12) were to come before [10, 20), then [0, 5) would be the largest +// interval <= the probe, leading to the wrong choice of interval for the +// Contains() test. Therefore [10, 12) needs to come after [10, 20). The +// simplest way to make this work in the general case is to order by ascending +// min() but descending max(). In this ordering, given two intervals with the +// same min(), the wider one goes before the narrower one. The comparator used +// by this library is careful to induce this ordering. +// +// Another detail involves the choice of which std::set method to use to try to +// find the candidate interval. The most appropriate entry point is +// set::upper_bound(), which finds the smallest interval which is > the probe +// interval. The semantics of upper_bound() are slightly different from what we +// want (namely, to find the largest interval which is <= the probe interval) +// but they are close enough; the interval found by upper_bound() will always be +// one step past the interval we are looking for (if it exists) or at begin() +// (if it does not). Getting to the proper interval is a simple matter of +// decrementing the iterator. +template <typename T> +typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::Find( + const value_type& probe) const { + const_iterator it = intervals_.upper_bound(probe); + if (it == intervals_.begin()) + return intervals_.end(); + --it; + if (it->Contains(probe)) + return it; + else + return intervals_.end(); +} + +template <typename T> +typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::LowerBound( + const T& value) const { + const_iterator it = intervals_.lower_bound(value_type(value, value)); + if (it == intervals_.begin()) { + return it; + } + + // The previous intervals_.lower_bound() checking is essentially based on + // interval.min(), so we need to check whether the `value` is contained in + // the previous interval. + --it; + if (it->Contains(value)) { + return it; + } else { + return ++it; + } +} + +template <typename T> +typename QuicIntervalSet<T>::const_iterator QuicIntervalSet<T>::UpperBound( + const T& value) const { + return intervals_.upper_bound(value_type(value, value)); +} + +template <typename T> +bool QuicIntervalSet<T>::IsDisjoint(const value_type& interval) const { + if (interval.Empty()) + return true; + value_type tmp(interval.min(), interval.min()); + // Find the first interval with min() > interval.min() + const_iterator it = intervals_.upper_bound(tmp); + if (it != intervals_.end() && interval.max() > it->min()) + return false; + if (it == intervals_.begin()) + return true; + --it; + return it->max() <= interval.min(); +} + +template <typename T> +void QuicIntervalSet<T>::Union(const QuicIntervalSet& other) { + intervals_.insert(other.begin(), other.end()); + Compact(intervals_.begin(), intervals_.end()); +} + +template <typename T> +typename QuicIntervalSet<T>::const_iterator +QuicIntervalSet<T>::FindIntersectionCandidate( + const QuicIntervalSet& other) const { + return FindIntersectionCandidate(*other.intervals_.begin()); +} + +template <typename T> +typename QuicIntervalSet<T>::const_iterator +QuicIntervalSet<T>::FindIntersectionCandidate( + const value_type& interval) const { + // Use upper_bound to efficiently find the first interval in intervals_ + // where min() is greater than interval.min(). If the result + // isn't the beginning of intervals_ then move backwards one interval since + // the interval before it is the first candidate where max() may be + // greater than interval.min(). + // In other words, no interval before that can possibly intersect with any + // of other.intervals_. + const_iterator mine = intervals_.upper_bound(interval); + if (mine != intervals_.begin()) { + --mine; + } + return mine; +} + +template <typename T> +template <typename X, typename Func> +bool QuicIntervalSet<T>::FindNextIntersectingPairImpl(X* x, + const QuicIntervalSet& y, + const_iterator* mine, + const_iterator* theirs, + Func on_hole) { + CHECK(x != nullptr); + if ((*mine == x->intervals_.end()) || (*theirs == y.intervals_.end())) { + return false; + } + while (!(**mine).Intersects(**theirs)) { + const_iterator erase_first = *mine; + // Skip over intervals in 'mine' that don't reach 'theirs'. + while (*mine != x->intervals_.end() && (**mine).max() <= (**theirs).min()) { + ++(*mine); + } + on_hole(x, erase_first, *mine); + // We're done if the end of intervals_ is reached. + if (*mine == x->intervals_.end()) { + return false; + } + // Skip over intervals 'theirs' that don't reach 'mine'. + while (*theirs != y.intervals_.end() && + (**theirs).max() <= (**mine).min()) { + ++(*theirs); + } + // If the end of other.intervals_ is reached, we're done. + if (*theirs == y.intervals_.end()) { + on_hole(x, *mine, x->intervals_.end()); + return false; + } + } + return true; +} + +template <typename T> +void QuicIntervalSet<T>::Intersection(const QuicIntervalSet& other) { + if (!SpanningInterval().Intersects(other.SpanningInterval())) { + intervals_.clear(); + return; + } + + const_iterator mine = FindIntersectionCandidate(other); + // Remove any intervals that cannot possibly intersect with other.intervals_. + intervals_.erase(intervals_.begin(), mine); + const_iterator theirs = other.FindIntersectionCandidate(*this); + + while (FindNextIntersectingPairAndEraseHoles(other, &mine, &theirs)) { + // OK, *mine and *theirs intersect. Now, we find the largest + // span of intervals in other (starting at theirs) - say [a..b] + // - that intersect *mine, and we replace *mine with (*mine + // intersect x) for all x in [a..b] Note that subsequent + // intervals in this can't intersect any intervals in [a..b) -- + // they may only intersect b or subsequent intervals in other. + value_type i(*mine); + intervals_.erase(mine); + mine = intervals_.end(); + value_type intersection; + while (theirs != other.intervals_.end() && + i.Intersects(*theirs, &intersection)) { + std::pair<typename Set::iterator, bool> ins = + intervals_.insert(intersection); + DCHECK(ins.second); + mine = ins.first; + ++theirs; + } + DCHECK(mine != intervals_.end()); + --theirs; + ++mine; + } + DCHECK(Valid()); +} + +template <typename T> +bool QuicIntervalSet<T>::Intersects(const QuicIntervalSet& other) const { + if (!SpanningInterval().Intersects(other.SpanningInterval())) { + return false; + } + + const_iterator mine = FindIntersectionCandidate(other); + if (mine == intervals_.end()) { + return false; + } + const_iterator theirs = other.FindIntersectionCandidate(*mine); + + return FindNextIntersectingPair(other, &mine, &theirs); +} + +template <typename T> +void QuicIntervalSet<T>::Difference(const value_type& interval) { + if (!SpanningInterval().Intersects(interval)) { + return; + } + Difference(QuicIntervalSet<T>(interval)); +} + +template <typename T> +void QuicIntervalSet<T>::Difference(const T& min, const T& max) { + Difference(value_type(min, max)); +} + +template <typename T> +void QuicIntervalSet<T>::Difference(const QuicIntervalSet& other) { + if (!SpanningInterval().Intersects(other.SpanningInterval())) { + return; + } + + const_iterator mine = FindIntersectionCandidate(other); + // If no interval in mine reaches the first interval of theirs then we're + // done. + if (mine == intervals_.end()) { + return; + } + const_iterator theirs = other.FindIntersectionCandidate(*this); + + while (FindNextIntersectingPair(other, &mine, &theirs)) { + // At this point *mine and *theirs overlap. Remove mine from + // intervals_ and replace it with the possibly two intervals that are + // the difference between mine and theirs. + value_type i(*mine); + intervals_.erase(mine++); + value_type lo; + value_type hi; + i.Difference(*theirs, &lo, &hi); + + if (!lo.Empty()) { + // We have a low end. This can't intersect anything else. + std::pair<typename Set::iterator, bool> ins = intervals_.insert(lo); + DCHECK(ins.second); + } + + if (!hi.Empty()) { + std::pair<typename Set::iterator, bool> ins = intervals_.insert(hi); + DCHECK(ins.second); + mine = ins.first; + } + } + DCHECK(Valid()); +} + +template <typename T> +void QuicIntervalSet<T>::Complement(const T& min, const T& max) { + QuicIntervalSet<T> span(min, max); + span.Difference(*this); + intervals_.swap(span.intervals_); +} + +template <typename T> +string QuicIntervalSet<T>::ToString() const { + std::ostringstream os; + os << *this; + return os.str(); +} + +// This method compacts the QuicIntervalSet, merging pairs of overlapping +// intervals into a single interval. In the steady state, the QuicIntervalSet +// does not contain any such pairs. However, the way the Union() and Add() +// methods work is to temporarily put the QuicIntervalSet into such a state and +// then to call Compact() to "fix it up" so that it is no longer in that state. +// +// Compact() needs the interval set to allow two intervals [a,b) and [a,c) +// (having the same min() but different max()) to briefly coexist in the set at +// the same time, and be adjacent to each other, so that they can be efficiently +// located and merged into a single interval. This state would be impossible +// with a comparator which only looked at min(), as such a comparator would +// consider such pairs equal. Fortunately, the comparator used by +// QuicIntervalSet does exactly what is needed, ordering first by ascending +// min(), then by descending max(). +template <typename T> +void QuicIntervalSet<T>::Compact(const typename Set::iterator& begin, + const typename Set::iterator& end) { + if (begin == end) + return; + typename Set::iterator next = begin; + typename Set::iterator prev = begin; + typename Set::iterator it = begin; + ++it; + ++next; + while (it != end) { + ++next; + if (prev->max() >= it->min()) { + // Overlapping / coalesced range; merge the two intervals. + T min = prev->min(); + T max = std::max(prev->max(), it->max()); + value_type i(min, max); + intervals_.erase(prev); + intervals_.erase(it); + std::pair<typename Set::iterator, bool> ins = intervals_.insert(i); + DCHECK(ins.second); + prev = ins.first; + } else { + prev = it; + } + it = next; + } +} + +template <typename T> +bool QuicIntervalSet<T>::Valid() const { + const_iterator prev = end(); + for (const_iterator it = begin(); it != end(); ++it) { + // invalid or empty interval. + if (it->min() >= it->max()) + return false; + // Not sorted, not disjoint, or adjacent. + if (prev != end() && prev->max() >= it->min()) + return false; + prev = it; + } + return true; +} + +template <typename T> +void swap(QuicIntervalSet<T>& x, QuicIntervalSet<T>& y) { + x.Swap(&y); +} + +// This comparator orders intervals first by ascending min() and then by +// descending max(). Readers who are satisified with that explanation can stop +// reading here. The remainder of this comment is for the benefit of future +// maintainers of this library. +// +// The reason for this ordering is that this comparator has to serve two +// masters. First, it has to maintain the intervals in its internal set in the +// order that clients expect to see them. Clients see these intervals via the +// iterators provided by begin()/end() or as a result of invoking Get(). For +// this reason, the comparator orders intervals by ascending min(). +// +// If client iteration were the only consideration, then ordering by ascending +// min() would be good enough. This is because the intervals in the +// QuicIntervalSet are non-empty, non-adjacent, and mutually disjoint; such +// intervals happen to always have disjoint min() values, so such a comparator +// would never even have to look at max() in order to work correctly for this +// class. +// +// However, in addition to ordering by ascending min(), this comparator also has +// a second responsibility: satisfying the special needs of this library's +// peculiar internal implementation. These needs require the comparator to order +// first by ascending min() and then by descending max(). The best way to +// understand why this is so is to check out the comments associated with the +// Find() and Compact() methods. +template <typename T> +bool QuicIntervalSet<T>::IntervalLess::operator()(const value_type& a, + const value_type& b) const { + return a.min() < b.min() || (a.min() == b.min() && a.max() > b.max()); +} + +} // namespace quic + +#endif // QUICHE_QUIC_CORE_QUIC_INTERVAL_SET_H_
diff --git a/quic/core/quic_interval_set_test.cc b/quic/core/quic_interval_set_test.cc new file mode 100644 index 0000000..65d1d32 --- /dev/null +++ b/quic/core/quic_interval_set_test.cc
@@ -0,0 +1,979 @@ +// 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. + +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" + +#include <stdarg.h> +#include <algorithm> +#include <iostream> +#include <iterator> +#include <limits> +#include <vector> + +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { +namespace { + +using ::testing::ElementsAreArray; + +class QuicIntervalSetTest : public QuicTest { + protected: + virtual void SetUp() { + // Initialize two QuicIntervalSets for union, intersection, and difference + // tests + is.Add(100, 200); + is.Add(300, 400); + is.Add(500, 600); + is.Add(700, 800); + is.Add(900, 1000); + is.Add(1100, 1200); + is.Add(1300, 1400); + is.Add(1500, 1600); + is.Add(1700, 1800); + is.Add(1900, 2000); + is.Add(2100, 2200); + + // Lots of different cases: + other.Add(50, 70); // disjoint, at the beginning + other.Add(2250, 2270); // disjoint, at the end + other.Add(650, 670); // disjoint, in the middle + other.Add(350, 360); // included + other.Add(370, 380); // also included (two at once) + other.Add(470, 530); // overlaps low end + other.Add(770, 830); // overlaps high end + other.Add(870, 900); // meets at low end + other.Add(1200, 1230); // meets at high end + other.Add(1270, 1830); // overlaps multiple ranges + } + + virtual void TearDown() { + is.Clear(); + EXPECT_TRUE(is.Empty()); + other.Clear(); + EXPECT_TRUE(other.Empty()); + } + QuicIntervalSet<int> is; + QuicIntervalSet<int> other; +}; + +TEST_F(QuicIntervalSetTest, IsDisjoint) { + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(0, 99))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(0, 100))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(200, 200))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(200, 299))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(400, 407))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(405, 499))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(2300, 2300))); + EXPECT_TRUE( + is.IsDisjoint(QuicInterval<int>(2300, std::numeric_limits<int>::max()))); + EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(100, 105))); + EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(199, 300))); + EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(250, 450))); + EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(299, 400))); + EXPECT_FALSE(is.IsDisjoint(QuicInterval<int>(250, 2000))); + EXPECT_FALSE( + is.IsDisjoint(QuicInterval<int>(2199, std::numeric_limits<int>::max()))); + // Empty intervals. + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(90, 90))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(100, 100))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(100, 90))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(150, 150))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(200, 200))); + EXPECT_TRUE(is.IsDisjoint(QuicInterval<int>(400, 300))); +} + +// Base helper method for verifying the contents of an interval set. +// Returns true iff <is> contains <count> intervals whose successive +// endpoints match the sequence of args in <ap>: +static bool VA_Check(const QuicIntervalSet<int>& is, int count, va_list ap) { + std::vector<QuicInterval<int>> intervals(is.begin(), is.end()); + if (count != static_cast<int>(intervals.size())) { + LOG(ERROR) << "Expected " << count << " intervals, got " << intervals.size() + << ": " << is; + return false; + } + if (count != static_cast<int>(is.Size())) { + LOG(ERROR) << "Expected " << count << " intervals, got Size " << is.Size() + << ": " << is; + return false; + } + bool result = true; + for (int i = 0; i < count; i++) { + int min = va_arg(ap, int); + int max = va_arg(ap, int); + if (min != intervals[i].min() || max != intervals[i].max()) { + LOG(ERROR) << "Expected: [" << min << ", " << max << ") got " + << intervals[i] << " in " << is; + result = false; + } + } + return result; +} + +static bool Check(const QuicIntervalSet<int>& is, int count, ...) { + va_list ap; + va_start(ap, count); + const bool result = VA_Check(is, count, ap); + va_end(ap); + return result; +} + +// Some helper functions for testing Contains and Find, which are logically the +// same. +static void TestContainsAndFind(const QuicIntervalSet<int>& is, int value) { + EXPECT_TRUE(is.Contains(value)) << "Set does not contain " << value; + auto it = is.Find(value); + EXPECT_NE(it, is.end()) << "No iterator to interval containing " << value; + EXPECT_TRUE(it->Contains(value)) << "Iterator does not contain " << value; +} + +static void TestContainsAndFind(const QuicIntervalSet<int>& is, + int min, + int max) { + EXPECT_TRUE(is.Contains(min, max)) + << "Set does not contain interval with min " << min << "and max " << max; + auto it = is.Find(min, max); + EXPECT_NE(it, is.end()) << "No iterator to interval with min " << min + << "and max " << max; + EXPECT_TRUE(it->Contains(QuicInterval<int>(min, max))) + << "Iterator does not contain interval with min " << min << "and max " + << max; +} + +static void TestNotContainsAndFind(const QuicIntervalSet<int>& is, int value) { + EXPECT_FALSE(is.Contains(value)) << "Set contains " << value; + auto it = is.Find(value); + EXPECT_EQ(it, is.end()) << "There is iterator to interval containing " + << value; +} + +static void TestNotContainsAndFind(const QuicIntervalSet<int>& is, + int min, + int max) { + EXPECT_FALSE(is.Contains(min, max)) + << "Set contains interval with min " << min << "and max " << max; + auto it = is.Find(min, max); + EXPECT_EQ(it, is.end()) << "There is iterator to interval with min " << min + << "and max " << max; +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetBasic) { + // Test Add, Get, Contains and Find + QuicIntervalSet<int> iset; + EXPECT_TRUE(iset.Empty()); + EXPECT_EQ(0, iset.Size()); + iset.Add(100, 200); + EXPECT_FALSE(iset.Empty()); + EXPECT_EQ(1, iset.Size()); + iset.Add(100, 150); + iset.Add(150, 200); + iset.Add(130, 170); + iset.Add(90, 150); + iset.Add(170, 220); + iset.Add(300, 400); + iset.Add(250, 450); + EXPECT_FALSE(iset.Empty()); + EXPECT_EQ(2, iset.Size()); + EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450)); + + // Test two intervals with a.max == b.min, that will just join up. + iset.Clear(); + iset.Add(100, 200); + iset.Add(200, 300); + EXPECT_FALSE(iset.Empty()); + EXPECT_EQ(1, iset.Size()); + EXPECT_TRUE(Check(iset, 1, 100, 300)); + + // Test adding two sets together. + iset.Clear(); + QuicIntervalSet<int> iset_add; + iset.Add(100, 200); + iset.Add(100, 150); + iset.Add(150, 200); + iset.Add(130, 170); + iset_add.Add(90, 150); + iset_add.Add(170, 220); + iset_add.Add(300, 400); + iset_add.Add(250, 450); + + iset.Add(iset_add); + EXPECT_FALSE(iset.Empty()); + EXPECT_EQ(2, iset.Size()); + EXPECT_TRUE(Check(iset, 2, 90, 220, 250, 450)); + + // Test begin()/end(), and rbegin()/rend() + // to iterate over intervals. + { + std::vector<QuicInterval<int>> expected(iset.begin(), iset.end()); + + std::vector<QuicInterval<int>> actual1; + std::copy(iset.begin(), iset.end(), back_inserter(actual1)); + ASSERT_EQ(expected.size(), actual1.size()); + + std::vector<QuicInterval<int>> actual2; + std::copy(iset.begin(), iset.end(), back_inserter(actual2)); + ASSERT_EQ(expected.size(), actual2.size()); + + for (size_t i = 0; i < expected.size(); i++) { + EXPECT_EQ(expected[i].min(), actual1[i].min()); + EXPECT_EQ(expected[i].max(), actual1[i].max()); + + EXPECT_EQ(expected[i].min(), actual2[i].min()); + EXPECT_EQ(expected[i].max(), actual2[i].max()); + } + + // Ensure that the rbegin()/rend() iterators correctly yield the intervals + // in reverse order. + EXPECT_THAT(std::vector<QuicInterval<int>>(iset.rbegin(), iset.rend()), + ElementsAreArray(expected.rbegin(), expected.rend())); + } + + TestNotContainsAndFind(iset, 89); + TestContainsAndFind(iset, 90); + TestContainsAndFind(iset, 120); + TestContainsAndFind(iset, 219); + TestNotContainsAndFind(iset, 220); + TestNotContainsAndFind(iset, 235); + TestNotContainsAndFind(iset, 249); + TestContainsAndFind(iset, 250); + TestContainsAndFind(iset, 300); + TestContainsAndFind(iset, 449); + TestNotContainsAndFind(iset, 450); + TestNotContainsAndFind(iset, 451); + + TestNotContainsAndFind(iset, 50, 60); + TestNotContainsAndFind(iset, 50, 90); + TestNotContainsAndFind(iset, 50, 200); + TestNotContainsAndFind(iset, 90, 90); + TestContainsAndFind(iset, 90, 200); + TestContainsAndFind(iset, 100, 200); + TestContainsAndFind(iset, 100, 220); + TestNotContainsAndFind(iset, 100, 221); + TestNotContainsAndFind(iset, 220, 220); + TestNotContainsAndFind(iset, 240, 300); + TestContainsAndFind(iset, 250, 300); + TestContainsAndFind(iset, 260, 300); + TestContainsAndFind(iset, 300, 450); + TestNotContainsAndFind(iset, 300, 451); + + QuicIntervalSet<int> iset_contains; + iset_contains.Add(50, 90); + EXPECT_FALSE(iset.Contains(iset_contains)); + iset_contains.Clear(); + + iset_contains.Add(90, 200); + EXPECT_TRUE(iset.Contains(iset_contains)); + iset_contains.Add(100, 200); + EXPECT_TRUE(iset.Contains(iset_contains)); + iset_contains.Add(100, 220); + EXPECT_TRUE(iset.Contains(iset_contains)); + iset_contains.Add(250, 300); + EXPECT_TRUE(iset.Contains(iset_contains)); + iset_contains.Add(300, 450); + EXPECT_TRUE(iset.Contains(iset_contains)); + iset_contains.Add(300, 451); + EXPECT_FALSE(iset.Contains(iset_contains)); + EXPECT_FALSE(iset.Contains(QuicInterval<int>())); + EXPECT_FALSE(iset.Contains(QuicIntervalSet<int>())); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetContainsEmpty) { + const QuicIntervalSet<int> empty; + const QuicIntervalSet<int> other_empty; + const QuicIntervalSet<int> non_empty({{10, 20}, {40, 50}}); + EXPECT_FALSE(empty.Contains(empty)); + EXPECT_FALSE(empty.Contains(other_empty)); + EXPECT_FALSE(empty.Contains(non_empty)); + EXPECT_FALSE(non_empty.Contains(empty)); +} + +TEST_F(QuicIntervalSetTest, Equality) { + QuicIntervalSet<int> is_copy = is; + EXPECT_EQ(is, is); + EXPECT_EQ(is, is_copy); + EXPECT_NE(is, other); + EXPECT_NE(is, QuicIntervalSet<int>()); + EXPECT_EQ(QuicIntervalSet<int>(), QuicIntervalSet<int>()); +} + +TEST_F(QuicIntervalSetTest, LowerAndUpperBound) { + QuicIntervalSet<int> intervals; + intervals.Add(10, 20); + intervals.Add(30, 40); + + // [10, 20) [30, 40) end + // ^ LowerBound(5) + // ^ LowerBound(10) + // ^ LowerBound(15) + // ^ LowerBound(20) + // ^ LowerBound(25) + // ^ LowerBound(30) + // ^ LowerBound(35) + // ^ LowerBound(40) + // ^ LowerBound(50) + EXPECT_EQ(intervals.LowerBound(5)->min(), 10); + EXPECT_EQ(intervals.LowerBound(10)->min(), 10); + EXPECT_EQ(intervals.LowerBound(15)->min(), 10); + EXPECT_EQ(intervals.LowerBound(20)->min(), 30); + EXPECT_EQ(intervals.LowerBound(25)->min(), 30); + EXPECT_EQ(intervals.LowerBound(30)->min(), 30); + EXPECT_EQ(intervals.LowerBound(35)->min(), 30); + EXPECT_EQ(intervals.LowerBound(40), intervals.end()); + EXPECT_EQ(intervals.LowerBound(50), intervals.end()); + + // [10, 20) [30, 40) end + // ^ UpperBound(5) + // ^ UpperBound(10) + // ^ UpperBound(15) + // ^ UpperBound(20) + // ^ UpperBound(25) + // ^ UpperBound(30) + // ^ UpperBound(35) + // ^ UpperBound(40) + // ^ UpperBound(50) + EXPECT_EQ(intervals.UpperBound(5)->min(), 10); + EXPECT_EQ(intervals.UpperBound(10)->min(), 30); + EXPECT_EQ(intervals.UpperBound(15)->min(), 30); + EXPECT_EQ(intervals.UpperBound(20)->min(), 30); + EXPECT_EQ(intervals.UpperBound(25)->min(), 30); + EXPECT_EQ(intervals.UpperBound(30), intervals.end()); + EXPECT_EQ(intervals.UpperBound(35), intervals.end()); + EXPECT_EQ(intervals.UpperBound(40), intervals.end()); + EXPECT_EQ(intervals.UpperBound(50), intervals.end()); +} + +TEST_F(QuicIntervalSetTest, SpanningInterval) { + // Spanning interval of an empty set is empty: + { + QuicIntervalSet<int> iset; + const QuicInterval<int>& ival = iset.SpanningInterval(); + EXPECT_TRUE(ival.Empty()); + } + + // Spanning interval of a set with one interval is that interval: + { + QuicIntervalSet<int> iset; + iset.Add(100, 200); + const QuicInterval<int>& ival = iset.SpanningInterval(); + EXPECT_EQ(100, ival.min()); + EXPECT_EQ(200, ival.max()); + } + + // Spanning interval of a set with multiple elements is determined + // by the endpoints of the first and last element: + { + const QuicInterval<int>& ival = is.SpanningInterval(); + EXPECT_EQ(100, ival.min()); + EXPECT_EQ(2200, ival.max()); + } + { + const QuicInterval<int>& ival = other.SpanningInterval(); + EXPECT_EQ(50, ival.min()); + EXPECT_EQ(2270, ival.max()); + } +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetUnion) { + is.Union(other); + EXPECT_TRUE(Check(is, 12, 50, 70, 100, 200, 300, 400, 470, 600, 650, 670, 700, + 830, 870, 1000, 1100, 1230, 1270, 1830, 1900, 2000, 2100, + 2200, 2250, 2270)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersection) { + EXPECT_TRUE(is.Intersects(other)); + EXPECT_TRUE(other.Intersects(is)); + is.Intersection(other); + EXPECT_TRUE(Check(is, 7, 350, 360, 370, 380, 500, 530, 770, 800, 1300, 1400, + 1500, 1600, 1700, 1800)); + EXPECT_TRUE(is.Intersects(other)); + EXPECT_TRUE(other.Intersects(is)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionBothEmpty) { + QuicIntervalSet<string> mine, theirs; + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionEmptyMine) { + QuicIntervalSet<string> mine; + QuicIntervalSet<string> theirs("a", "b"); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionEmptyTheirs) { + QuicIntervalSet<string> mine("a", "b"); + QuicIntervalSet<string> theirs; + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionTheirsBeforeMine) { + QuicIntervalSet<string> mine("y", "z"); + QuicIntervalSet<string> theirs; + theirs.Add("a", "b"); + theirs.Add("c", "d"); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionMineBeforeTheirs) { + QuicIntervalSet<string> mine; + mine.Add("a", "b"); + mine.Add("c", "d"); + QuicIntervalSet<string> theirs("y", "z"); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, + QuicIntervalSetIntersectionTheirsBeforeMineInt64Singletons) { + QuicIntervalSet<int64_t> mine({{10, 15}}); + QuicIntervalSet<int64_t> theirs({{-20, -5}}); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, + QuicIntervalSetIntersectionMineBeforeTheirsIntSingletons) { + QuicIntervalSet<int> mine({{10, 15}}); + QuicIntervalSet<int> theirs({{90, 95}}); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionTheirsBetweenMine) { + QuicIntervalSet<int64_t> mine({{0, 5}, {40, 50}}); + QuicIntervalSet<int64_t> theirs({{10, 15}}); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionMineBetweenTheirs) { + QuicIntervalSet<int> mine({{20, 25}}); + QuicIntervalSet<int> theirs({{10, 15}, {30, 32}}); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionAlternatingIntervals) { + QuicIntervalSet<int> mine, theirs; + mine.Add(10, 20); + mine.Add(40, 50); + mine.Add(60, 70); + theirs.Add(25, 39); + theirs.Add(55, 59); + theirs.Add(75, 79); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(mine.Empty()); + EXPECT_FALSE(mine.Intersects(theirs)); + EXPECT_FALSE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, + QuicIntervalSetIntersectionAdjacentAlternatingNonIntersectingIntervals) { + // Make sure that intersection with adjacent interval set is empty. + const QuicIntervalSet<int> x1({{0, 10}}); + const QuicIntervalSet<int> y1({{-50, 0}, {10, 95}}); + + QuicIntervalSet<int> result1 = x1; + result1.Intersection(y1); + EXPECT_TRUE(result1.Empty()) << result1; + + const QuicIntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}}); + const QuicIntervalSet<int16_t> y2( + {{-50, -40}, {-2, 0}, {10, 20}, {32, 40}, {90, 95}}); + + QuicIntervalSet<int16_t> result2 = x2; + result2.Intersection(y2); + EXPECT_TRUE(result2.Empty()) << result2; + + const QuicIntervalSet<int64_t> x3({{-1, 5}, {5, 10}}); + const QuicIntervalSet<int64_t> y3({{-10, -1}, {10, 95}}); + + QuicIntervalSet<int64_t> result3 = x3; + result3.Intersection(y3); + EXPECT_TRUE(result3.Empty()) << result3; +} + +TEST_F(QuicIntervalSetTest, + QuicIntervalSetIntersectionAlternatingIntersectingIntervals) { + const QuicIntervalSet<int> x1({{0, 10}}); + const QuicIntervalSet<int> y1({{-50, 1}, {9, 95}}); + const QuicIntervalSet<int> expected_result1({{0, 1}, {9, 10}}); + + QuicIntervalSet<int> result1 = x1; + result1.Intersection(y1); + EXPECT_EQ(result1, expected_result1); + + const QuicIntervalSet<int16_t> x2({{0, 10}, {20, 30}, {40, 90}}); + const QuicIntervalSet<int16_t> y2( + {{-50, -40}, {-2, 2}, {9, 21}, {32, 41}, {85, 95}}); + const QuicIntervalSet<int16_t> expected_result2( + {{0, 2}, {9, 10}, {20, 21}, {40, 41}, {85, 90}}); + + QuicIntervalSet<int16_t> result2 = x2; + result2.Intersection(y2); + EXPECT_EQ(result2, expected_result2); + + const QuicIntervalSet<int64_t> x3({{-1, 5}, {5, 10}}); + const QuicIntervalSet<int64_t> y3({{-10, 3}, {4, 95}}); + const QuicIntervalSet<int64_t> expected_result3({{-1, 3}, {4, 10}}); + + QuicIntervalSet<int64_t> result3 = x3; + result3.Intersection(y3); + EXPECT_EQ(result3, expected_result3); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionIdentical) { + QuicIntervalSet<int> copy(is); + EXPECT_TRUE(copy.Intersects(is)); + EXPECT_TRUE(is.Intersects(copy)); + is.Intersection(copy); + EXPECT_EQ(copy, is); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionSuperset) { + QuicIntervalSet<int> mine(-1, 10000); + EXPECT_TRUE(mine.Intersects(is)); + EXPECT_TRUE(is.Intersects(mine)); + mine.Intersection(is); + EXPECT_EQ(is, mine); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionSubset) { + QuicIntervalSet<int> copy(is); + QuicIntervalSet<int> theirs(-1, 10000); + EXPECT_TRUE(copy.Intersects(theirs)); + EXPECT_TRUE(theirs.Intersects(copy)); + is.Intersection(theirs); + EXPECT_EQ(copy, is); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetIntersectionLargeSet) { + QuicIntervalSet<int> mine, theirs; + // mine: [0, 9), [10, 19), ..., [990, 999) + for (int i = 0; i < 1000; i += 10) { + mine.Add(i, i + 9); + } + + theirs.Add(500, 520); + theirs.Add(535, 545); + theirs.Add(801, 809); + EXPECT_TRUE(mine.Intersects(theirs)); + EXPECT_TRUE(theirs.Intersects(mine)); + mine.Intersection(theirs); + EXPECT_TRUE(Check(mine, 5, 500, 509, 510, 519, 535, 539, 540, 545, 801, 809)); + EXPECT_TRUE(mine.Intersects(theirs)); + EXPECT_TRUE(theirs.Intersects(mine)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifference) { + is.Difference(other); + EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600, + 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200)); + QuicIntervalSet<int> copy = is; + is.Difference(copy); + EXPECT_TRUE(is.Empty()); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceSingleBounds) { + std::vector<QuicInterval<int>> ivals(other.begin(), other.end()); + for (const QuicInterval<int>& ival : ivals) { + is.Difference(ival.min(), ival.max()); + } + EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600, + 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceSingleInterval) { + std::vector<QuicInterval<int>> ivals(other.begin(), other.end()); + for (const QuicInterval<int>& ival : ivals) { + is.Difference(ival); + } + EXPECT_TRUE(Check(is, 10, 100, 200, 300, 350, 360, 370, 380, 400, 530, 600, + 700, 770, 900, 1000, 1100, 1200, 1900, 2000, 2100, 2200)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceAlternatingIntervals) { + QuicIntervalSet<int> mine, theirs; + mine.Add(10, 20); + mine.Add(40, 50); + mine.Add(60, 70); + theirs.Add(25, 39); + theirs.Add(55, 59); + theirs.Add(75, 79); + + mine.Difference(theirs); + EXPECT_TRUE(Check(mine, 3, 10, 20, 40, 50, 60, 70)); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceEmptyMine) { + QuicIntervalSet<string> mine, theirs; + theirs.Add("a", "b"); + + mine.Difference(theirs); + EXPECT_TRUE(mine.Empty()); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceEmptyTheirs) { + QuicIntervalSet<string> mine, theirs; + mine.Add("a", "b"); + + mine.Difference(theirs); + EXPECT_EQ(1, mine.Size()); + EXPECT_EQ("a", mine.begin()->min()); + EXPECT_EQ("b", mine.begin()->max()); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceTheirsBeforeMine) { + QuicIntervalSet<string> mine, theirs; + mine.Add("y", "z"); + theirs.Add("a", "b"); + + mine.Difference(theirs); + EXPECT_EQ(1, mine.Size()); + EXPECT_EQ("y", mine.begin()->min()); + EXPECT_EQ("z", mine.begin()->max()); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceMineBeforeTheirs) { + QuicIntervalSet<string> mine, theirs; + mine.Add("a", "b"); + theirs.Add("y", "z"); + + mine.Difference(theirs); + EXPECT_EQ(1, mine.Size()); + EXPECT_EQ("a", mine.begin()->min()); + EXPECT_EQ("b", mine.begin()->max()); +} + +TEST_F(QuicIntervalSetTest, QuicIntervalSetDifferenceIdentical) { + QuicIntervalSet<string> mine; + mine.Add("a", "b"); + mine.Add("c", "d"); + QuicIntervalSet<string> theirs(mine); + + mine.Difference(theirs); + EXPECT_TRUE(mine.Empty()); +} + +TEST_F(QuicIntervalSetTest, EmptyComplement) { + // The complement of an empty set is the input interval: + QuicIntervalSet<int> iset; + iset.Complement(100, 200); + EXPECT_TRUE(Check(iset, 1, 100, 200)); +} + +TEST(QuicIntervalSetMultipleCompactionTest, OuterCovering) { + QuicIntervalSet<int> iset; + // First add a bunch of disjoint ranges + iset.Add(100, 150); + iset.Add(200, 250); + iset.Add(300, 350); + iset.Add(400, 450); + EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450)); + // Now add a big range that covers all of these ranges + iset.Add(0, 500); + EXPECT_TRUE(Check(iset, 1, 0, 500)); +} + +TEST(QuicIntervalSetMultipleCompactionTest, InnerCovering) { + QuicIntervalSet<int> iset; + // First add a bunch of disjoint ranges + iset.Add(100, 150); + iset.Add(200, 250); + iset.Add(300, 350); + iset.Add(400, 450); + EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450)); + // Now add a big range that partially covers the left and right most ranges. + iset.Add(125, 425); + EXPECT_TRUE(Check(iset, 1, 100, 450)); +} + +TEST(QuicIntervalSetMultipleCompactionTest, LeftCovering) { + QuicIntervalSet<int> iset; + // First add a bunch of disjoint ranges + iset.Add(100, 150); + iset.Add(200, 250); + iset.Add(300, 350); + iset.Add(400, 450); + EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450)); + // Now add a big range that partially covers the left most range. + iset.Add(125, 500); + EXPECT_TRUE(Check(iset, 1, 100, 500)); +} + +TEST(QuicIntervalSetMultipleCompactionTest, RightCovering) { + QuicIntervalSet<int> iset; + // First add a bunch of disjoint ranges + iset.Add(100, 150); + iset.Add(200, 250); + iset.Add(300, 350); + iset.Add(400, 450); + EXPECT_TRUE(Check(iset, 4, 100, 150, 200, 250, 300, 350, 400, 450)); + // Now add a big range that partially covers the right most range. + iset.Add(0, 425); + EXPECT_TRUE(Check(iset, 1, 0, 450)); +} + +// Helper method for testing and verifying the results of a one-interval +// completement case. +static bool CheckOneComplement(int add_min, + int add_max, + int comp_min, + int comp_max, + int count, + ...) { + QuicIntervalSet<int> iset; + iset.Add(add_min, add_max); + iset.Complement(comp_min, comp_max); + bool result = true; + va_list ap; + va_start(ap, count); + if (!VA_Check(iset, count, ap)) { + result = false; + } + va_end(ap); + return result; +} + +TEST_F(QuicIntervalSetTest, SingleIntervalComplement) { + // Verify the complement of a set with one interval (i): + // |----- i -----| + // |----- args -----| + EXPECT_TRUE(CheckOneComplement(0, 10, 50, 150, 1, 50, 150)); + + // |----- i -----| + // |----- args -----| + EXPECT_TRUE(CheckOneComplement(50, 150, 0, 100, 1, 0, 50)); + + // |----- i -----| + // |----- args -----| + EXPECT_TRUE(CheckOneComplement(50, 150, 50, 150, 0)); + + // |---------- i ----------| + // |----- args -----| + EXPECT_TRUE(CheckOneComplement(50, 500, 100, 300, 0)); + + // |----- i -----| + // |---------- args ----------| + EXPECT_TRUE(CheckOneComplement(50, 500, 0, 800, 2, 0, 50, 500, 800)); + + // |----- i -----| + // |----- args -----| + EXPECT_TRUE(CheckOneComplement(50, 150, 100, 300, 1, 150, 300)); + + // |----- i -----| + // |----- args -----| + EXPECT_TRUE(CheckOneComplement(50, 150, 200, 300, 1, 200, 300)); +} + +// Helper method that copies <iset> and takes its complement, +// returning false if Check succeeds. +static bool CheckComplement(const QuicIntervalSet<int>& iset, + int comp_min, + int comp_max, + int count, + ...) { + QuicIntervalSet<int> iset_copy = iset; + iset_copy.Complement(comp_min, comp_max); + bool result = true; + va_list ap; + va_start(ap, count); + if (!VA_Check(iset_copy, count, ap)) { + result = false; + } + va_end(ap); + return result; +} + +TEST_F(QuicIntervalSetTest, MultiIntervalComplement) { + // Initialize a small test set: + QuicIntervalSet<int> iset; + iset.Add(100, 200); + iset.Add(300, 400); + iset.Add(500, 600); + + // |----- i -----| + // |----- comp -----| + EXPECT_TRUE(CheckComplement(iset, 0, 50, 1, 0, 50)); + + // |----- i -----| + // |----- comp -----| + EXPECT_TRUE(CheckComplement(iset, 0, 200, 1, 0, 100)); + EXPECT_TRUE(CheckComplement(iset, 0, 220, 2, 0, 100, 200, 220)); + + // |----- i -----| + // |----- comp -----| + EXPECT_TRUE(CheckComplement(iset, 100, 600, 2, 200, 300, 400, 500)); + + // |---------- i ----------| + // |----- comp -----| + EXPECT_TRUE(CheckComplement(iset, 300, 400, 0)); + EXPECT_TRUE(CheckComplement(iset, 250, 400, 1, 250, 300)); + EXPECT_TRUE(CheckComplement(iset, 300, 450, 1, 400, 450)); + EXPECT_TRUE(CheckComplement(iset, 250, 450, 2, 250, 300, 400, 450)); + + // |----- i -----| + // |---------- comp ----------| + EXPECT_TRUE( + CheckComplement(iset, 0, 700, 4, 0, 100, 200, 300, 400, 500, 600, 700)); + + // |----- i -----| + // |----- comp -----| + EXPECT_TRUE(CheckComplement(iset, 400, 700, 2, 400, 500, 600, 700)); + EXPECT_TRUE(CheckComplement(iset, 350, 700, 2, 400, 500, 600, 700)); + + // |----- i -----| + // |----- comp -----| + EXPECT_TRUE(CheckComplement(iset, 700, 800, 1, 700, 800)); +} + +// Verifies ToString, operator<< don't assert. +TEST_F(QuicIntervalSetTest, ToString) { + QuicIntervalSet<int> iset; + iset.Add(300, 400); + iset.Add(100, 200); + iset.Add(500, 600); + EXPECT_TRUE(!iset.ToString().empty()); + QUIC_VLOG(2) << iset; + // Order and format of ToString() output is guaranteed. + EXPECT_EQ("{ [100, 200) [300, 400) [500, 600) }", iset.ToString()); + EXPECT_EQ("{ [1, 2) }", QuicIntervalSet<int>(1, 2).ToString()); + EXPECT_EQ("{ }", QuicIntervalSet<int>().ToString()); +} + +TEST_F(QuicIntervalSetTest, ConstructionDiscardsEmptyInterval) { + EXPECT_TRUE(QuicIntervalSet<int>(QuicInterval<int>(2, 2)).Empty()); + EXPECT_TRUE(QuicIntervalSet<int>(2, 2).Empty()); + EXPECT_FALSE(QuicIntervalSet<int>(QuicInterval<int>(2, 3)).Empty()); + EXPECT_FALSE(QuicIntervalSet<int>(2, 3).Empty()); +} + +TEST_F(QuicIntervalSetTest, Swap) { + QuicIntervalSet<int> a, b; + a.Add(300, 400); + b.Add(100, 200); + b.Add(500, 600); + a.Swap(&b); + EXPECT_TRUE(Check(a, 2, 100, 200, 500, 600)); + EXPECT_TRUE(Check(b, 1, 300, 400)); + swap(a, b); + EXPECT_TRUE(Check(a, 1, 300, 400)); + EXPECT_TRUE(Check(b, 2, 100, 200, 500, 600)); +} + +TEST_F(QuicIntervalSetTest, OutputReturnsOstreamRef) { + std::stringstream ss; + const QuicIntervalSet<int> v(QuicInterval<int>(1, 2)); + auto return_type_is_a_ref = [](std::ostream&) {}; + return_type_is_a_ref(ss << v); +} + +struct NotOstreamable { + bool operator<(const NotOstreamable& other) const { return false; } + bool operator>(const NotOstreamable& other) const { return false; } + bool operator!=(const NotOstreamable& other) const { return false; } + bool operator>=(const NotOstreamable& other) const { return true; } + bool operator<=(const NotOstreamable& other) const { return true; } + bool operator==(const NotOstreamable& other) const { return true; } +}; + +TEST_F(QuicIntervalSetTest, IntervalOfTypeWithNoOstreamSupport) { + const NotOstreamable v; + const QuicIntervalSet<NotOstreamable> d(QuicInterval<NotOstreamable>(v, v)); + // EXPECT_EQ builds a string representation of d. If d::operator<<() + // would be defined then this test would not compile because NotOstreamable + // objects lack the operator<<() support. + EXPECT_EQ(d, d); +} + +class QuicIntervalSetInitTest : public QuicTest { + protected: + const std::vector<QuicInterval<int>> intervals_{{0, 1}, {2, 4}}; +}; + +TEST_F(QuicIntervalSetInitTest, DirectInit) { + std::initializer_list<QuicInterval<int>> il = {{0, 1}, {2, 3}, {3, 4}}; + QuicIntervalSet<int> s(il); + EXPECT_THAT(s, ElementsAreArray(intervals_)); +} + +TEST_F(QuicIntervalSetInitTest, CopyInit) { + std::initializer_list<QuicInterval<int>> il = {{0, 1}, {2, 3}, {3, 4}}; + QuicIntervalSet<int> s = il; + EXPECT_THAT(s, ElementsAreArray(intervals_)); +} + +TEST_F(QuicIntervalSetInitTest, AssignIterPair) { + QuicIntervalSet<int> s(0, 1000); // Make sure assign clears. + s.assign(intervals_.begin(), intervals_.end()); + EXPECT_THAT(s, ElementsAreArray(intervals_)); +} + +TEST_F(QuicIntervalSetInitTest, AssignInitList) { + QuicIntervalSet<int> s(0, 1000); // Make sure assign clears. + s.assign({{0, 1}, {2, 3}, {3, 4}}); + EXPECT_THAT(s, ElementsAreArray(intervals_)); +} + +TEST_F(QuicIntervalSetInitTest, AssignmentInitList) { + std::initializer_list<QuicInterval<int>> il = {{0, 1}, {2, 3}, {3, 4}}; + QuicIntervalSet<int> s; + s = il; + EXPECT_THAT(s, ElementsAreArray(intervals_)); +} + +TEST_F(QuicIntervalSetInitTest, BracedInitThenBracedAssign) { + QuicIntervalSet<int> s{{0, 1}, {2, 3}, {3, 4}}; + s = {{0, 1}, {2, 4}}; + EXPECT_THAT(s, ElementsAreArray(intervals_)); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/quic_interval_test.cc b/quic/core/quic_interval_test.cc new file mode 100644 index 0000000..3cb134e --- /dev/null +++ b/quic/core/quic_interval_test.cc
@@ -0,0 +1,457 @@ +// 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. + +#include "net/third_party/quiche/src/quic/core/quic_interval.h" + +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +#include "net/third_party/quiche/src/quic/core/quic_time.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" + +namespace quic { +namespace test { +namespace { + +template <typename ForwardIterator> +void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) { + while (begin != end) { + auto temp = begin; + ++begin; + delete *temp; + } +} + +template <typename T> +void STLDeleteElements(T* container) { + if (!container) + return; + STLDeleteContainerPointers(container->begin(), container->end()); + container->clear(); +} + +class ConstructorListener { + public: + ConstructorListener(int* copy_construct_counter, int* move_construct_counter) + : copy_construct_counter_(copy_construct_counter), + move_construct_counter_(move_construct_counter) { + *copy_construct_counter_ = 0; + *move_construct_counter_ = 0; + } + ConstructorListener(const ConstructorListener& other) { + copy_construct_counter_ = other.copy_construct_counter_; + move_construct_counter_ = other.move_construct_counter_; + ++*copy_construct_counter_; + } + ConstructorListener(ConstructorListener&& other) { + copy_construct_counter_ = other.copy_construct_counter_; + move_construct_counter_ = other.move_construct_counter_; + ++*move_construct_counter_; + } + bool operator<(const ConstructorListener&) { return false; } + bool operator>(const ConstructorListener&) { return false; } + bool operator<=(const ConstructorListener&) { return true; } + bool operator>=(const ConstructorListener&) { return true; } + bool operator==(const ConstructorListener&) { return true; } + + private: + int* copy_construct_counter_; + int* move_construct_counter_; +}; + +TEST(IntervalConstructorTest, Move) { + int object1_copy_count, object1_move_count; + ConstructorListener object1(&object1_copy_count, &object1_move_count); + int object2_copy_count, object2_move_count; + ConstructorListener object2(&object2_copy_count, &object2_move_count); + + QuicInterval<ConstructorListener> interval(object1, std::move(object2)); + EXPECT_EQ(1, object1_copy_count); + EXPECT_EQ(0, object1_move_count); + EXPECT_EQ(0, object2_copy_count); + EXPECT_EQ(1, object2_move_count); +} + +TEST(IntervalConstructorTest, ImplicitConversion) { + struct WrappedInt { + WrappedInt(int value) : value(value) {} + bool operator<(const WrappedInt& other) { return value < other.value; } + bool operator>(const WrappedInt& other) { return value > other.value; } + bool operator<=(const WrappedInt& other) { return value <= other.value; } + bool operator>=(const WrappedInt& other) { return value >= other.value; } + bool operator==(const WrappedInt& other) { return value == other.value; } + int value; + }; + + static_assert(std::is_convertible<int, WrappedInt>::value, ""); + static_assert( + std::is_constructible<QuicInterval<WrappedInt>, int, int>::value, ""); + + QuicInterval<WrappedInt> i(10, 20); + EXPECT_EQ(10, i.min().value); + EXPECT_EQ(20, i.max().value); +} + +class IntervalTest : public QuicTest { + protected: + // Test intersection between the two intervals i1 and i2. Tries + // i1.IntersectWith(i2) and vice versa. The intersection should change i1 iff + // changes_i1 is true, and the same for changes_i2. The resulting + // intersection should be result. + void TestIntersect(const QuicInterval<int64_t>& i1, + const QuicInterval<int64_t>& i2, + bool changes_i1, + bool changes_i2, + const QuicInterval<int64_t>& result) { + QuicInterval<int64_t> i; + i = i1; + EXPECT_TRUE(i.IntersectWith(i2) == changes_i1 && i == result); + i = i2; + EXPECT_TRUE(i.IntersectWith(i1) == changes_i2 && i == result); + } +}; + +TEST_F(IntervalTest, ConstructorsCopyAndClear) { + QuicInterval<int32_t> empty; + EXPECT_TRUE(empty.Empty()); + + QuicInterval<int32_t> d2(0, 100); + EXPECT_EQ(0, d2.min()); + EXPECT_EQ(100, d2.max()); + EXPECT_EQ(QuicInterval<int32_t>(0, 100), d2); + EXPECT_NE(QuicInterval<int32_t>(0, 99), d2); + + empty = d2; + EXPECT_EQ(0, d2.min()); + EXPECT_EQ(100, d2.max()); + EXPECT_TRUE(empty == d2); + EXPECT_EQ(empty, d2); + EXPECT_TRUE(d2 == empty); + EXPECT_EQ(d2, empty); + + QuicInterval<int32_t> max_less_than_min(40, 20); + EXPECT_TRUE(max_less_than_min.Empty()); + EXPECT_EQ(40, max_less_than_min.min()); + EXPECT_EQ(20, max_less_than_min.max()); + + QuicInterval<int> d3(10, 20); + d3.Clear(); + EXPECT_TRUE(d3.Empty()); +} + +TEST_F(IntervalTest, MakeQuicInterval) { + static_assert( + std::is_same<QuicInterval<int>, decltype(MakeQuicInterval(0, 3))>::value, + "Type is deduced incorrectly."); + static_assert(std::is_same<QuicInterval<double>, + decltype(MakeQuicInterval(0., 3.))>::value, + "Type is deduced incorrectly."); + + EXPECT_EQ(MakeQuicInterval(0., 3.), QuicInterval<double>(0, 3)); +} + +TEST_F(IntervalTest, GettersSetters) { + QuicInterval<int32_t> d1(100, 200); + + // SetMin: + d1.SetMin(30); + EXPECT_EQ(30, d1.min()); + EXPECT_EQ(200, d1.max()); + + // SetMax: + d1.SetMax(220); + EXPECT_EQ(30, d1.min()); + EXPECT_EQ(220, d1.max()); + + // Set: + d1.Clear(); + d1.Set(30, 220); + EXPECT_EQ(30, d1.min()); + EXPECT_EQ(220, d1.max()); + + // SpanningUnion: + QuicInterval<int32_t> d2; + EXPECT_TRUE(!d1.SpanningUnion(d2)); + EXPECT_EQ(30, d1.min()); + EXPECT_EQ(220, d1.max()); + + EXPECT_TRUE(d2.SpanningUnion(d1)); + EXPECT_EQ(30, d2.min()); + EXPECT_EQ(220, d2.max()); + + d2.SetMin(40); + d2.SetMax(100); + EXPECT_TRUE(!d1.SpanningUnion(d2)); + EXPECT_EQ(30, d1.min()); + EXPECT_EQ(220, d1.max()); + + d2.SetMin(20); + d2.SetMax(100); + EXPECT_TRUE(d1.SpanningUnion(d2)); + EXPECT_EQ(20, d1.min()); + EXPECT_EQ(220, d1.max()); + + d2.SetMin(50); + d2.SetMax(300); + EXPECT_TRUE(d1.SpanningUnion(d2)); + EXPECT_EQ(20, d1.min()); + EXPECT_EQ(300, d1.max()); + + d2.SetMin(0); + d2.SetMax(500); + EXPECT_TRUE(d1.SpanningUnion(d2)); + EXPECT_EQ(0, d1.min()); + EXPECT_EQ(500, d1.max()); + + d2.SetMin(100); + d2.SetMax(0); + EXPECT_TRUE(!d1.SpanningUnion(d2)); + EXPECT_EQ(0, d1.min()); + EXPECT_EQ(500, d1.max()); + EXPECT_TRUE(d2.SpanningUnion(d1)); + EXPECT_EQ(0, d2.min()); + EXPECT_EQ(500, d2.max()); +} + +TEST_F(IntervalTest, CoveringOps) { + const QuicInterval<int64_t> empty; + const QuicInterval<int64_t> d(100, 200); + const QuicInterval<int64_t> d1(0, 50); + const QuicInterval<int64_t> d2(50, 110); + const QuicInterval<int64_t> d3(110, 180); + const QuicInterval<int64_t> d4(180, 220); + const QuicInterval<int64_t> d5(220, 300); + const QuicInterval<int64_t> d6(100, 150); + const QuicInterval<int64_t> d7(150, 200); + const QuicInterval<int64_t> d8(0, 300); + + // Intersection: + EXPECT_TRUE(d.Intersects(d)); + EXPECT_TRUE(!empty.Intersects(d) && !d.Intersects(empty)); + EXPECT_TRUE(!d.Intersects(d1) && !d1.Intersects(d)); + EXPECT_TRUE(d.Intersects(d2) && d2.Intersects(d)); + EXPECT_TRUE(d.Intersects(d3) && d3.Intersects(d)); + EXPECT_TRUE(d.Intersects(d4) && d4.Intersects(d)); + EXPECT_TRUE(!d.Intersects(d5) && !d5.Intersects(d)); + EXPECT_TRUE(d.Intersects(d6) && d6.Intersects(d)); + EXPECT_TRUE(d.Intersects(d7) && d7.Intersects(d)); + EXPECT_TRUE(d.Intersects(d8) && d8.Intersects(d)); + + QuicInterval<int64_t> i; + EXPECT_TRUE(d.Intersects(d, &i) && d == i); + EXPECT_TRUE(!empty.Intersects(d, nullptr) && !d.Intersects(empty, nullptr)); + EXPECT_TRUE(!d.Intersects(d1, nullptr) && !d1.Intersects(d, nullptr)); + EXPECT_TRUE(d.Intersects(d2, &i) && i == QuicInterval<int64_t>(100, 110)); + EXPECT_TRUE(d2.Intersects(d, &i) && i == QuicInterval<int64_t>(100, 110)); + EXPECT_TRUE(d.Intersects(d3, &i) && i == d3); + EXPECT_TRUE(d3.Intersects(d, &i) && i == d3); + EXPECT_TRUE(d.Intersects(d4, &i) && i == QuicInterval<int64_t>(180, 200)); + EXPECT_TRUE(d4.Intersects(d, &i) && i == QuicInterval<int64_t>(180, 200)); + EXPECT_TRUE(!d.Intersects(d5, nullptr) && !d5.Intersects(d, nullptr)); + EXPECT_TRUE(d.Intersects(d6, &i) && i == d6); + EXPECT_TRUE(d6.Intersects(d, &i) && i == d6); + EXPECT_TRUE(d.Intersects(d7, &i) && i == d7); + EXPECT_TRUE(d7.Intersects(d, &i) && i == d7); + EXPECT_TRUE(d.Intersects(d8, &i) && i == d); + EXPECT_TRUE(d8.Intersects(d, &i) && i == d); + + // Test IntersectsWith(). + // Arguments are TestIntersect(i1, i2, changes_i1, changes_i2, result). + TestIntersect(empty, d, false, true, empty); + TestIntersect(d, d1, true, true, empty); + TestIntersect(d1, d2, true, true, empty); + TestIntersect(d, d2, true, true, QuicInterval<int64_t>(100, 110)); + TestIntersect(d8, d, true, false, d); + TestIntersect(d8, d1, true, false, d1); + TestIntersect(d8, d5, true, false, d5); + + // Contains: + EXPECT_TRUE(!empty.Contains(d) && !d.Contains(empty)); + EXPECT_TRUE(d.Contains(d)); + EXPECT_TRUE(!d.Contains(d1) && !d1.Contains(d)); + EXPECT_TRUE(!d.Contains(d2) && !d2.Contains(d)); + EXPECT_TRUE(d.Contains(d3) && !d3.Contains(d)); + EXPECT_TRUE(!d.Contains(d4) && !d4.Contains(d)); + EXPECT_TRUE(!d.Contains(d5) && !d5.Contains(d)); + EXPECT_TRUE(d.Contains(d6) && !d6.Contains(d)); + EXPECT_TRUE(d.Contains(d7) && !d7.Contains(d)); + EXPECT_TRUE(!d.Contains(d8) && d8.Contains(d)); + + EXPECT_TRUE(d.Contains(100)); + EXPECT_TRUE(!d.Contains(200)); + EXPECT_TRUE(d.Contains(150)); + EXPECT_TRUE(!d.Contains(99)); + EXPECT_TRUE(!d.Contains(201)); + + // Difference: + std::vector<QuicInterval<int64_t>*> diff; + + EXPECT_TRUE(!d.Difference(empty, &diff)); + EXPECT_EQ(1, diff.size()); + EXPECT_EQ(100, diff[0]->min()); + EXPECT_EQ(200, diff[0]->max()); + STLDeleteElements(&diff); + EXPECT_TRUE(!empty.Difference(d, &diff) && diff.empty()); + + EXPECT_TRUE(d.Difference(d, &diff) && diff.empty()); + EXPECT_TRUE(!d.Difference(d1, &diff)); + EXPECT_EQ(1, diff.size()); + EXPECT_EQ(100, diff[0]->min()); + EXPECT_EQ(200, diff[0]->max()); + STLDeleteElements(&diff); + + QuicInterval<int64_t> lo; + QuicInterval<int64_t> hi; + + EXPECT_TRUE(d.Difference(d2, &lo, &hi)); + EXPECT_TRUE(lo.Empty()); + EXPECT_EQ(110, hi.min()); + EXPECT_EQ(200, hi.max()); + EXPECT_TRUE(d.Difference(d2, &diff)); + EXPECT_EQ(1, diff.size()); + EXPECT_EQ(110, diff[0]->min()); + EXPECT_EQ(200, diff[0]->max()); + STLDeleteElements(&diff); + + EXPECT_TRUE(d.Difference(d3, &lo, &hi)); + EXPECT_EQ(100, lo.min()); + EXPECT_EQ(110, lo.max()); + EXPECT_EQ(180, hi.min()); + EXPECT_EQ(200, hi.max()); + EXPECT_TRUE(d.Difference(d3, &diff)); + EXPECT_EQ(2, diff.size()); + EXPECT_EQ(100, diff[0]->min()); + EXPECT_EQ(110, diff[0]->max()); + EXPECT_EQ(180, diff[1]->min()); + EXPECT_EQ(200, diff[1]->max()); + STLDeleteElements(&diff); + + EXPECT_TRUE(d.Difference(d4, &lo, &hi)); + EXPECT_EQ(100, lo.min()); + EXPECT_EQ(180, lo.max()); + EXPECT_TRUE(hi.Empty()); + EXPECT_TRUE(d.Difference(d4, &diff)); + EXPECT_EQ(1, diff.size()); + EXPECT_EQ(100, diff[0]->min()); + EXPECT_EQ(180, diff[0]->max()); + STLDeleteElements(&diff); + + EXPECT_FALSE(d.Difference(d5, &lo, &hi)); + EXPECT_EQ(100, lo.min()); + EXPECT_EQ(200, lo.max()); + EXPECT_TRUE(hi.Empty()); + EXPECT_FALSE(d.Difference(d5, &diff)); + EXPECT_EQ(1, diff.size()); + EXPECT_EQ(100, diff[0]->min()); + EXPECT_EQ(200, diff[0]->max()); + STLDeleteElements(&diff); + + EXPECT_TRUE(d.Difference(d6, &lo, &hi)); + EXPECT_TRUE(lo.Empty()); + EXPECT_EQ(150, hi.min()); + EXPECT_EQ(200, hi.max()); + EXPECT_TRUE(d.Difference(d6, &diff)); + EXPECT_EQ(1, diff.size()); + EXPECT_EQ(150, diff[0]->min()); + EXPECT_EQ(200, diff[0]->max()); + STLDeleteElements(&diff); + + EXPECT_TRUE(d.Difference(d7, &lo, &hi)); + EXPECT_EQ(100, lo.min()); + EXPECT_EQ(150, lo.max()); + EXPECT_TRUE(hi.Empty()); + EXPECT_TRUE(d.Difference(d7, &diff)); + EXPECT_EQ(1, diff.size()); + EXPECT_EQ(100, diff[0]->min()); + EXPECT_EQ(150, diff[0]->max()); + STLDeleteElements(&diff); + + EXPECT_TRUE(d.Difference(d8, &lo, &hi)); + EXPECT_TRUE(lo.Empty()); + EXPECT_TRUE(hi.Empty()); + EXPECT_TRUE(d.Difference(d8, &diff) && diff.empty()); +} + +TEST_F(IntervalTest, Length) { + const QuicInterval<int> empty1; + const QuicInterval<int> empty2(1, 1); + const QuicInterval<int> empty3(1, 0); + const QuicInterval<QuicTime> empty4( + QuicTime::Zero() + QuicTime::Delta::FromSeconds(1), QuicTime::Zero()); + const QuicInterval<int> d1(1, 2); + const QuicInterval<int> d2(0, 50); + const QuicInterval<QuicTime> d3( + QuicTime::Zero(), QuicTime::Zero() + QuicTime::Delta::FromSeconds(1)); + const QuicInterval<QuicTime> d4( + QuicTime::Zero() + QuicTime::Delta::FromSeconds(3600), + QuicTime::Zero() + QuicTime::Delta::FromSeconds(5400)); + + EXPECT_EQ(0, empty1.Length()); + EXPECT_EQ(0, empty2.Length()); + EXPECT_EQ(0, empty3.Length()); + EXPECT_EQ(QuicTime::Delta::Zero(), empty4.Length()); + EXPECT_EQ(1, d1.Length()); + EXPECT_EQ(50, d2.Length()); + EXPECT_EQ(QuicTime::Delta::FromSeconds(1), d3.Length()); + EXPECT_EQ(QuicTime::Delta::FromSeconds(1800), d4.Length()); +} + +TEST_F(IntervalTest, IntervalOfTypeWithNoOperatorMinus) { + // QuicInterval<T> should work even if T does not support operator-(). We + // just can't call QuicInterval<T>::Length() for such types. + const QuicInterval<string> d1("a", "b"); + const QuicInterval<std::pair<int, int>> d2({1, 2}, {4, 3}); + EXPECT_EQ("a", d1.min()); + EXPECT_EQ("b", d1.max()); + EXPECT_EQ(std::make_pair(1, 2), d2.min()); + EXPECT_EQ(std::make_pair(4, 3), d2.max()); +} + +struct NoEquals { + NoEquals(int v) : value(v) {} // NOLINT + int value; + bool operator<(const NoEquals& other) const { return value < other.value; } +}; + +TEST_F(IntervalTest, OrderedComparisonForTypeWithoutEquals) { + const QuicInterval<NoEquals> d1(0, 4); + const QuicInterval<NoEquals> d2(0, 3); + const QuicInterval<NoEquals> d3(1, 4); + const QuicInterval<NoEquals> d4(1, 5); + const QuicInterval<NoEquals> d6(0, 4); + EXPECT_TRUE(d1 < d2); + EXPECT_TRUE(d1 < d3); + EXPECT_TRUE(d1 < d4); + EXPECT_FALSE(d1 < d6); +} + +TEST_F(IntervalTest, OutputReturnsOstreamRef) { + std::stringstream ss; + const QuicInterval<int> v(1, 2); + // If (ss << v) were to return a value, it wouldn't match the signature of + // return_type_is_a_ref() function. + auto return_type_is_a_ref = [](std::ostream&) {}; + return_type_is_a_ref(ss << v); +} + +struct NotOstreamable { + bool operator<(const NotOstreamable& other) const { return false; } + bool operator>=(const NotOstreamable& other) const { return true; } + bool operator==(const NotOstreamable& other) const { return true; } +}; + +TEST_F(IntervalTest, IntervalOfTypeWithNoOstreamSupport) { + const NotOstreamable v; + const QuicInterval<NotOstreamable> d(v, v); + // EXPECT_EQ builds a string representation of d. If d::operator<<() would be + // defined then this test would not compile because NotOstreamable objects + // lack the operator<<() support. + EXPECT_EQ(d, d); +} + +} // namespace +} // namespace test +} // namespace quic
diff --git a/quic/core/quic_packet_creator.cc b/quic/core/quic_packet_creator.cc index cc4f50e..6ad5351 100644 --- a/quic/core/quic_packet_creator.cc +++ b/quic/core/quic_packet_creator.cc
@@ -21,8 +21,29 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" namespace quic { +namespace { + +QuicLongHeaderType EncryptionlevelToLongHeaderType(EncryptionLevel level) { + switch (level) { + case ENCRYPTION_NONE: + return INITIAL; + case ENCRYPTION_ZERO_RTT: + return ZERO_RTT_PROTECTED; + case ENCRYPTION_FORWARD_SECURE: + QUIC_BUG + << "Try to derive long header type for packet with encryption level: " + << QuicUtils::EncryptionLevelToString(level); + return INVALID_PACKET_TYPE; + default: + QUIC_BUG << QuicUtils::EncryptionLevelToString(level); + return INVALID_PACKET_TYPE; + } +} + +} // namespace #define ENDPOINT \ (framer_->perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ") @@ -60,7 +81,9 @@ needs_full_padding_(false), can_set_transmission_type_(false), set_transmission_type_for_next_frame_( - GetQuicReloadableFlag(quic_set_transmission_type_for_next_frame)) { + GetQuicReloadableFlag(quic_set_transmission_type_for_next_frame)), + encryption_level_driven_long_header_type_( + GetQuicReloadableFlag(quic_encryption_driven_header_type)) { SetMaxPacketLength(kDefaultMaxPacketSize); } @@ -132,6 +155,25 @@ framer_->transport_version(), QuicPacketNumber(delta * 4)); } +bool QuicPacketCreator::ConsumeCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset, + TransmissionType transmission_type, + QuicFrame* frame) { + if (!CreateCryptoFrame(level, write_length, offset, frame)) { + return false; + } + // When crypto data was sent in stream frames, ConsumeData is called with + // |needs_full_padding = true|. Keep the same behavior here when sending + // crypto frames. + // + // TODO(nharper): Check what the IETF drafts say about padding out initial + // messages and change this as appropriate. + needs_full_padding_ = true; + return AddFrame(*frame, /*save_retransmittable_frames*/ true, + transmission_type); +} + bool QuicPacketCreator::ConsumeData(QuicStreamId id, size_t write_length, size_t iov_offset, @@ -190,7 +232,7 @@ // this information, leading to a cascade of changes and B) the // higher-up software does not always loop, calling // StreamFramePacketOverhead() once for every packet -- eg there is -// a test in quic_connetion_test that calls it once and assumes that +// a test in quic_connection_test that calls it once and assumes that // the value is the same for all packets. // static @@ -201,13 +243,16 @@ bool include_version, bool include_diversification_nonce, QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicVariableLengthIntegerLength length_length, QuicStreamOffset offset) { return GetPacketHeaderSize(version, destination_connection_id_length, source_connection_id_length, include_version, include_diversification_nonce, - packet_number_length) + + packet_number_length, retry_token_length_length, 0, + length_length) + - // Assumes this is packet with a aingle stream frame in it. Since + // Assumes this is a packet with a single stream frame in it. Since // last_frame_in_packet is set true, the size of the length field is // not included in the calculation. This is OK because in other places // in the code, the logic adds back 2 (the size of the Google QUIC @@ -236,7 +281,8 @@ StreamFramePacketOverhead( framer_->transport_version(), GetDestinationConnectionIdLength(), GetSourceConnectionIdLength(), kIncludeVersion, - IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER, offset)); + IncludeNonceInPublicHeader(), PACKET_6BYTE_PACKET_NUMBER, + GetRetryTokenLengthLength(), GetLengthLength(), offset)); QUIC_BUG_IF(!HasRoomForStreamFrame(id, offset, data_size)) << "No room for Stream frame, BytesFree: " << BytesFree() @@ -261,6 +307,21 @@ *frame = QuicFrame(QuicStreamFrame(id, set_fin, offset, bytes_consumed)); } +bool QuicPacketCreator::CreateCryptoFrame(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset, + QuicFrame* frame) { + size_t min_frame_size = + QuicFramer::GetMinCryptoFrameSize(write_length, offset); + if (BytesFree() <= min_frame_size) { + return false; + } + size_t max_write_length = BytesFree() - min_frame_size; + size_t bytes_consumed = std::min<size_t>(max_write_length, write_length); + *frame = QuicFrame(new QuicCryptoFrame(level, offset, bytes_consumed)); + return true; +} + void QuicPacketCreator::ReserializeAllFrames( const QuicPendingRetransmission& retransmission, char* buffer, @@ -369,9 +430,9 @@ encrypted_buffer = stack_buffer; } - QuicDataWriter writer(kMaxPacketSize, encrypted_buffer, - framer_->endianness()); - if (!framer_->AppendPacketHeader(header, &writer)) { + QuicDataWriter writer(kMaxPacketSize, encrypted_buffer); + size_t length_field_offset = 0; + if (!framer_->AppendPacketHeader(header, &writer, &length_field_offset)) { QUIC_BUG << "AppendPacketHeader failed"; return; } @@ -405,6 +466,11 @@ return; } + if (!framer_->WriteIetfLongHeaderLength(header, &writer, length_field_offset, + packet_.encryption_level)) { + return; + } + if (ShouldSetTransmissionTypeForNextFrame()) { QUIC_RELOADABLE_FLAG_COUNT_N(quic_set_transmission_type_for_next_frame, 1, 2); @@ -453,7 +519,7 @@ !queued_frames_.empty() && queued_frames_.back().type == MESSAGE_FRAME; if (has_trailing_message_frame) { return QuicDataWriter::GetVarInt62Len( - queued_frames_.back().message_frame->message_data.length()); + queued_frames_.back().message_frame->message_length); } // If the last frame in the packet is a stream frame, then it will expand to // include the stream_length field when a new frame is added. @@ -482,7 +548,8 @@ packet_size_ = GetPacketHeaderSize( framer_->transport_version(), GetDestinationConnectionIdLength(), GetSourceConnectionIdLength(), IncludeVersionInHeader(), - IncludeNonceInPublicHeader(), GetPacketNumberLength()); + IncludeNonceInPublicHeader(), GetPacketNumberLength(), + GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength()); return packet_size_; } @@ -517,8 +584,9 @@ DCHECK_GE(max_plaintext_size_, packet_size_); // Use the packet_size_ instead of the buffer size to ensure smaller // packet sizes are properly used. - size_t length = framer_->BuildDataPacket(header, queued_frames_, - encrypted_buffer, packet_size_); + size_t length = + framer_->BuildDataPacket(header, queued_frames_, encrypted_buffer, + packet_size_, packet_.encryption_level); if (length == 0) { QUIC_BUG << "Failed to serialize " << queued_frames_.size() << " frames."; return; @@ -573,8 +641,8 @@ FillPacketHeader(&header); std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); - size_t length = framer_->BuildConnectivityProbingPacket(header, buffer.get(), - max_plaintext_size_); + size_t length = framer_->BuildConnectivityProbingPacket( + header, buffer.get(), max_plaintext_size_, packet_.encryption_level); DCHECK(length); const size_t encrypted_length = framer_->EncryptInPlace( @@ -606,7 +674,8 @@ std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); size_t length = framer_->BuildPaddedPathChallengePacket( - header, buffer.get(), max_plaintext_size_, payload, random_); + header, buffer.get(), max_plaintext_size_, payload, random_, + packet_.encryption_level); DCHECK(length); const size_t encrypted_length = framer_->EncryptInPlace( @@ -639,7 +708,8 @@ std::unique_ptr<char[]> buffer(new char[kMaxPacketSize]); size_t length = framer_->BuildPathResponsePacket( - header, buffer.get(), max_plaintext_size_, payloads, is_padded); + header, buffer.get(), max_plaintext_size_, payloads, is_padded, + packet_.encryption_level); DCHECK(length); const size_t encrypted_length = framer_->EncryptInPlace( @@ -691,6 +761,41 @@ return packet_.packet_number_length; } +QuicLongHeaderType QuicPacketCreator::GetLongHeaderType() const { + return (encryption_level_driven_long_header_type_ + ? EncryptionlevelToLongHeaderType(packet_.encryption_level) + : long_header_type_); +} + +QuicVariableLengthIntegerLength QuicPacketCreator::GetRetryTokenLengthLength() + const { + if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) && + HasIetfLongHeader() && GetLongHeaderType() == INITIAL) { + return QuicDataWriter::GetVarInt62Len(GetRetryToken().length()); + } + return VARIABLE_LENGTH_INTEGER_LENGTH_0; +} + +QuicStringPiece QuicPacketCreator::GetRetryToken() const { + return retry_token_; +} + +void QuicPacketCreator::SetRetryToken(QuicStringPiece retry_token) { + retry_token_ = QuicString(retry_token); +} + +QuicVariableLengthIntegerLength QuicPacketCreator::GetLengthLength() const { + if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) && + HasIetfLongHeader()) { + QuicLongHeaderType long_header_type = GetLongHeaderType(); + if (long_header_type == INITIAL || long_header_type == ZERO_RTT_PROTECTED || + long_header_type == HANDSHAKE) { + return VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + } + return VARIABLE_LENGTH_INTEGER_LENGTH_0; +} + void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { header->destination_connection_id = connection_id_; header->destination_connection_id_length = GetDestinationConnectionIdLength(); @@ -711,10 +816,14 @@ } header->packet_number = packet_.packet_number; header->packet_number_length = GetPacketNumberLength(); + header->retry_token_length_length = GetRetryTokenLengthLength(); + header->retry_token = GetRetryToken(); + header->length_length = GetLengthLength(); + header->remaining_packet_length = 0; if (!HasIetfLongHeader()) { return; } - header->long_packet_type = long_header_type_; + header->long_packet_type = GetLongHeaderType(); } bool QuicPacketCreator::AddFrame(const QuicFrame& frame, @@ -753,9 +862,7 @@ } packet_.retransmittable_frames.push_back(frame); queued_frames_.push_back(frame); - if (frame.type == STREAM_FRAME && - frame.stream_frame.stream_id == - QuicUtils::GetCryptoStreamId(framer_->transport_version())) { + if (QuicUtils::IsHandshakeFrame(frame, framer_->transport_version())) { packet_.has_crypto_handshake = IS_HANDSHAKE; } } else { @@ -819,7 +926,7 @@ bool QuicPacketCreator::IncludeNonceInPublicHeader() const { return have_diversification_nonce_ && - packet_.encryption_level == ENCRYPTION_INITIAL; + packet_.encryption_level == ENCRYPTION_ZERO_RTT; } bool QuicPacketCreator::IncludeVersionInHeader() const { @@ -873,7 +980,8 @@ const size_t packet_header_size = GetPacketHeaderSize( framer_->transport_version(), GetDestinationConnectionIdLength(), GetSourceConnectionIdLength(), IncludeVersionInHeader(), - IncludeNonceInPublicHeader(), GetPacketNumberLength()); + IncludeNonceInPublicHeader(), GetPacketNumberLength(), + GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength()); // This is the largest possible message payload when the length field is // omitted. return max_plaintext_size_ -
diff --git a/quic/core/quic_packet_creator.h b/quic/core/quic_packet_creator.h index ef4fa37..c159026 100644 --- a/quic/core/quic_packet_creator.h +++ b/quic/core/quic_packet_creator.h
@@ -88,6 +88,8 @@ bool include_version, bool include_diversification_nonce, QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicVariableLengthIntegerLength length_length, QuicStreamOffset offset); // Returns false and flushes all pending frames if current open packet is @@ -103,13 +105,21 @@ TransmissionType transmission_type, QuicFrame* frame); + // Creates a CRYPTO frame that fits into the current packet (which must be + // empty) and adds it to the packet. + bool ConsumeCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset, + TransmissionType transmission_type, + QuicFrame* frame); + // Returns true if current open packet can accommodate more stream frames of // stream |id| at |offset| and data length |data_size|, false otherwise. bool HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset, size_t data_size); - // Returns true if current open packet can accomoodate a message frame of + // Returns true if current open packet can accommodate a message frame of // |length|. bool HasRoomForMessageFrame(QuicByteCount length); @@ -242,6 +252,9 @@ // Sets long header type of next constructed packets. void SetLongHeaderType(QuicLongHeaderType type); + // Sets the retry token to be sent over the wire in v99 IETF Initial packets. + void SetRetryToken(QuicStringPiece retry_token); + // Returns the largest payload that will fit into a single MESSAGE frame. QuicPacketLength GetLargestMessagePayload() const; @@ -276,6 +289,14 @@ bool fin, QuicFrame* frame); + // Creates a CRYPTO frame which fits into the current open packet. Returns + // false if there isn't enough room in the current open packet for a CRYPTO + // frame, and true if there is. + bool CreateCryptoFrame(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset, + QuicFrame* frame); + void FillPacketHeader(QuicPacketHeader* header); // Adds a |frame| if there is space and returns false and flushes all pending @@ -314,6 +335,21 @@ // function instead. QuicPacketNumberLength GetPacketNumberLength() const; + // Returns long header type of packet to send over the wire. + QuicLongHeaderType GetLongHeaderType() const; + + // Returns length of the retry token variable length integer to send over the + // wire. Is non-zero for v99 IETF Initial packets. + QuicVariableLengthIntegerLength GetRetryTokenLengthLength() const; + + // Returns the retry token to send over the wire, only sent in + // v99 IETF Initial packets. + QuicStringPiece GetRetryToken() const; + + // Returns length of the length variable length integer to send over the + // wire. Is non-zero for v99 IETF Initial, 0-RTT or Handshake packets. + QuicVariableLengthIntegerLength GetLengthLength() const; + // Returns true if |frame| starts with CHLO. bool StreamFrameStartsWithChlo(const QuicStreamFrame& frame) const; @@ -354,8 +390,13 @@ SerializedPacket packet_; // Long header type of next constructed packets. + // TODO(fayang): remove this variable when deprecating + // quic_encryption_driven_header_type. QuicLongHeaderType long_header_type_; + // Retry token to send over the wire in v99 IETF Initial packets. + QuicString retry_token_; + // Pending padding bytes to send. Pending padding bytes will be sent in next // packet(s) (after all other frames) if current constructed packet does not // have room to send all of them. @@ -373,6 +414,9 @@ // Latched value of --quic_set_transmission_type_for_next_frame. Don't use // this variable directly, use ShouldSetTransmissionTypeForNextFrame instead. bool set_transmission_type_for_next_frame_; + + // Latched value of gfe2_reloadable_flag_quic_encryption_driven_header_type. + const bool encryption_level_driven_long_header_type_; }; } // namespace quic
diff --git a/quic/core/quic_packet_creator_test.cc b/quic/core/quic_packet_creator_test.cc index 5dd4abb..cfc92ea 100644 --- a/quic/core/quic_packet_creator_test.cc +++ b/quic/core/quic_packet_creator_test.cc
@@ -148,8 +148,8 @@ creator_(connection_id_, &client_framer_, &delegate_, &producer_), serialized_packet_(creator_.NoPacket()) { EXPECT_CALL(delegate_, GetPacketBuffer()).WillRepeatedly(Return(nullptr)); - creator_.SetEncrypter(ENCRYPTION_INITIAL, QuicMakeUnique<NullEncrypter>( - Perspective::IS_CLIENT)); + creator_.SetEncrypter(ENCRYPTION_ZERO_RTT, QuicMakeUnique<NullEncrypter>( + Perspective::IS_CLIENT)); creator_.SetEncrypter( ENCRYPTION_FORWARD_SECURE, QuicMakeUnique<NullEncrypter>(Perspective::IS_CLIENT)); @@ -203,7 +203,9 @@ creator_.GetSourceConnectionIdLength(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)); + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(&creator_)); } // Returns the number of bytes of overhead that will be added to a packet @@ -256,14 +258,15 @@ TestPacketCreator creator_; SerializedPacket serialized_packet_; SimpleDataProducer producer_; + SimpleBufferAllocator allocator_; }; // Run all packet creator tests with all supported versions of QUIC, and with // and without version in the packet header, as well as doing a run for each // length of truncated connection id. -INSTANTIATE_TEST_CASE_P(QuicPacketCreatorTests, - QuicPacketCreatorTest, - ::testing::ValuesIn(GetTestParams())); +INSTANTIATE_TEST_SUITE_P(QuicPacketCreatorTests, + QuicPacketCreatorTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicPacketCreatorTest, SerializeFrames) { for (int i = ENCRYPTION_NONE; i < NUM_ENCRYPTION_LEVELS; ++i) { @@ -528,6 +531,15 @@ ProcessPacket(serialized); } +TEST_P(QuicPacketCreatorTest, ConsumeCryptoData) { + QuicString data = "crypto data"; + QuicFrame frame; + ASSERT_TRUE(creator_.ConsumeCryptoData(ENCRYPTION_NONE, data.length(), 0, + NOT_RETRANSMISSION, &frame)); + EXPECT_EQ(frame.crypto_frame->data_length, data.length()); + EXPECT_TRUE(creator_.HasPendingFrames()); +} + TEST_P(QuicPacketCreatorTest, ConsumeData) { QuicFrame frame; MakeIOVector("test", &iov_); @@ -1113,7 +1125,8 @@ creator_.GetDestinationConnectionIdLength(), creator_.GetSourceConnectionIdLength(), QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), - &payload_length)); + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), + QuicPacketCreatorPeer::GetLengthLength(&creator_), &payload_length)); QuicFrame frame; const QuicString too_long_payload(payload_length * 2, 'a'); MakeIOVector(too_long_payload, &iov_); @@ -1148,7 +1161,9 @@ creator_.GetSourceConnectionIdLength(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)), + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), + 0, QuicPacketCreatorPeer::GetLengthLength(&creator_)), creator_.BytesFree()); // Add a variety of frame types and then a padding frame. @@ -1202,7 +1217,9 @@ creator_.GetSourceConnectionIdLength(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(&creator_)), + QuicPacketCreatorPeer::GetPacketNumberLength(&creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(&creator_), + 0, QuicPacketCreatorPeer::GetLengthLength(&creator_)), creator_.BytesFree()); } @@ -1489,22 +1506,29 @@ .Times(3) .WillRepeatedly( Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacketForTests)); + QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); // Verify that there is enough room for the largest message payload. EXPECT_TRUE( creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload())); QuicString message(creator_.GetLargestMessagePayload(), 'a'); - EXPECT_TRUE(creator_.AddSavedFrame( - QuicFrame(new QuicMessageFrame(1, message)), NOT_RETRANSMISSION)); + QuicMessageFrame* message_frame = new QuicMessageFrame(1); + MakeSpan(&allocator_, message, &storage) + .SaveMemSlicesAsMessageData(message_frame); + EXPECT_TRUE( + creator_.AddSavedFrame(QuicFrame(message_frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); creator_.Flush(); - EXPECT_TRUE(creator_.AddSavedFrame( - QuicFrame(new QuicMessageFrame(2, "message")), NOT_RETRANSMISSION)); + QuicMessageFrame* frame2 = new QuicMessageFrame(2); + MakeSpan(&allocator_, "message", &storage).SaveMemSlicesAsMessageData(frame2); + EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame2), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); // Verify if a new frame is added, 1 byte message length will be added. EXPECT_EQ(1u, creator_.ExpansionOnNewFrame()); - EXPECT_TRUE(creator_.AddSavedFrame( - QuicFrame(new QuicMessageFrame(3, "message2")), NOT_RETRANSMISSION)); + QuicMessageFrame* frame3 = new QuicMessageFrame(3); + MakeSpan(&allocator_, "message2", &storage) + .SaveMemSlicesAsMessageData(frame3); + EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame3), NOT_RETRANSMISSION)); EXPECT_EQ(1u, creator_.ExpansionOnNewFrame()); creator_.Flush(); @@ -1513,16 +1537,17 @@ EXPECT_TRUE(creator_.ConsumeData( QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), &iov_, 1u, iov_.iov_len, 0u, 0u, false, false, NOT_RETRANSMISSION, &frame)); - EXPECT_TRUE(creator_.AddSavedFrame( - QuicFrame(new QuicMessageFrame(1, "message")), NOT_RETRANSMISSION)); + QuicMessageFrame* frame4 = new QuicMessageFrame(4); + MakeSpan(&allocator_, "message", &storage).SaveMemSlicesAsMessageData(frame4); + EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame4), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); // Verify there is not enough room for largest payload. EXPECT_FALSE( creator_.HasRoomForMessageFrame(creator_.GetLargestMessagePayload())); // Add largest message will causes the flush of the stream frame. - QuicMessageFrame message_frame(2, message); - EXPECT_FALSE( - creator_.AddSavedFrame(QuicFrame(&message_frame), NOT_RETRANSMISSION)); + QuicMessageFrame frame5(5); + MakeSpan(&allocator_, message, &storage).SaveMemSlicesAsMessageData(&frame5); + EXPECT_FALSE(creator_.AddSavedFrame(QuicFrame(&frame5), NOT_RETRANSMISSION)); EXPECT_FALSE(creator_.HasPendingFrames()); } @@ -1532,13 +1557,15 @@ } QuicString message_data(kDefaultMaxPacketSize, 'a'); QuicStringPiece message_buffer(message_data); + QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); // Test all possible size of message frames. for (size_t message_size = 0; message_size <= creator_.GetLargestMessagePayload(); ++message_size) { - EXPECT_TRUE(creator_.AddSavedFrame( - QuicFrame(new QuicMessageFrame( - 0, QuicStringPiece(message_buffer.data(), message_size))), - NOT_RETRANSMISSION)); + QuicMessageFrame* frame = new QuicMessageFrame(0); + MakeSpan(&allocator_, QuicStringPiece(message_buffer.data(), message_size), + &storage) + .SaveMemSlicesAsMessageData(frame); + EXPECT_TRUE(creator_.AddSavedFrame(QuicFrame(frame), NOT_RETRANSMISSION)); EXPECT_TRUE(creator_.HasPendingFrames()); size_t expansion_bytes = message_size >= 64 ? 2 : 1; @@ -1598,6 +1625,44 @@ DeleteSerializedPacket(); } +TEST_P(QuicPacketCreatorTest, RetryToken) { + if (!GetParam().version_serialization || + !QuicVersionHasLongHeaderLengths(client_framer_.transport_version())) { + return; + } + + char retry_token_bytes[] = {1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16}; + + creator_.SetRetryToken( + QuicString(retry_token_bytes, sizeof(retry_token_bytes))); + + frames_.push_back(QuicFrame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId(client_framer_.transport_version()), false, + 0u, QuicStringPiece()))); + SerializedPacket serialized = SerializeAllFrames(frames_); + + QuicPacketHeader header; + { + InSequence s; + EXPECT_CALL(framer_visitor_, OnPacket()); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); + EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); + EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); + EXPECT_CALL(framer_visitor_, OnPacketHeader(_)) + .WillOnce(DoAll(SaveArg<0>(&header), Return(true))); + EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); + EXPECT_CALL(framer_visitor_, OnPacketComplete()); + } + ProcessPacket(serialized); + ASSERT_TRUE(header.version_flag); + ASSERT_EQ(header.long_packet_type, INITIAL); + ASSERT_EQ(header.retry_token.length(), sizeof(retry_token_bytes)); + test::CompareCharArraysWithHexError( + "retry token", header.retry_token.data(), header.retry_token.length(), + retry_token_bytes, sizeof(retry_token_bytes)); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_packet_generator.cc b/quic/core/quic_packet_generator.cc index 12978a3..0b83030 100644 --- a/quic/core/quic_packet_generator.cc +++ b/quic/core/quic_packet_generator.cc
@@ -56,6 +56,44 @@ SendQueuedFrames(/*flush=*/false); } +size_t QuicPacketGenerator::ConsumeCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset) { + QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " + "generator tries to write crypto data."; + // To make reasoning about crypto frames easier, we don't combine them with + // other retransmittable frames in a single packet. + // TODO(nharper): Once we have separate packet number spaces, everything + // should be driven by encryption level, and we should stop flushing in this + // spot. + const bool flush = packet_creator_.HasPendingRetransmittableFrames(); + SendQueuedFrames(flush); + + size_t total_bytes_consumed = 0; + + while (total_bytes_consumed < write_length) { + QuicFrame frame; + if (!packet_creator_.ConsumeCryptoData( + level, write_length - total_bytes_consumed, + offset + total_bytes_consumed, next_transmission_type_, &frame)) { + // The only pending data in the packet is non-retransmittable frames. I'm + // assuming here that they won't occupy so much of the packet that a + // CRYPTO frame won't fit. + QUIC_BUG << "Failed to ConsumeCryptoData at level " << level; + return 0; + } + total_bytes_consumed += frame.crypto_frame->data_length; + + // TODO(ianswett): Move to having the creator flush itself when it's full. + packet_creator_.Flush(); + } + + // Don't allow the handshake to be bundled with other retransmittable frames. + SendQueuedFrames(/*flush=*/true); + + return total_bytes_consumed; +} + QuicConsumedData QuicPacketGenerator::ConsumeData(QuicStreamId id, size_t write_length, QuicStreamOffset offset, @@ -418,17 +456,19 @@ } MessageStatus QuicPacketGenerator::AddMessageFrame(QuicMessageId message_id, - QuicStringPiece message) { + QuicMemSliceSpan message) { QUIC_BUG_IF(!flusher_attached_) << "Packet flusher is not attached when " "generator tries to add message frame."; - if (message.length() > GetLargestMessagePayload()) { + const QuicByteCount message_length = message.total_length(); + if (message_length > GetLargestMessagePayload()) { return MESSAGE_STATUS_TOO_LARGE; } SendQueuedFrames(/*flush=*/false); - if (!packet_creator_.HasRoomForMessageFrame(message.length())) { + if (!packet_creator_.HasRoomForMessageFrame(message_length)) { packet_creator_.Flush(); } - QuicMessageFrame* frame = new QuicMessageFrame(message_id, message); + QuicMessageFrame* frame = new QuicMessageFrame(message_id); + message.SaveMemSlicesAsMessageData(frame); const bool success = packet_creator_.AddSavedFrame(QuicFrame(frame), next_transmission_type_); if (!success) {
diff --git a/quic/core/quic_packet_generator.h b/quic/core/quic_packet_generator.h index 572d170..d50f38e 100644 --- a/quic/core/quic_packet_generator.h +++ b/quic/core/quic_packet_generator.h
@@ -50,6 +50,7 @@ #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.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_mem_slice_span.h" namespace quic { @@ -100,6 +101,14 @@ QuicStreamOffset offset, StreamSendingState state); + // Consumes data for CRYPTO frames sent at |level| starting at |offset| for a + // total of |write_length| bytes, and returns the number of bytes consumed. + // The data is passed into the packet creator and serialized into one or more + // packets. + size_t ConsumeCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset); + // Sends as many data only packets as allowed by the send algorithm and the // available iov. // This path does not support padding, or bundling pending frames. @@ -210,7 +219,7 @@ // Tries to add a message frame containing |message| and returns the status. MessageStatus AddMessageFrame(QuicMessageId message_id, - QuicStringPiece message); + QuicMemSliceSpan message); // Returns the largest payload that will fit into a single MESSAGE frame. QuicPacketLength GetLargestMessagePayload() const;
diff --git a/quic/core/quic_packet_generator_test.cc b/quic/core/quic_packet_generator_test.cc index b85a4f7..4a2dcc5 100644 --- a/quic/core/quic_packet_generator_test.cc +++ b/quic/core/quic_packet_generator_test.cc
@@ -86,6 +86,7 @@ num_rst_stream_frames(0), num_stop_waiting_frames(0), num_stream_frames(0), + num_crypto_frames(0), num_ping_frames(0), num_mtu_discovery_frames(0), num_padding_frames(0) {} @@ -96,6 +97,7 @@ size_t num_rst_stream_frames; size_t num_stop_waiting_frames; size_t num_stream_frames; + size_t num_crypto_frames; size_t num_ping_frames; size_t num_mtu_discovery_frames; size_t num_padding_frames; @@ -140,6 +142,13 @@ return QuicPacketGenerator::ConsumeData(id, total_length, offset, state); } + size_t ConsumeCryptoData(EncryptionLevel level, + QuicStringPiece data, + QuicStreamOffset offset) { + producer_->SaveCryptoData(level, offset, data); + return QuicPacketGenerator::ConsumeCryptoData(level, data.length(), offset); + } + SimpleDataProducer* producer_; }; @@ -195,7 +204,7 @@ size_t num_retransmittable_frames = contents.num_connection_close_frames + contents.num_goaway_frames + contents.num_rst_stream_frames + contents.num_stream_frames + - contents.num_ping_frames; + contents.num_crypto_frames + contents.num_ping_frames; size_t num_frames = contents.num_ack_frames + contents.num_stop_waiting_frames + contents.num_mtu_discovery_frames + contents.num_padding_frames + @@ -222,6 +231,8 @@ simple_framer_.rst_stream_frames().size()); EXPECT_EQ(contents.num_stream_frames, simple_framer_.stream_frames().size()); + EXPECT_EQ(contents.num_crypto_frames, + simple_framer_.crypto_frames().size()); EXPECT_EQ(contents.num_stop_waiting_frames, simple_framer_.stop_waiting_frames().size()); EXPECT_EQ(contents.num_padding_frames, @@ -266,6 +277,7 @@ std::vector<SerializedPacket> packets_; QuicAckFrame ack_frame_; struct iovec iov_; + SimpleBufferAllocator allocator_; private: std::unique_ptr<char[]> data_array_; @@ -399,6 +411,23 @@ CheckPacketContains(contents, 0); } +TEST_F(QuicPacketGeneratorTest, ConsumeCryptoData) { + EXPECT_CALL(delegate_, OnSerializedPacket(_)) + .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); + QuicString data = "crypto data"; + size_t consumed_bytes = + generator_.ConsumeCryptoData(ENCRYPTION_NONE, data, 0); + generator_.Flush(); + EXPECT_EQ(data.length(), consumed_bytes); + EXPECT_FALSE(generator_.HasQueuedFrames()); + EXPECT_FALSE(generator_.HasRetransmittableFrames()); + + PacketContents contents; + contents.num_crypto_frames = 1; + contents.num_padding_frames = 1; + CheckPacketContains(contents, 0); +} + TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) { delegate_.SetCanNotWrite(); @@ -555,22 +584,25 @@ TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) { // Set the packet size be enough for two stream frames with 0 stream offset, // but not enough for a stream frame of 0 offset and one with non-zero offset. - size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + - GetPacketHeaderSize( - framer_.transport_version(), - creator_->GetDestinationConnectionIdLength(), - creator_->GetSourceConnectionIdLength(), - QuicPacketCreatorPeer::SendVersionInPacket(creator_), - !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + - // Add an extra 3 bytes for the payload and 1 byte so - // BytesFree is larger than the GetMinStreamFrameSize. - QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), - 1, 0, false, 3) + - 3 + - QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), - 1, 0, true, 1) + - 1; + size_t length = + NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + + GetPacketHeaderSize( + framer_.transport_version(), + creator_->GetDestinationConnectionIdLength(), + creator_->GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(creator_)) + + // Add an extra 3 bytes for the payload and 1 byte so + // BytesFree is larger than the GetMinStreamFrameSize. + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, + false, 3) + + 3 + + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), 1, 0, true, + 1) + + 1; generator_.SetMaxPacketLength(length); delegate_.SetCanWriteAnything(); { @@ -1227,19 +1259,22 @@ const QuicStreamId kDataStreamId = 5; // Set the packet size be enough for one stream frame with 0 stream offset and // max size of random padding. - size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + - GetPacketHeaderSize( - framer_.transport_version(), - creator_->GetDestinationConnectionIdLength(), - creator_->GetSourceConnectionIdLength(), - QuicPacketCreatorPeer::SendVersionInPacket(creator_), - !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + - QuicFramer::GetMinStreamFrameSize( - framer_.transport_version(), kDataStreamId, 0, - /*last_frame_in_packet=*/false, - kStreamFramePayloadSize + kMaxNumRandomPaddingBytes) + - kStreamFramePayloadSize + kMaxNumRandomPaddingBytes; + size_t length = + NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + + GetPacketHeaderSize( + framer_.transport_version(), + creator_->GetDestinationConnectionIdLength(), + creator_->GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(creator_)) + + QuicFramer::GetMinStreamFrameSize( + framer_.transport_version(), kDataStreamId, 0, + /*last_frame_in_packet=*/false, + kStreamFramePayloadSize + kMaxNumRandomPaddingBytes) + + kStreamFramePayloadSize + kMaxNumRandomPaddingBytes; generator_.SetMaxPacketLength(length); delegate_.SetCanWriteAnything(); EXPECT_CALL(delegate_, OnSerializedPacket(_)) @@ -1275,7 +1310,9 @@ creator_->GetSourceConnectionIdLength(), QuicPacketCreatorPeer::SendVersionInPacket(creator_), !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + + QuicPacketCreatorPeer::GetPacketNumberLength(creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(creator_)) + QuicFramer::GetMinStreamFrameSize( framer_.transport_version(), kDataStreamId, 0, /*last_frame_in_packet=*/false, kStreamFramePayloadSize + 1) + @@ -1315,22 +1352,25 @@ const QuicStreamId kDataStreamId2 = 6; // Set the packet size be enough for first frame with 0 stream offset + second // frame + 1 byte payload. two or more packets will accommodate. - size_t length = NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + - GetPacketHeaderSize( - framer_.transport_version(), - creator_->GetDestinationConnectionIdLength(), - creator_->GetSourceConnectionIdLength(), - QuicPacketCreatorPeer::SendVersionInPacket(creator_), - !kIncludeDiversificationNonce, - QuicPacketCreatorPeer::GetPacketNumberLength(creator_)) + - QuicFramer::GetMinStreamFrameSize( - framer_.transport_version(), kDataStreamId1, 0, - /*last_frame_in_packet=*/false, kStreamFramePayloadSize) + - kStreamFramePayloadSize + - QuicFramer::GetMinStreamFrameSize( - framer_.transport_version(), kDataStreamId1, 0, - /*last_frame_in_packet=*/false, 1) + - 1; + size_t length = + NullEncrypter(Perspective::IS_CLIENT).GetCiphertextSize(0) + + GetPacketHeaderSize( + framer_.transport_version(), + creator_->GetDestinationConnectionIdLength(), + creator_->GetSourceConnectionIdLength(), + QuicPacketCreatorPeer::SendVersionInPacket(creator_), + !kIncludeDiversificationNonce, + QuicPacketCreatorPeer::GetPacketNumberLength(creator_), + QuicPacketCreatorPeer::GetRetryTokenLengthLength(creator_), 0, + QuicPacketCreatorPeer::GetLengthLength(creator_)) + + QuicFramer::GetMinStreamFrameSize( + framer_.transport_version(), kDataStreamId1, 0, + /*last_frame_in_packet=*/false, kStreamFramePayloadSize) + + kStreamFramePayloadSize + + QuicFramer::GetMinStreamFrameSize(framer_.transport_version(), + kDataStreamId1, 0, + /*last_frame_in_packet=*/false, 1) + + 1; generator_.SetMaxPacketLength(length); delegate_.SetCanWriteAnything(); EXPECT_CALL(delegate_, OnSerializedPacket(_)) @@ -1370,6 +1410,7 @@ if (framer_.transport_version() <= QUIC_VERSION_44) { return; } + quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); delegate_.SetCanWriteAnything(); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); @@ -1378,21 +1419,29 @@ generator_.ConsumeData( QuicUtils::GetHeadersStreamId(framer_.transport_version()), &iov_, 1u, iov_.iov_len, 0, FIN); - EXPECT_EQ(MESSAGE_STATUS_SUCCESS, generator_.AddMessageFrame(1, "message")); + EXPECT_EQ(MESSAGE_STATUS_SUCCESS, + generator_.AddMessageFrame( + 1, MakeSpan(&allocator_, "message", &storage))); EXPECT_TRUE(generator_.HasQueuedFrames()); EXPECT_TRUE(generator_.HasRetransmittableFrames()); // Add a message which causes the flush of current packet. - EXPECT_EQ(MESSAGE_STATUS_SUCCESS, - generator_.AddMessageFrame( - 2, QuicString(generator_.GetLargestMessagePayload(), 'a'))); + EXPECT_EQ( + MESSAGE_STATUS_SUCCESS, + generator_.AddMessageFrame( + 2, MakeSpan(&allocator_, + QuicString(generator_.GetLargestMessagePayload(), 'a'), + &storage))); EXPECT_TRUE(generator_.HasRetransmittableFrames()); // Failed to send messages which cannot fit into one packet. EXPECT_EQ( MESSAGE_STATUS_TOO_LARGE, generator_.AddMessageFrame( - 3, QuicString(generator_.GetLargestMessagePayload() + 10, 'a'))); + 3, + MakeSpan(&allocator_, + QuicString(generator_.GetLargestMessagePayload() + 10, 'a'), + &storage))); } } // namespace test
diff --git a/quic/core/quic_packet_number.cc b/quic/core/quic_packet_number.cc index f0a497f..8a799c1 100644 --- a/quic/core/quic_packet_number.cc +++ b/quic/core/quic_packet_number.cc
@@ -64,9 +64,9 @@ #ifndef NDEBUG DCHECK(IsInitialized()); if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) { - DCHECK_GE(ToUint64(), 1); + DCHECK_GE(ToUint64(), 1UL); } else { - DCHECK_GT(ToUint64(), 1); + DCHECK_GT(ToUint64(), 1UL); } #endif packet_number_--; @@ -77,9 +77,9 @@ #ifndef NDEBUG DCHECK(IsInitialized()); if (GetQuicRestartFlag(quic_uint64max_uninitialized_pn)) { - DCHECK_GE(ToUint64(), 1); + DCHECK_GE(ToUint64(), 1UL); } else { - DCHECK_GT(ToUint64(), 1); + DCHECK_GT(ToUint64(), 1UL); } #endif QuicPacketNumber previous(*this);
diff --git a/quic/core/quic_packet_reader.cc b/quic/core/quic_packet_reader.cc index fc2ac15..2763b34 100644 --- a/quic/core/quic_packet_reader.cc +++ b/quic/core/quic_packet_reader.cc
@@ -20,6 +20,7 @@ #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" +#include "net/third_party/quiche/src/quic/platform/api/quic_server_stats.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/quic/platform/impl/quic_socket_utils.h" @@ -115,9 +116,12 @@ } if (QUIC_PREDICT_FALSE(mmsg_hdr_[i].msg_hdr.msg_flags & MSG_TRUNC)) { - QUIC_LOG_FIRST_N(ERROR, 10) + QUIC_LOG_FIRST_N(WARNING, 100) << "Dropping truncated QUIC packet: buffer size:" << packets_[i].iov.iov_len << " packet size:" << mmsg_hdr_[i].msg_len; + QUIC_SERVER_HISTOGRAM_COUNTS( + "QuicPacketReader.DroppedPacketSize", mmsg_hdr_[i].msg_len, 1, 10000, + 20, "In QuicPacketReader, the size of big packets that are dropped."); continue; }
diff --git a/quic/core/quic_packet_writer.h b/quic/core/quic_packet_writer.h index 3314701..c33e9b7 100644 --- a/quic/core/quic_packet_writer.h +++ b/quic/core/quic_packet_writer.h
@@ -84,11 +84,6 @@ const QuicSocketAddress& peer_address, PerPacketOptions* options) = 0; - // Returns true if the writer buffers and subsequently rewrites data - // when an attempt to write results in the underlying socket becoming - // write blocked. - virtual bool IsWriteBlockedDataBuffered() const = 0; - // Returns true if the network socket is not writable. virtual bool IsWriteBlocked() const = 0;
diff --git a/quic/core/quic_packet_writer_wrapper.cc b/quic/core/quic_packet_writer_wrapper.cc index 248bf82..f1f25d8 100644 --- a/quic/core/quic_packet_writer_wrapper.cc +++ b/quic/core/quic_packet_writer_wrapper.cc
@@ -24,10 +24,6 @@ options); } -bool QuicPacketWriterWrapper::IsWriteBlockedDataBuffered() const { - return writer_->IsWriteBlockedDataBuffered(); -} - bool QuicPacketWriterWrapper::IsWriteBlocked() const { return writer_->IsWriteBlocked(); }
diff --git a/quic/core/quic_packet_writer_wrapper.h b/quic/core/quic_packet_writer_wrapper.h index b731064..64b10f5 100644 --- a/quic/core/quic_packet_writer_wrapper.h +++ b/quic/core/quic_packet_writer_wrapper.h
@@ -30,7 +30,6 @@ const QuicIpAddress& self_address, const QuicSocketAddress& peer_address, PerPacketOptions* options) override; - bool IsWriteBlockedDataBuffered() const override; bool IsWriteBlocked() const override; void SetWritable() override; QuicByteCount GetMaxPacketSize(
diff --git a/quic/core/quic_packets.cc b/quic/core/quic_packets.cc index 5e3ba76..31cdb7d 100644 --- a/quic/core/quic_packets.cc +++ b/quic/core/quic_packets.cc
@@ -4,11 +4,13 @@ #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/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_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_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" namespace quic { @@ -18,7 +20,9 @@ return GetPacketHeaderSize(version, header.destination_connection_id_length, header.source_connection_id_length, header.version_flag, header.nonce != nullptr, - header.packet_number_length); + header.packet_number_length, + header.retry_token_length_length, + header.retry_token.length(), header.length_length); } size_t GetPacketHeaderSize( @@ -27,16 +31,20 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, - QuicPacketNumberLength packet_number_length) { + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + QuicVariableLengthIntegerLength length_length) { if (version > QUIC_VERSION_43) { if (include_version) { // Long header. return kPacketHeaderTypeSize + kConnectionIdLengthSize + destination_connection_id_length + source_connection_id_length + - (version > QUIC_VERSION_46 ? packet_number_length + (version > QUIC_VERSION_44 ? packet_number_length : PACKET_4BYTE_PACKET_NUMBER) + kQuicVersionSize + - (include_diversification_nonce ? kDiversificationNonceSize : 0); + (include_diversification_nonce ? kDiversificationNonceSize : 0) + + retry_token_length_length + retry_token_length + length_length; } // Short header. return kPacketHeaderTypeSize + destination_connection_id_length + @@ -58,11 +66,15 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, - QuicPacketNumberLength packet_number_length) { + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + QuicVariableLengthIntegerLength length_length) { // Encryption starts before private flags. return GetPacketHeaderSize( version, destination_connection_id_length, source_connection_id_length, - include_version, include_diversification_nonce, packet_number_length); + include_version, include_diversification_nonce, packet_number_length, + retry_token_length_length, retry_token_length, length_length); } QuicPacketHeader::QuicPacketHeader() @@ -78,7 +90,11 @@ nonce(nullptr), form(GOOGLE_QUIC_PACKET), long_packet_type(INITIAL), - possible_stateless_reset_token(0) {} + possible_stateless_reset_token(0), + retry_token_length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0), + retry_token(QuicStringPiece()), + length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0), + remaining_packet_length(0) {} QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default; @@ -126,6 +142,23 @@ << ", version_flag: " << header.version_flag; if (header.version_flag) { os << ", version: " << ParsedQuicVersionToString(header.version); + if (header.long_packet_type != INVALID_PACKET_TYPE) { + os << ", long_packet_type: " + << QuicUtils::QuicLongHeaderTypetoString(header.long_packet_type); + } + if (header.retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) { + os << ", retry_token_length_length: " + << static_cast<int>(header.retry_token_length_length); + } + if (header.retry_token.length() != 0) { + os << ", retry_token_length: " << header.retry_token.length(); + } + if (header.length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) { + os << ", length_length: " << static_cast<int>(header.length_length); + } + if (header.remaining_packet_length != 0) { + os << ", remaining_packet_length: " << header.remaining_packet_length; + } } if (header.nonce != nullptr) { os << ", diversification_nonce: " @@ -148,21 +181,44 @@ } } -QuicPacket::QuicPacket(char* buffer, - size_t length, - bool owns_buffer, - QuicConnectionIdLength destination_connection_id_length, - QuicConnectionIdLength source_connection_id_length, - bool includes_version, - bool includes_diversification_nonce, - QuicPacketNumberLength packet_number_length) +QuicPacket::QuicPacket( + char* buffer, + size_t length, + bool owns_buffer, + QuicConnectionIdLength destination_connection_id_length, + QuicConnectionIdLength source_connection_id_length, + bool includes_version, + bool includes_diversification_nonce, + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + QuicVariableLengthIntegerLength length_length) : QuicData(buffer, length, owns_buffer), buffer_(buffer), destination_connection_id_length_(destination_connection_id_length), source_connection_id_length_(source_connection_id_length), includes_version_(includes_version), includes_diversification_nonce_(includes_diversification_nonce), - packet_number_length_(packet_number_length) {} + packet_number_length_(packet_number_length), + retry_token_length_length_(retry_token_length_length), + retry_token_length_(retry_token_length), + length_length_(length_length) {} + +QuicPacket::QuicPacket(char* buffer, + size_t length, + bool owns_buffer, + const QuicPacketHeader& header) + : QuicPacket(buffer, + length, + owns_buffer, + header.destination_connection_id_length, + header.source_connection_id_length, + header.version_flag, + header.nonce != nullptr, + header.packet_number_length, + header.retry_token_length_length, + header.retry_token.length(), + header.length_length) {} QuicEncryptedPacket::QuicEncryptedPacket(const char* buffer, size_t length) : QuicData(buffer, length) {} @@ -262,17 +318,19 @@ QuicStringPiece QuicPacket::AssociatedData(QuicTransportVersion version) const { return QuicStringPiece( - data(), GetStartOfEncryptedData( - version, destination_connection_id_length_, - source_connection_id_length_, includes_version_, - includes_diversification_nonce_, packet_number_length_)); + data(), + GetStartOfEncryptedData(version, destination_connection_id_length_, + source_connection_id_length_, includes_version_, + includes_diversification_nonce_, + packet_number_length_, retry_token_length_length_, + retry_token_length_, length_length_)); } QuicStringPiece QuicPacket::Plaintext(QuicTransportVersion version) const { const size_t start_of_encrypted_data = GetStartOfEncryptedData( version, destination_connection_id_length_, source_connection_id_length_, - includes_version_, includes_diversification_nonce_, - packet_number_length_); + includes_version_, includes_diversification_nonce_, packet_number_length_, + retry_token_length_length_, retry_token_length_, length_length_); return QuicStringPiece(data() + start_of_encrypted_data, length() - start_of_encrypted_data); }
diff --git a/quic/core/quic_packets.h b/quic/core/quic_packets.h index a89ddbb..8808ad2 100644 --- a/quic/core/quic_packets.h +++ b/quic/core/quic_packets.h
@@ -5,6 +5,7 @@ #ifndef QUICHE_QUIC_CORE_QUIC_PACKETS_H_ #define QUICHE_QUIC_CORE_QUIC_PACKETS_H_ +#include <cstddef> #include <cstdint> #include <limits> #include <list> @@ -42,20 +43,26 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, - QuicPacketNumberLength packet_number_length); + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + QuicVariableLengthIntegerLength length_length); // Index of the first byte in a QUIC packet of encrypted data. QUIC_EXPORT_PRIVATE size_t GetStartOfEncryptedData(QuicTransportVersion version, const QuicPacketHeader& header); -QUIC_EXPORT_PRIVATE size_t -GetStartOfEncryptedData(QuicTransportVersion version, - QuicConnectionIdLength destination_connection_id_length, - QuicConnectionIdLength source_connection_id_length, - bool include_version, - bool include_diversification_nonce, - QuicPacketNumberLength packet_number_length); +QUIC_EXPORT_PRIVATE size_t GetStartOfEncryptedData( + QuicTransportVersion version, + QuicConnectionIdLength destination_connection_id_length, + QuicConnectionIdLength source_connection_id_length, + bool include_version, + bool include_diversification_nonce, + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + QuicVariableLengthIntegerLength length_length); struct QUIC_EXPORT_PRIVATE QuicPacketHeader { QuicPacketHeader(); @@ -94,6 +101,18 @@ // Stores last 16 bytes of a this packet, used to check whether this packet is // a stateless reset packet on decryption failure. QuicUint128 possible_stateless_reset_token; + // Length of the retry token length variable length integer field, + // carried only by v99 IETF Initial packets. + QuicVariableLengthIntegerLength retry_token_length_length; + // Retry token, carried only by v99 IETF Initial packets. + QuicStringPiece retry_token; + // Length of the length variable length integer field, + // carried only by v99 IETF Initial, 0-RTT and Handshake packets. + QuicVariableLengthIntegerLength length_length; + // Length of the packet number and payload, carried only by v99 IETF Initial, + // 0-RTT and Handshake packets. Also includes the length of the + // diversification nonce in server to client 0-RTT packets. + QuicByteCount remaining_packet_length; }; struct QUIC_EXPORT_PRIVATE QuicPublicResetPacket { @@ -153,9 +172,6 @@ class QUIC_EXPORT_PRIVATE QuicPacket : public QuicData { public: - // TODO(fayang): 3 fields from header are passed in as arguments. - // Consider to add a convenience method which directly accepts the entire - // header. QuicPacket(char* buffer, size_t length, bool owns_buffer, @@ -163,7 +179,14 @@ QuicConnectionIdLength source_connection_id_length, bool includes_version, bool includes_diversification_nonce, - QuicPacketNumberLength packet_number_length); + QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + QuicVariableLengthIntegerLength length_length); + QuicPacket(char* buffer, + size_t length, + bool owns_buffer, + const QuicPacketHeader& header); QuicPacket(const QuicPacket&) = delete; QuicPacket& operator=(const QuicPacket&) = delete; @@ -179,6 +202,9 @@ const bool includes_version_; const bool includes_diversification_nonce_; const QuicPacketNumberLength packet_number_length_; + const QuicVariableLengthIntegerLength retry_token_length_length_; + const QuicByteCount retry_token_length_; + const QuicVariableLengthIntegerLength length_length_; }; class QUIC_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData {
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc index 8189ff8..a9e422f 100644 --- a/quic/core/quic_received_packet_manager.cc +++ b/quic/core/quic_received_packet_manager.cc
@@ -4,6 +4,7 @@ #include "net/third_party/quiche/src/quic/core/quic_received_packet_manager.h" +#include <algorithm> #include <limits> #include <utility> @@ -75,6 +76,13 @@ std::make_pair(packet_number, receipt_time)); } } + + if (least_received_packet_number_.IsInitialized()) { + least_received_packet_number_ = + std::min(least_received_packet_number_, packet_number); + } else { + least_received_packet_number_ = packet_number; + } } bool QuicReceivedPacketManager::IsMissing(QuicPacketNumber packet_number) { @@ -150,12 +158,14 @@ if (ack_frame_.packets.NumIntervals() > 1) { return true; } - // TODO(fayang): Fix this as this check assumes first sent packet by peer - // is 1. - return ack_frame_.packets.Min() > - (peer_least_packet_awaiting_ack_.IsInitialized() - ? peer_least_packet_awaiting_ack_ - : QuicPacketNumber(1)); + if (!GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + return ack_frame_.packets.Min() > + (peer_least_packet_awaiting_ack_.IsInitialized() + ? peer_least_packet_awaiting_ack_ + : QuicPacketNumber(1)); + } + return peer_least_packet_awaiting_ack_.IsInitialized() && + ack_frame_.packets.Min() > peer_least_packet_awaiting_ack_; } bool QuicReceivedPacketManager::HasNewMissingPackets() const { @@ -171,4 +181,16 @@ return LargestAcked(ack_frame_); } +QuicPacketNumber QuicReceivedPacketManager::PeerFirstSendingPacketNumber() + const { + if (!GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + return QuicPacketNumber(1); + } + if (!least_received_packet_number_.IsInitialized()) { + QUIC_BUG << "No packets have been received yet"; + return QuicPacketNumber(1); + } + return least_received_packet_number_; +} + } // namespace quic
diff --git a/quic/core/quic_received_packet_manager.h b/quic/core/quic_received_packet_manager.h index c720a01..12d1f9c 100644 --- a/quic/core/quic_received_packet_manager.h +++ b/quic/core/quic_received_packet_manager.h
@@ -65,6 +65,13 @@ QuicPacketNumber GetLargestObserved() const; + // Returns peer first sending packet number to our best knowledge. If + // GetQuicRestartFlag(quic_enable_accept_random_ipn) is false, returns 1. + // Otherwise considers least_received_packet_number_ as peer first sending + // packet number. Please note, this function should only be called when at + // least one packet has been received. + QuicPacketNumber PeerFirstSendingPacketNumber() const; + // For logging purposes. const QuicAckFrame& ack_frame() const { return ack_frame_; } @@ -101,6 +108,9 @@ // If true, save timestamps in the ack_frame_. bool save_timestamps_; + // Least packet number received from peer. + QuicPacketNumber least_received_packet_number_; + QuicConnectionStats* stats_; };
diff --git a/quic/core/quic_received_packet_manager_test.cc b/quic/core/quic_received_packet_manager_test.cc index b8264a5..9cbc6e7 100644 --- a/quic/core/quic_received_packet_manager_test.cc +++ b/quic/core/quic_received_packet_manager_test.cc
@@ -9,6 +9,7 @@ #include <vector> #include "net/third_party/quiche/src/quic/core/quic_connection_stats.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic { @@ -56,9 +57,9 @@ QuicReceivedPacketManager received_manager_; }; -INSTANTIATE_TEST_CASE_P(QuicReceivedPacketManagerTest, - QuicReceivedPacketManagerTest, - ::testing::ValuesIn(GetTestParams())); +INSTANTIATE_TEST_SUITE_P(QuicReceivedPacketManagerTest, + QuicReceivedPacketManagerTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicReceivedPacketManagerTest, DontWaitForPacketsBefore) { QuicPacketHeader header; @@ -159,6 +160,44 @@ EXPECT_EQ(2u, received_manager_.ack_frame().received_packet_times.size()); } +TEST_P(QuicReceivedPacketManagerTest, HasMissingPackets) { + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_QUIC_BUG(received_manager_.PeerFirstSendingPacketNumber(), + "No packets have been received yet"); + } else { + EXPECT_EQ(QuicPacketNumber(1), + received_manager_.PeerFirstSendingPacketNumber()); + } + RecordPacketReceipt(4, QuicTime::Zero()); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_EQ(QuicPacketNumber(4), + received_manager_.PeerFirstSendingPacketNumber()); + EXPECT_FALSE(received_manager_.HasMissingPackets()); + } else { + EXPECT_TRUE(received_manager_.HasMissingPackets()); + EXPECT_EQ(QuicPacketNumber(1), + received_manager_.PeerFirstSendingPacketNumber()); + } + RecordPacketReceipt(3, QuicTime::Zero()); + if (GetQuicRestartFlag(quic_enable_accept_random_ipn)) { + EXPECT_FALSE(received_manager_.HasMissingPackets()); + EXPECT_EQ(QuicPacketNumber(3), + received_manager_.PeerFirstSendingPacketNumber()); + } else { + EXPECT_TRUE(received_manager_.HasMissingPackets()); + EXPECT_EQ(QuicPacketNumber(1), + received_manager_.PeerFirstSendingPacketNumber()); + } + RecordPacketReceipt(1, QuicTime::Zero()); + EXPECT_EQ(QuicPacketNumber(1), + received_manager_.PeerFirstSendingPacketNumber()); + EXPECT_TRUE(received_manager_.HasMissingPackets()); + RecordPacketReceipt(2, QuicTime::Zero()); + EXPECT_EQ(QuicPacketNumber(1), + received_manager_.PeerFirstSendingPacketNumber()); + EXPECT_FALSE(received_manager_.HasMissingPackets()); +} + } // namespace } // namespace test } // namespace quic
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index 4bbe070..49c5e08 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -67,8 +67,9 @@ } // namespace -#define ENDPOINT \ - (perspective_ == Perspective::IS_SERVER ? "Server: " : "Client: ") +#define ENDPOINT \ + (unacked_packets_.perspective() == Perspective::IS_SERVER ? "Server: " \ + : "Client: ") QuicSentPacketManager::QuicSentPacketManager( Perspective perspective, @@ -76,15 +77,19 @@ QuicConnectionStats* stats, CongestionControlType congestion_control_type, LossDetectionType loss_type) - : unacked_packets_(), - perspective_(perspective), + : unacked_packets_(perspective), clock_(clock), stats_(stats), debug_delegate_(nullptr), network_change_visitor_(nullptr), initial_congestion_window_(kInitialCongestionWindow), - loss_algorithm_(&general_loss_algorithm_), + loss_algorithm_( + unacked_packets_.use_uber_loss_algorithm() + ? dynamic_cast<LossDetectionInterface*>(&uber_loss_algorithm_) + : dynamic_cast<LossDetectionInterface*>( + &general_loss_algorithm_)), general_loss_algorithm_(loss_type), + uber_loss_algorithm_(loss_type), n_connection_simulation_(false), consecutive_rto_count_(0), consecutive_tlp_count_(0), @@ -107,20 +112,17 @@ delayed_ack_time_( QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)), rtt_updated_(false), - acked_packets_iter_(last_ack_frame_.packets.rbegin()), - aggregate_acked_stream_frames_( - GetQuicReloadableFlag(quic_aggregate_acked_stream_frames_2)), - fix_mark_for_loss_retransmission_( - GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { + acked_packets_iter_(last_ack_frame_.packets.rbegin()) { SetSendAlgorithm(congestion_control_type); } QuicSentPacketManager::~QuicSentPacketManager() {} void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) { + const Perspective perspective = unacked_packets_.perspective(); if (config.HasReceivedInitialRoundTripTimeUs() && config.ReceivedInitialRoundTripTimeUs() > 0) { - if (!config.HasClientSentConnectionOption(kNRTT, perspective_)) { + if (!config.HasClientSentConnectionOption(kNRTT, perspective)) { SetInitialRtt(QuicTime::Delta::FromMicroseconds( config.ReceivedInitialRoundTripTimeUs())); } @@ -129,55 +131,54 @@ SetInitialRtt(QuicTime::Delta::FromMicroseconds( config.GetInitialRoundTripTimeUsToSend())); } - if (config.HasClientSentConnectionOption(kMAD0, perspective_)) { + if (config.HasClientSentConnectionOption(kMAD0, perspective)) { rtt_stats_.set_ignore_max_ack_delay(true); } - if (config.HasClientSentConnectionOption(kMAD1, perspective_)) { + if (config.HasClientSentConnectionOption(kMAD1, perspective)) { rtt_stats_.set_initial_max_ack_delay(delayed_ack_time_); } - if (config.HasClientSentConnectionOption(kMAD2, perspective_)) { + if (config.HasClientSentConnectionOption(kMAD2, perspective)) { min_tlp_timeout_ = QuicTime::Delta::Zero(); } - if (config.HasClientSentConnectionOption(kMAD3, perspective_)) { + if (config.HasClientSentConnectionOption(kMAD3, perspective)) { min_rto_timeout_ = QuicTime::Delta::Zero(); } - if (config.HasClientSentConnectionOption(kMAD4, perspective_)) { + if (config.HasClientSentConnectionOption(kMAD4, perspective)) { ietf_style_tlp_ = true; } - if (config.HasClientSentConnectionOption(kMAD5, perspective_)) { + if (config.HasClientSentConnectionOption(kMAD5, perspective)) { ietf_style_2x_tlp_ = true; } // Configure congestion control. - if (config.HasClientRequestedIndependentOption(kTBBR, perspective_)) { + if (config.HasClientRequestedIndependentOption(kTBBR, perspective)) { SetSendAlgorithm(kBBR); } - if (config.HasClientRequestedIndependentOption(kRENO, perspective_)) { + if (config.HasClientRequestedIndependentOption(kRENO, perspective)) { SetSendAlgorithm(kRenoBytes); - } else if (config.HasClientRequestedIndependentOption(kBYTE, perspective_) || + } else if (config.HasClientRequestedIndependentOption(kBYTE, perspective) || (GetQuicReloadableFlag(quic_default_to_bbr) && - config.HasClientRequestedIndependentOption(kQBIC, - perspective_))) { + config.HasClientRequestedIndependentOption(kQBIC, perspective))) { SetSendAlgorithm(kCubicBytes); } else if (GetQuicReloadableFlag(quic_enable_pcc3) && - config.HasClientRequestedIndependentOption(kTPCC, perspective_)) { + config.HasClientRequestedIndependentOption(kTPCC, perspective)) { SetSendAlgorithm(kPCC); } // Initial window. if (GetQuicReloadableFlag(quic_unified_iw_options)) { - if (config.HasClientRequestedIndependentOption(kIW03, perspective_)) { + if (config.HasClientRequestedIndependentOption(kIW03, perspective)) { initial_congestion_window_ = 3; send_algorithm_->SetInitialCongestionWindowInPackets(3); } - if (config.HasClientRequestedIndependentOption(kIW10, perspective_)) { + if (config.HasClientRequestedIndependentOption(kIW10, perspective)) { initial_congestion_window_ = 10; send_algorithm_->SetInitialCongestionWindowInPackets(10); } - if (config.HasClientRequestedIndependentOption(kIW20, perspective_)) { + if (config.HasClientRequestedIndependentOption(kIW20, perspective)) { initial_congestion_window_ = 20; send_algorithm_->SetInitialCongestionWindowInPackets(20); } - if (config.HasClientRequestedIndependentOption(kIW50, perspective_)) { + if (config.HasClientRequestedIndependentOption(kIW50, perspective)) { initial_congestion_window_ = 50; send_algorithm_->SetInitialCongestionWindowInPackets(50); } @@ -185,41 +186,53 @@ using_pacing_ = !FLAGS_quic_disable_pacing_for_perf_tests; - if (config.HasClientSentConnectionOption(k1CON, perspective_)) { + if (config.HasClientSentConnectionOption(k1CON, perspective)) { send_algorithm_->SetNumEmulatedConnections(1); } - if (config.HasClientSentConnectionOption(kNCON, perspective_)) { + if (config.HasClientSentConnectionOption(kNCON, perspective)) { n_connection_simulation_ = true; } - if (config.HasClientSentConnectionOption(kNTLP, perspective_)) { + if (config.HasClientSentConnectionOption(kNTLP, perspective)) { max_tail_loss_probes_ = 0; } - if (config.HasClientSentConnectionOption(k1TLP, perspective_)) { + if (config.HasClientSentConnectionOption(k1TLP, perspective)) { max_tail_loss_probes_ = 1; } - if (config.HasClientSentConnectionOption(k1RTO, perspective_)) { + if (config.HasClientSentConnectionOption(k1RTO, perspective)) { max_rto_packets_ = 1; } - if (config.HasClientSentConnectionOption(kTLPR, perspective_)) { + if (config.HasClientSentConnectionOption(kTLPR, perspective)) { enable_half_rtt_tail_loss_probe_ = true; } - if (config.HasClientSentConnectionOption(kNRTO, perspective_)) { + if (config.HasClientSentConnectionOption(kNRTO, perspective)) { use_new_rto_ = true; } // Configure loss detection. - if (config.HasClientRequestedIndependentOption(kTIME, perspective_)) { - general_loss_algorithm_.SetLossDetectionType(kTime); + if (config.HasClientRequestedIndependentOption(kTIME, perspective)) { + if (unacked_packets_.use_uber_loss_algorithm()) { + uber_loss_algorithm_.SetLossDetectionType(kTime); + } else { + general_loss_algorithm_.SetLossDetectionType(kTime); + } } - if (config.HasClientRequestedIndependentOption(kATIM, perspective_)) { - general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime); + if (config.HasClientRequestedIndependentOption(kATIM, perspective)) { + if (unacked_packets_.use_uber_loss_algorithm()) { + uber_loss_algorithm_.SetLossDetectionType(kAdaptiveTime); + } else { + general_loss_algorithm_.SetLossDetectionType(kAdaptiveTime); + } } - if (config.HasClientRequestedIndependentOption(kLFAK, perspective_)) { - general_loss_algorithm_.SetLossDetectionType(kLazyFack); + if (config.HasClientRequestedIndependentOption(kLFAK, perspective)) { + if (unacked_packets_.use_uber_loss_algorithm()) { + uber_loss_algorithm_.SetLossDetectionType(kLazyFack); + } else { + general_loss_algorithm_.SetLossDetectionType(kLazyFack); + } } - if (config.HasClientSentConnectionOption(kCONH, perspective_)) { + if (config.HasClientSentConnectionOption(kCONH, perspective)) { conservative_handshake_retransmits_ = true; } - send_algorithm_->SetFromConfig(config, perspective_); + send_algorithm_->SetFromConfig(config, perspective); if (network_change_visitor_ != nullptr) { network_change_visitor_->OnCongestionChange(); @@ -257,13 +270,19 @@ } } +void QuicSentPacketManager::SetHandshakeConfirmed() { + handshake_confirmed_ = true; + if (unacked_packets_.use_uber_loss_algorithm()) { + NeuterHandshakePackets(); + } +} + void QuicSentPacketManager::PostProcessAfterMarkingPacketHandled( const QuicAckFrame& ack_frame, QuicTime ack_receive_time, bool rtt_updated, QuicByteCount prior_bytes_in_flight) { - if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_aggregate_acked_stream_frames_2, 1, 2); + if (session_decides_what_to_write()) { unacked_packets_.NotifyAggregatedStreamFrameAcked( last_ack_frame_.ack_delay_time); } @@ -305,8 +324,8 @@ if (debug_delegate_ != nullptr) { debug_delegate_->OnIncomingAck(ack_frame, ack_receive_time, - unacked_packets_.largest_acked(), - rtt_updated, GetLeastUnacked()); + LargestAcked(ack_frame), rtt_updated, + GetLeastUnacked()); } // Remove packets below least unacked from all_packets_acked_ and // last_ack_frame_. @@ -343,7 +362,7 @@ for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); it != unacked_packets_.end(); ++it, ++packet_number) { if ((retransmission_type == ALL_UNACKED_RETRANSMISSION || - it->encryption_level == ENCRYPTION_INITIAL) && + it->encryption_level == ENCRYPTION_ZERO_RTT) && unacked_packets_.HasRetransmittableFrames(*it)) { MarkForRetransmission(packet_number, retransmission_type); } @@ -380,6 +399,29 @@ } } +void QuicSentPacketManager::NeuterHandshakePackets() { + DCHECK(unacked_packets_.use_uber_loss_algorithm()); + QuicPacketNumber packet_number = unacked_packets_.GetLeastUnacked(); + for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin(); + it != unacked_packets_.end(); ++it, ++packet_number) { + if (session_decides_what_to_write()) { + if (!it->retransmittable_frames.empty() && + unacked_packets_.GetPacketNumberSpace(it->encryption_level) == + HANDSHAKE_DATA) { + unacked_packets_.RemoveFromInFlight(packet_number); + } + continue; + } + if (unacked_packets_.GetPacketNumberSpace(it->encryption_level) == + HANDSHAKE_DATA && + unacked_packets_.HasRetransmittableFrames(*it)) { + pending_retransmissions_.erase(packet_number); + unacked_packets_.RemoveFromInFlight(packet_number); + unacked_packets_.RemoveRetransmittability(packet_number); + } + } +} + void QuicSentPacketManager::MarkForRetransmission( QuicPacketNumber packet_number, TransmissionType transmission_type) { @@ -402,8 +444,7 @@ } if (!session_decides_what_to_write()) { - if (fix_mark_for_loss_retransmission_ && - !unacked_packets_.HasRetransmittableFrames(*transmission_info)) { + if (!unacked_packets_.HasRetransmittableFrames(*transmission_info)) { return; } if (!QuicContainsKey(pending_retransmissions_, packet_number)) { @@ -545,15 +586,12 @@ if (newest_transmission == packet_number) { // Try to aggregate acked stream frames if acked packet is not a // retransmission. - const bool fast_path = aggregate_acked_stream_frames_ && - session_decides_what_to_write() && + const bool fast_path = session_decides_what_to_write() && info->transmission_type == NOT_RETRANSMISSION; if (fast_path) { unacked_packets_.MaybeAggregateAckedStreamFrame(*info, ack_delay_time); } else { - if (aggregate_acked_stream_frames_ && session_decides_what_to_write()) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_aggregate_acked_stream_frames_2, 2, - 2); + if (session_decides_what_to_write()) { unacked_packets_.NotifyAggregatedStreamFrameAcked(ack_delay_time); } const bool new_data_acked = @@ -818,19 +856,7 @@ time); } - if (fix_mark_for_loss_retransmission_ || - unacked_packets_.HasRetransmittableFrames(packet.packet_number)) { - if (fix_mark_for_loss_retransmission_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_fix_mark_for_loss_retransmission); - } - MarkForRetransmission(packet.packet_number, LOSS_RETRANSMISSION); - } else { - // Since we will not retransmit this, we need to remove it from - // unacked_packets_. This is either the current transmission of - // a packet whose previous transmission has been acked or a packet that - // has been TLP retransmitted. - unacked_packets_.RemoveFromInFlight(packet.packet_number); - } + MarkForRetransmission(packet.packet_number, LOSS_RETRANSMISSION); } } @@ -1143,6 +1169,10 @@ // Unackable packets are skipped earlier. largest_newly_acked_ = acked_packet.packet_number; } + if (unacked_packets_.use_uber_loss_algorithm()) { + unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace( + info->encryption_level, acked_packet.packet_number); + } MarkPacketHandled(acked_packet.packet_number, info, last_ack_frame_.ack_delay_time); }
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h index aad16e2..4799e1f 100644 --- a/quic/core/quic_sent_packet_manager.h +++ b/quic/core/quic_sent_packet_manager.h
@@ -13,11 +13,10 @@ #include <vector> #include "base/macros.h" -#include "net/third_party/quiche/src/quic/core/congestion_control/general_loss_algorithm.h" -#include "net/third_party/quiche/src/quic/core/congestion_control/loss_detection_interface.h" #include "net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h" #include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" #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_packets.h" #include "net/third_party/quiche/src/quic/core/quic_pending_retransmission.h" @@ -115,7 +114,9 @@ return pacing_sender_.max_pacing_rate(); } - void SetHandshakeConfirmed() { handshake_confirmed_ = true; } + // Set handshake_confirmed_ to true and neuter packets in HANDSHAKE packet + // number space. + void SetHandshakeConfirmed(); // Requests retransmission of all unacked packets of |retransmission_type|. // The behavior of this method depends on the value of |retransmission_type|: @@ -140,6 +141,8 @@ // Removes the retransmittable frames from all unencrypted packets to ensure // they don't get retransmitted. + // TODO(fayang): Consider remove this function when deprecating + // quic_use_uber_loss_algorithm. void NeuterUnencryptedPackets(); // Returns true if there are pending retransmissions. @@ -473,6 +476,14 @@ // Sets the initial RTT of the connection. void SetInitialRtt(QuicTime::Delta rtt); + // Called when handshake is confirmed to remove the retransmittable frames + // from all packets of HANDSHAKE_DATA packet number space to ensure they don't + // get retransmitted and will eventually be removed from unacked packets map. + // Only used when quic_use_uber_loss_algorithm is true. Please note, this only + // applies to QUIC Crypto and needs to be changed when switches to IETF QUIC + // with QUIC TLS. + void NeuterHandshakePackets(); + // 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 @@ -486,9 +497,6 @@ // Pending retransmissions which have not been packetized and sent yet. PendingRetransmissionMap pending_retransmissions_; - // Tracks if the connection was created by the server or the client. - Perspective perspective_; - const QuicClock* clock_; QuicConnectionStats* stats_; @@ -499,7 +507,10 @@ std::unique_ptr<SendAlgorithmInterface> send_algorithm_; // Not owned. Always points to |general_loss_algorithm_| outside of tests. LossDetectionInterface* loss_algorithm_; + // TODO(fayang): Remove general_loss_algorithm_ when deprecating + // quic_use_uber_loss_algorithm. GeneralLossAlgorithm general_loss_algorithm_; + UberLossAlgorithm uber_loss_algorithm_; bool n_connection_simulation_; // Tracks the first RTO packet. If any packet before that packet gets acked, @@ -572,12 +583,6 @@ // A reverse iterator of last_ack_frame_.packets. This is reset in // OnAckRangeStart, and gradually moves in OnAckRange.. PacketNumberQueue::const_reverse_iterator acked_packets_iter_; - - // Latched value of quic_aggregate_acked_stream_frames_2 flag. - const bool aggregate_acked_stream_frames_; - - // Latched value of quic_fix_mark_for_loss_retransmission flag. - const bool fix_mark_for_loss_retransmission_; }; } // namespace quic
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc index 97e1697..6ed2078 100644 --- a/quic/core/quic_sent_packet_manager_test.cc +++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -322,7 +322,7 @@ StrictMock<MockSessionNotifier> notifier_; }; -INSTANTIATE_TEST_CASE_P(Tests, QuicSentPacketManagerTest, testing::Bool()); +INSTANTIATE_TEST_SUITE_P(Tests, QuicSentPacketManagerTest, testing::Bool()); TEST_P(QuicSentPacketManagerTest, IsUnacked) { VerifyUnackedPackets(nullptr, 0); @@ -504,11 +504,9 @@ if (manager_.session_decides_what_to_write()) { // Frames in all packets are acked. EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - // Notify session that stream frame in packet 2 gets lost although it is - // not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); - } + // Notify session that stream frame in packet 2 gets lost although it is + // not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); } manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), clock_.Now()); @@ -516,8 +514,7 @@ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); - if (manager_.session_decides_what_to_write() && - GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { + if (manager_.session_decides_what_to_write()) { uint64_t unacked[] = {2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); } else { @@ -629,11 +626,9 @@ if (manager_.session_decides_what_to_write()) { // Frames in all packets are acked. EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - // Notify session that stream frame in packet 2 gets lost although it is - // not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); - } + // Notify session that stream frame in packet 2 gets lost although it is + // not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(1); } manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), clock_.Now()); @@ -641,8 +636,7 @@ manager_.OnAckRange(QuicPacketNumber(1), QuicPacketNumber(2)); EXPECT_TRUE(manager_.OnAckFrameEnd(clock_.Now())); - if (manager_.session_decides_what_to_write() && - GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { + if (manager_.session_decides_what_to_write()) { uint64_t unacked[] = {2}; VerifyUnackedPackets(unacked, QUIC_ARRAYSIZE(unacked)); } else { @@ -873,11 +867,9 @@ if (manager_.session_decides_what_to_write()) { // Frames in all packets are acked. EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(false)); - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - // Notify session that stream frame in packets 1 and 2 get lost although - // they are not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2); - } + // Notify session that stream frame in packets 1 and 2 get lost although + // they are not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(2); } manager_.OnAckFrameStart(QuicPacketNumber(5), QuicTime::Delta::Infinite(), clock_.Now()); @@ -980,27 +972,12 @@ true, _, _, Pointwise(PacketNumberEq(), {largest_acked}), _)); EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); if (manager_.session_decides_what_to_write()) { - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - // Although frames in packet 3 gets acked, it would be kept for another - // RTT. - EXPECT_CALL(notifier_, IsFrameOutstanding(_)) - .WillRepeatedly(Return(true)); - } else { - // Frames in packet 3 gets acked as packet 103 gets acked. - EXPECT_CALL(notifier_, IsFrameOutstanding(_)) - .WillOnce(Return(true)) - .WillOnce(Return(true)) - .WillOnce(Return(false)) - .WillRepeatedly(Return(true)); - } - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - // Packets [1, 102] are lost, although stream frame in packet 3 is not - // outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(102); - } else { - // Packets 1, 2 and [4, 102] are lost. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(101); - } + // Although frames in packet 3 gets acked, it would be kept for another + // RTT. + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); + // Packets [1, 102] are lost, although stream frame in packet 3 is not + // outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(102); } manager_.OnAckFrameStart(QuicPacketNumber(103), QuicTime::Delta::Infinite(), clock_.Now()); @@ -1363,27 +1340,10 @@ OnPacketLoss(QuicPacketNumber(i), LOSS_RETRANSMISSION, _)); } if (manager_.session_decides_what_to_write()) { - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)) - .WillRepeatedly(Return(true)); - } else { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)) - .WillOnce(Return(true)) - // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not - // ideal. - .WillOnce(Return(true)) - .WillOnce(Return(false)) - .WillRepeatedly(Return(true)); - } - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - // Packets [1, 99] are considered as lost, although stream frame in packet - // 2 is not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); - } else { - // Packets [1, 99] are considered as lost, but packets 2 does not have - // retransmittable frames as packet 102 is acked. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); + // Packets [1, 99] are considered as lost, although stream frame in packet + // 2 is not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); } manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(), clock_.Now()); @@ -1492,27 +1452,10 @@ /*lost_packets=*/Not(IsEmpty()))); EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); if (manager_.session_decides_what_to_write()) { - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)) - .WillRepeatedly(Return(true)); - } else { - EXPECT_CALL(notifier_, IsFrameOutstanding(_)) - .WillOnce(Return(true)) - // This is used for QUIC_BUG_IF in MarkForRetransmission, which is not - // ideal. - .WillOnce(Return(true)) - .WillOnce(Return(false)) - .WillRepeatedly(Return(true)); - } - if (GetQuicReloadableFlag(quic_fix_mark_for_loss_retransmission)) { - // Packets [1, 99] are considered as lost, although stream frame in packet - // 2 is not outstanding. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); - } else { - // Packets [1, 99] are considered as lost, but packets 2 does not have - // retransmittable frames as packet 102 is acked. - EXPECT_CALL(notifier_, OnFrameLost(_)).Times(98); - } + EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); + // Packets [1, 99] are considered as lost, although stream frame in packet + // 2 is not outstanding. + EXPECT_CALL(notifier_, OnFrameLost(_)).Times(99); } manager_.OnAckFrameStart(QuicPacketNumber(102), QuicTime::Delta::Zero(), clock_.Now());
diff --git a/quic/core/quic_session.cc b/quic/core/quic_session.cc index b5e88ff..2eb67e7 100644 --- a/quic/core/quic_session.cc +++ b/quic/core/quic_session.cc
@@ -151,6 +151,10 @@ handler.stream->OnStreamFrame(frame); } +void QuicSession::OnCryptoFrame(const QuicCryptoFrame& frame) { + GetMutableCryptoStream()->OnCryptoFrame(frame); +} + bool QuicSession::OnStopSendingFrame(const QuicStopSendingFrame& frame) { // We are not version 99. In theory, if not in version 99 then the framer // could not call OnStopSending... This is just a check that is good when @@ -231,7 +235,6 @@ static_cast<quic::QuicRstStreamErrorCode>(frame.application_error_code), stream->stream_bytes_written(), /*close_write_side_only=*/true); - stream->set_rst_sent(true); return true; } @@ -585,16 +588,13 @@ // Send a RST_STREAM frame plus, if version 99, an IETF // QUIC STOP_SENDING frame. Both sre sent to emulate // the two-way close that Google QUIC's RST_STREAM does. - QuicConnection::ScopedPacketFlusher* flusher = - (connection_->transport_version() == QUIC_VERSION_99) - ? new QuicConnection::ScopedPacketFlusher( - connection(), QuicConnection::SEND_ACK_IF_QUEUED) - : nullptr; - control_frame_manager_.WriteOrBufferRstStreamStopSending(id, error, - bytes_written); - if (flusher) { - delete flusher; - flusher = nullptr; + if (connection_->transport_version() == QUIC_VERSION_99) { + QuicConnection::ScopedPacketFlusher flusher( + connection(), QuicConnection::SEND_ACK_IF_QUEUED); + control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); + control_frame_manager_.WriteOrBufferStopSending(error, id); + } else { + control_frame_manager_.WriteOrBufferRstStream(id, error, bytes_written); } } connection_->OnStreamReset(id, error); @@ -603,17 +603,20 @@ OnStreamDoneWaitingForAcks(id); return; } - if (close_write_side_only) { - DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version()); - DynamicStreamMap::iterator it = dynamic_stream_map_.find(id); - if (it != dynamic_stream_map_.end()) { - QuicStream* stream = it->second.get(); - if (stream) { - stream->CloseWriteSide(); - } - } - } else { + + if (!close_write_side_only) { CloseStreamInner(id, true); + return; + } + DCHECK_EQ(QUIC_VERSION_99, connection_->transport_version()); + + DynamicStreamMap::iterator it = dynamic_stream_map_.find(id); + if (it != dynamic_stream_map_.end()) { + QuicStream* stream = it->second.get(); + if (stream) { + stream->set_rst_sent(true); + stream->CloseWriteSide(); + } } } @@ -1366,6 +1369,10 @@ OnMessageAcked(frame.message_frame->message_id); return true; } + if (frame.type == CRYPTO_FRAME) { + return GetMutableCryptoStream()->OnCryptoFrameAcked(*frame.crypto_frame, + ack_delay_time); + } if (frame.type != STREAM_FRAME) { return control_frame_manager_.OnControlFrameAcked(frame); } @@ -1373,9 +1380,10 @@ QuicStream* stream = GetStream(frame.stream_frame.stream_id); // Stream can already be reset when sent frame gets acked. if (stream != nullptr) { + QuicByteCount newly_acked_length = 0; new_stream_data_acked = stream->OnStreamFrameAcked( frame.stream_frame.offset, frame.stream_frame.data_length, - frame.stream_frame.fin, ack_delay_time); + frame.stream_frame.fin, ack_delay_time, &newly_acked_length); if (!stream->HasPendingRetransmission()) { streams_with_pending_retransmission_.erase(stream->id()); } @@ -1402,6 +1410,10 @@ OnMessageLost(frame.message_frame->message_id); return; } + if (frame.type == CRYPTO_FRAME) { + GetMutableCryptoStream()->OnCryptoFrameLost(frame.crypto_frame); + return; + } if (frame.type != STREAM_FRAME) { control_frame_manager_.OnControlFrameLost(frame); return; @@ -1431,6 +1443,10 @@ // Do not retransmit MESSAGE frames. continue; } + if (frame.type == CRYPTO_FRAME) { + GetMutableCryptoStream()->RetransmitData(frame.crypto_frame); + continue; + } if (frame.type != STREAM_FRAME) { if (!control_frame_manager_.RetransmitControlFrame(frame)) { break; @@ -1451,6 +1467,11 @@ if (frame.type == MESSAGE_FRAME) { return false; } + if (frame.type == CRYPTO_FRAME) { + return GetCryptoStream()->IsFrameOutstanding( + frame.crypto_frame->level, frame.crypto_frame->offset, + frame.crypto_frame->data_length); + } if (frame.type != STREAM_FRAME) { return control_frame_manager_.IsControlFrameOutstanding(frame); } @@ -1495,21 +1516,27 @@ QuicStreamOffset offset, QuicByteCount data_length, QuicDataWriter* writer) { - QUIC_BUG << "QuicSession::WriteCryptoData is unimplemented"; - return false; + return GetMutableCryptoStream()->WriteCryptoFrame(level, offset, data_length, + writer); } QuicUint128 QuicSession::GetStatelessResetToken() const { - if (!QuicConnectionIdSupportsVariableLength(perspective())) { - return QuicConnectionIdToUInt64(connection_->connection_id()); - } return QuicUtils::GenerateStatelessResetToken(connection_->connection_id()); } bool QuicSession::RetransmitLostData() { QuicConnection::ScopedPacketFlusher retransmission_flusher( connection_, QuicConnection::SEND_ACK_IF_QUEUED); - if (QuicContainsKey( + // Retransmit crypto data first. + bool uses_crypto_frames = connection_->transport_version() >= QUIC_VERSION_47; + QuicCryptoStream* crypto_stream = GetMutableCryptoStream(); + if (uses_crypto_frames && crypto_stream->HasPendingCryptoRetransmission()) { + SetTransmissionType(HANDSHAKE_RETRANSMISSION); + crypto_stream->WritePendingCryptoRetransmission(); + } + // Retransmit crypto data in stream 1 frames (version < 47). + if (!uses_crypto_frames && + QuicContainsKey( streams_with_pending_retransmission_, QuicUtils::GetCryptoStreamId(connection_->transport_version()))) { SetTransmissionType(HANDSHAKE_RETRANSMISSION); @@ -1579,7 +1606,7 @@ connection_->SetTransmissionType(type); } -MessageResult QuicSession::SendMessage(QuicStringPiece message) { +MessageResult QuicSession::SendMessage(QuicMemSliceSpan message) { if (!IsEncryptionEstablished()) { return {MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0}; }
diff --git a/quic/core/quic_session.h b/quic/core/quic_session.h index 23778e7..cb0f0a7 100644 --- a/quic/core/quic_session.h +++ b/quic/core/quic_session.h
@@ -77,7 +77,7 @@ // ENCRYPTION_REESTABLISHED indicates that a client hello was rejected by // the server and thus the encryption key has been updated. Therefore the // connection should resend any packets that were sent under - // ENCRYPTION_INITIAL. (Client only.) + // ENCRYPTION_ZERO_RTT. (Client only.) ENCRYPTION_REESTABLISHED, // HANDSHAKE_CONFIRMED, in a client, indicates the server has accepted // our handshake. In a server it indicates that a full, valid client hello @@ -99,6 +99,7 @@ // QuicConnectionVisitorInterface methods: void OnStreamFrame(const QuicStreamFrame& frame) override; + void OnCryptoFrame(const QuicCryptoFrame& frame) override; void OnRstStream(const QuicRstStreamFrame& frame) override; void OnGoAway(const QuicGoAwayFrame& frame) override; void OnMessageReceived(QuicStringPiece message) override; @@ -165,11 +166,17 @@ QuicStreamOffset offset, StreamSendingState state); - // Called by application to send |message|. Returns the message result which - // includes the message status and message ID (valid if the write succeeds). - // SendMessage flushes a message packet even it is not full. If the - // application wants to bundle other data in the same packet, please consider - // adding a packet flusher around the SendMessage and/or WritevData calls. + // Called by application to send |message|. Data copy can be avoided if + // |message| is provided in reference counted memory. + // Please note, |message| provided in reference counted memory would be moved + // internally when message is successfully sent. Thereafter, it would be + // undefined behavior if callers try to access the slices through their own + // copy of the span object. + // Returns the message result which includes the message status and message ID + // (valid if the write succeeds). SendMessage flushes a message packet even it + // is not full. If the application wants to bundle other data in the same + // packet, please consider adding a packet flusher around the SendMessage + // and/or WritevData calls. // // OnMessageAcked and OnMessageLost are called when a particular message gets // acked or lost. @@ -179,7 +186,7 @@ // blocked. In this case the caller can retry sending message again when // connection becomes available, for example after getting OnCanWrite() // callback. - MessageResult SendMessage(QuicStringPiece message); + MessageResult SendMessage(QuicMemSliceSpan message); // Called when message with |message_id| gets acked. virtual void OnMessageAcked(QuicMessageId message_id); @@ -381,6 +388,17 @@ return num_locally_closed_incoming_streams_highest_offset_; } + // Does actual work of sending reset-stream or reset-stream&stop-sending + // If the connection is not version 99/IETF QUIC, will always send a + // RESET_STREAM and close_write_side_only is ignored. If the connection is + // IETF QUIC/Version 99 then will send a RESET_STREAM and STOP_SENDING if + // close_write_side_only is false, just a RESET_STREAM if + // close_write_side_only is true. + virtual void SendRstStreamInner(QuicStreamId id, + QuicRstStreamErrorCode error, + QuicStreamOffset bytes_written, + bool close_write_side_only); + protected: using StaticStreamMap = QuicSmallMap<QuicStreamId, QuicStream*, 2>; @@ -571,17 +589,6 @@ // Closes the pending stream |stream_id| before it has been created. void ClosePendingStream(QuicStreamId stream_id); - // Does actual work of sending reset-stream or reset-stream&stop-sending - // If the connection is not version 99/IETF QUIC, will always send a - // RESET_STREAM and close_write_side_only is ignored. If the connection is - // IETF QUIC/Version 99 then will send a RESET_STREAM and STOP_SENDING if - // close_write_side_only is false, just a RESET_STREAM if - // close_write_side_only is true. - void SendRstStreamInner(QuicStreamId id, - QuicRstStreamErrorCode error, - QuicStreamOffset bytes_written, - bool close_write_side_only); - // Keep track of highest received byte offset of locally closed streams, while // waiting for a definitive final highest offset from the peer. std::map<QuicStreamId, QuicStreamOffset>
diff --git a/quic/core/quic_session_test.cc b/quic/core/quic_session_test.cc index 6bf26ab..ddd5a2b 100644 --- a/quic/core/quic_session_test.cc +++ b/quic/core/quic_session_test.cc
@@ -98,6 +98,7 @@ } MOCK_METHOD0(OnCanWrite, void()); + bool HasPendingCryptoRetransmission() override { return false; } MOCK_CONST_METHOD0(HasPendingRetransmission, bool()); @@ -191,10 +192,11 @@ return nullptr; } - TestStream* stream = new TestStream( - id, this, - DetermineStreamType(id, connection()->transport_version(), - /*is_incoming=*/true, BIDIRECTIONAL)); + TestStream* stream = + new TestStream(id, this, + DetermineStreamType( + id, connection()->transport_version(), perspective(), + /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); ++num_incoming_streams_created_; return stream; @@ -202,10 +204,11 @@ TestStream* CreateIncomingStream(PendingStream pending) override { QuicStreamId id = pending.id(); - TestStream* stream = new TestStream( - std::move(pending), - DetermineStreamType(id, connection()->transport_version(), - /*is_incoming=*/true, BIDIRECTIONAL)); + TestStream* stream = + new TestStream(std::move(pending), + DetermineStreamType( + id, connection()->transport_version(), perspective(), + /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); ++num_incoming_streams_created_; return stream; @@ -335,7 +338,8 @@ void CloseStream(QuicStreamId id) { if (session_.connection()->transport_version() == QUIC_VERSION_99 && - QuicUtils::GetStreamType(id, session_.IsIncomingStream(id)) == + QuicUtils::GetStreamType(id, session_.perspective(), + session_.IsIncomingStream(id)) == READ_UNIDIRECTIONAL) { // Verify reset is not sent for READ_UNIDIRECTIONAL streams. EXPECT_CALL(*connection_, SendControlFrame(_)).Times(0); @@ -446,9 +450,9 @@ QuicFramer client_framer_; }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSessionTestServer, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSessionTestServer, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSessionTestServer, PeerAddress) { EXPECT_EQ(QuicSocketAddress(QuicIpAddress::Loopback4(), kTestPort), @@ -456,7 +460,7 @@ } TEST_P(QuicSessionTestServer, SelfAddress) { - EXPECT_EQ(QuicSocketAddress(), session_.self_address()); + EXPECT_TRUE(session_.self_address().IsInitialized()); } TEST_P(QuicSessionTestServer, DontCallOnWriteBlockedForDisconnectedConnection) { @@ -913,8 +917,6 @@ MockPacketWriter* writer = static_cast<MockPacketWriter*>( QuicConnectionPeer::GetWriter(session_.connection())); EXPECT_CALL(*writer, IsWriteBlocked()).WillRepeatedly(Return(true)); - EXPECT_CALL(*writer, IsWriteBlockedDataBuffered()) - .WillRepeatedly(Return(true)); EXPECT_CALL(*writer, WritePacket(_, _, _, _, _)).Times(0); TestStream* stream2 = session_.CreateOutgoingBidirectionalStream(); @@ -1237,6 +1239,12 @@ } TEST_P(QuicSessionTestServer, HandshakeUnblocksFlowControlBlockedCryptoStream) { + if (GetParam().transport_version >= QUIC_VERSION_46) { + // QUIC version 46 onwards uses CRYPTO frames for the handshake, so this + // test doesn't make sense for those versions since CRYPTO frames aren't + // flow controlled. + return; + } // Test that if the crypto stream is flow control blocked, then if the SHLO // contains a larger send window offset, the stream becomes unblocked. session_.set_writev_consumes_all_data(true); @@ -1290,19 +1298,11 @@ const QuicStreamOffset kByteOffset = 1 + kInitialSessionFlowControlWindowForTest / 2; - if (transport_version() == QUIC_VERSION_99) { - // Two more control frames than in Google QUIC, one is the STOP_SENDING - // frame, the other is the RST_STREAM generated in response. - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(4) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)).Times(2); - } else { - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(2) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); - } + EXPECT_CALL(*connection_, SendControlFrame(_)) + .Times(2) + .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); + EXPECT_CALL(*connection_, OnStreamReset(stream->id(), _)); + QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream->id(), QUIC_STREAM_CANCELLED, kByteOffset); session_.OnRstStream(rst_frame); @@ -1624,9 +1624,9 @@ QuicSessionTestClient() : QuicSessionTestBase(Perspective::IS_CLIENT) {} }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSessionTestClient, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSessionTestClient, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSessionTestClient, AvailableBidirectionalStreamsClient) { ASSERT_TRUE(session_.GetOrCreateDynamicStream( @@ -1741,20 +1741,18 @@ QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream2->id(), QUIC_STREAM_CANCELLED, 1234); + // Just for the RST_STREAM + EXPECT_CALL(*connection_, SendControlFrame(_)) + .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); if (transport_version() == QUIC_VERSION_99) { - // Once for the RST_STREAM, once for the STOP_SENDING - EXPECT_CALL(*connection_, SendControlFrame(_)) - .Times(3) - .WillRepeatedly(Invoke(&session_, &TestSession::ClearControlFrame)); - EXPECT_CALL(*connection_, OnStreamReset(stream2->id(), _)).Times(2); + EXPECT_CALL(*connection_, + OnStreamReset(stream2->id(), QUIC_STREAM_CANCELLED)); } else { - // Just for the RST_STREAM - EXPECT_CALL(*connection_, SendControlFrame(_)) - .WillOnce(Invoke(&session_, &TestSession::ClearControlFrame)); EXPECT_CALL(*connection_, OnStreamReset(stream2->id(), QUIC_RST_ACKNOWLEDGEMENT)); } stream2->OnStreamReset(rst_frame); + if (transport_version() == QUIC_VERSION_99) { // The test is predicated on the stream being fully closed. For V99, the // RST_STREAM only does one side (the read side from the perspective of the @@ -1810,11 +1808,18 @@ // Lost data on cryption stream, streams 2 and 4. EXPECT_CALL(*stream4, HasPendingRetransmission()).WillOnce(Return(true)); - EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) - .WillOnce(Return(true)); + if (connection_->transport_version() < QUIC_VERSION_47) { + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(true)); + } EXPECT_CALL(*stream2, HasPendingRetransmission()).WillOnce(Return(true)); session_.OnFrameLost(QuicFrame(frame3)); - session_.OnFrameLost(QuicFrame(frame1)); + if (connection_->transport_version() < QUIC_VERSION_47) { + session_.OnFrameLost(QuicFrame(frame1)); + } else { + QuicCryptoFrame crypto_frame(ENCRYPTION_NONE, 0, 1300); + session_.OnFrameLost(QuicFrame(&crypto_frame)); + } session_.OnFrameLost(QuicFrame(frame2)); EXPECT_TRUE(session_.WillingAndAbleToWrite()); @@ -1826,9 +1831,11 @@ // stream go first. // Do not check congestion window when crypto stream has lost data. EXPECT_CALL(*send_algorithm, CanSend(_)).Times(0); - EXPECT_CALL(*crypto_stream, OnCanWrite()); - EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) - .WillOnce(Return(false)); + if (connection_->transport_version() < QUIC_VERSION_47) { + EXPECT_CALL(*crypto_stream, OnCanWrite()); + EXPECT_CALL(*crypto_stream, HasPendingRetransmission()) + .WillOnce(Return(false)); + } // Check congestion window for non crypto streams. EXPECT_CALL(*send_algorithm, CanSend(_)).WillOnce(Return(true)); EXPECT_CALL(*stream4, OnCanWrite()); @@ -1962,8 +1969,11 @@ TEST_P(QuicSessionTestServer, SendMessage) { // Cannot send message when encryption is not established. EXPECT_FALSE(session_.IsCryptoHandshakeConfirmed()); + quic::QuicMemSliceStorage storage(nullptr, 0, nullptr, 0); EXPECT_EQ(MessageResult(MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED, 0), - session_.SendMessage("")); + session_.SendMessage( + MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), + "", &storage))); // Finish handshake. CryptoHandshakeMessage handshake_message; @@ -1971,23 +1981,29 @@ EXPECT_TRUE(session_.IsCryptoHandshakeConfirmed()); QuicStringPiece message; - QuicMessageFrame frame(1, message); EXPECT_CALL(*connection_, SendMessage(1, _)) .WillOnce(Return(MESSAGE_STATUS_SUCCESS)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 1), - session_.SendMessage(message)); + session_.SendMessage( + MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), + message, &storage))); // Verify message_id increases. EXPECT_CALL(*connection_, SendMessage(2, _)) .WillOnce(Return(MESSAGE_STATUS_TOO_LARGE)); EXPECT_EQ(MessageResult(MESSAGE_STATUS_TOO_LARGE, 0), - session_.SendMessage(message)); + session_.SendMessage( + MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), + message, &storage))); // Verify unsent message does not consume a message_id. EXPECT_CALL(*connection_, SendMessage(2, _)) .WillOnce(Return(MESSAGE_STATUS_SUCCESS)); - QuicMessageFrame frame2(2, message); EXPECT_EQ(MessageResult(MESSAGE_STATUS_SUCCESS, 2), - session_.SendMessage(message)); + session_.SendMessage( + MakeSpan(connection_->helper()->GetStreamSendBufferAllocator(), + message, &storage))); + QuicMessageFrame frame(1); + QuicMessageFrame frame2(2); EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame))); EXPECT_FALSE(session_.IsFrameOutstanding(QuicFrame(&frame2))); @@ -2313,7 +2329,7 @@ QuicStreamId stream_id = stream->id(); QuicStopSendingFrame frame(1, stream_id, 123); EXPECT_CALL(*stream, OnStopSending(123)); - // Expect a reset to come back out.xxxxx + // Expect a reset to come back out. EXPECT_CALL(*connection_, SendControlFrame(_)); EXPECT_CALL( *connection_,
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc index 6c8ea8d..70af656 100644 --- a/quic/core/quic_stream.cc +++ b/quic/core/quic_stream.cc
@@ -23,12 +23,6 @@ namespace { -struct iovec MakeIovec(QuicStringPiece data) { - struct iovec iov = {const_cast<char*>(data.data()), - static_cast<size_t>(data.size())}; - return iov; -} - size_t GetInitialStreamFlowControlWindowToSend(QuicSession* session) { return session->config()->GetInitialStreamFlowControlWindowToSend(); } @@ -236,20 +230,16 @@ stream_contributes_to_connection_flow_control_(true), busy_counter_(0), add_random_padding_after_fin_(false), - ack_listener_(nullptr), send_buffer_( session->connection()->helper()->GetStreamSendBufferAllocator()), buffered_data_threshold_(GetQuicFlag(FLAGS_quic_buffered_data_threshold)), is_static_(is_static), deadline_(QuicTime::Zero()), type_(session->connection()->transport_version() == QUIC_VERSION_99 - ? QuicUtils::GetStreamType(id_, session->IsIncomingStream(id_)) + ? QuicUtils::GetStreamType(id_, + perspective_, + session->IsIncomingStream(id_)) : type) { - if (session->connection()->transport_version() == QUIC_VERSION_99) { - DCHECK_EQ(type, - QuicUtils::GetStreamType(id_, session->IsIncomingStream(id_))) - << id_; - } if (type_ == WRITE_UNIDIRECTIONAL) { set_fin_received(true); CloseReadSide(); @@ -453,7 +443,7 @@ // Do not respect buffered data upper limit as WriteOrBufferData guarantees // all data to be consumed. if (data.length() > 0) { - struct iovec iov(MakeIovec(data)); + struct iovec iov(QuicUtils::MakeIovec(data)); QuicStreamOffset offset = send_buffer_.stream_offset(); if (kMaxStreamLength - offset < data.length()) { QUIC_BUG << "Write too many data via stream " << id_; @@ -783,13 +773,14 @@ bool QuicStream::OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length, bool fin_acked, - QuicTime::Delta ack_delay_time) { + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length) { QUIC_DVLOG(1) << ENDPOINT << "stream " << id_ << " Acking " << "[" << offset << ", " << offset + data_length << "]" << " fin = " << fin_acked; - QuicByteCount newly_acked_length = 0; + *newly_acked_length = 0; if (!send_buffer_.OnStreamDataAcked(offset, data_length, - &newly_acked_length)) { + newly_acked_length)) { CloseConnectionWithDetails(QUIC_INTERNAL_ERROR, "Trying to ack unsent data."); return false; @@ -801,7 +792,7 @@ } // Indicates whether ack listener's OnPacketAcked should be called. const bool new_data_acked = - newly_acked_length > 0 || (fin_acked && fin_outstanding_); + *newly_acked_length > 0 || (fin_acked && fin_outstanding_); if (fin_acked) { fin_outstanding_ = false; fin_lost_ = false; @@ -809,9 +800,6 @@ if (!IsWaitingForAcks()) { session_->OnStreamDoneWaitingForAcks(id_); } - if (ack_listener_ != nullptr && new_data_acked) { - ack_listener_->OnPacketAcked(newly_acked_length, ack_delay_time); - } return new_data_acked; } @@ -822,9 +810,6 @@ if (fin_retransmitted) { fin_lost_ = false; } - if (ack_listener_ != nullptr) { - ack_listener_->OnPacketRetransmitted(data_length); - } } void QuicStream::OnStreamFrameLost(QuicStreamOffset offset,
diff --git a/quic/core/quic_stream.h b/quic/core/quic_stream.h index 13a6b2c..fe0a794 100644 --- a/quic/core/quic_stream.h +++ b/quic/core/quic_stream.h
@@ -286,12 +286,13 @@ QuicDataWriter* writer); // Called when data [offset, offset + data_length) is acked. |fin_acked| - // indicates whether the fin is acked. Returns true if any new stream data - // (including fin) gets acked. + // indicates whether the fin is acked. Returns true and updates + // |newly_acked_length| if any new stream data (including fin) gets acked. virtual bool OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length, bool fin_acked, - QuicTime::Delta ack_delay_time); + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length); // Called when data [offset, offset + data_length) was retransmitted. // |fin_retransmitted| indicates whether fin was retransmitted. @@ -413,11 +414,6 @@ stream_contributes_to_connection_flow_control_ = false; } - void set_ack_listener( - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - ack_listener_ = std::move(ack_listener); - } - const QuicIntervalSet<QuicStreamOffset>& bytes_acked() const; const QuicStreamSendBuffer& send_buffer() const { return send_buffer_; } @@ -521,10 +517,6 @@ // stream. bool add_random_padding_after_fin_; - // Ack listener of this stream, and it is notified when any of written bytes - // are acked. - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener_; - // Send buffer of this stream. Send buffer is cleaned up when data gets acked // or discarded. QuicStreamSendBuffer send_buffer_;
diff --git a/quic/core/quic_stream_id_manager_test.cc b/quic/core/quic_stream_id_manager_test.cc index 5647d75..51799e2 100644 --- a/quic/core/quic_stream_id_manager_test.cc +++ b/quic/core/quic_stream_id_manager_test.cc
@@ -63,6 +63,7 @@ TestQuicStream* stream = new TestQuicStream( id, this, DetermineStreamType(id, connection()->transport_version(), + perspective(), /*is_incoming=*/true, BIDIRECTIONAL)); ActivateStream(QuicWrapUnique(stream)); return stream; @@ -170,7 +171,7 @@ : QuicStreamIdManagerTestBase(Perspective::IS_CLIENT) {} }; -INSTANTIATE_TEST_CASE_P(Tests, QuicStreamIdManagerTestClient, testing::Bool()); +INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTestClient, testing::Bool()); // Check that the parameters used by the stream ID manager are properly // initialized. @@ -618,7 +619,7 @@ : QuicStreamIdManagerTestBase(Perspective::IS_SERVER) {} }; -INSTANTIATE_TEST_CASE_P(Tests, QuicStreamIdManagerTestServer, testing::Bool()); +INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTestServer, testing::Bool()); // This test checks that the initialization for the maximum allowed outgoing // stream id is correct.
diff --git a/quic/core/quic_stream_send_buffer.cc b/quic/core/quic_stream_send_buffer.cc index 628439a..efe6240 100644 --- a/quic/core/quic_stream_send_buffer.cc +++ b/quic/core/quic_stream_send_buffer.cc
@@ -6,12 +6,12 @@ #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h" #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" +#include "net/third_party/quiche/src/quic/core/quic_interval.h" #include "net/third_party/quiche/src/quic/core/quic_stream_send_buffer.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" #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_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic {
diff --git a/quic/core/quic_stream_send_buffer.h b/quic/core/quic_stream_send_buffer.h index 7b6a9c9..4bcac34 100644 --- a/quic/core/quic_stream_send_buffer.h +++ b/quic/core/quic_stream_send_buffer.h
@@ -6,6 +6,7 @@ #define QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_ #include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_iovec.h" #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice.h"
diff --git a/quic/core/quic_stream_sequencer.cc b/quic/core/quic_stream_sequencer.cc index cfd288d..6311dcf 100644 --- a/quic/core/quic_stream_sequencer.cc +++ b/quic/core/quic_stream_sequencer.cc
@@ -47,12 +47,23 @@ return; } } + OnFrameData(byte_offset, data_len, frame.data_buffer); +} + +void QuicStreamSequencer::OnCryptoFrame(const QuicCryptoFrame& frame) { + ++num_frames_received_; + OnFrameData(frame.offset, frame.data_length, frame.data_buffer); +} + +void QuicStreamSequencer::OnFrameData(QuicStreamOffset byte_offset, + size_t data_len, + const char* data_buffer) { const size_t previous_readable_bytes = buffered_frames_.ReadableBytes(); size_t bytes_written; QuicString error_details; QuicErrorCode result = buffered_frames_.OnStreamData( - byte_offset, QuicStringPiece(frame.data_buffer, frame.data_length), - &bytes_written, &error_details); + byte_offset, QuicStringPiece(data_buffer, data_len), &bytes_written, + &error_details); if (result != QUIC_NO_ERROR) { QuicString details = QuicStrCat( "Stream ", stream_->id(), ": ", QuicErrorCodeToString(result), ": ",
diff --git a/quic/core/quic_stream_sequencer.h b/quic/core/quic_stream_sequencer.h index dfe5e7d..3feee5e 100644 --- a/quic/core/quic_stream_sequencer.h +++ b/quic/core/quic_stream_sequencer.h
@@ -64,6 +64,13 @@ // buffered. void OnStreamFrame(const QuicStreamFrame& frame); + // If the frame is the next one we need in order to process in-order data, + // ProcessData will be immediately called on the crypto stream until all + // buffered data is processed or the crypto stream fails to consume data. Any + // unconsumed data will be buffered. If the frame is not the next in line, it + // will be buffered. + void OnCryptoFrame(const QuicCryptoFrame& frame); + // Once data is buffered, it's up to the stream to read it when the stream // can handle more data. The following three functions make that possible. @@ -162,6 +169,11 @@ // the stream of FIN, and clear buffers. bool MaybeCloseStream(); + // Shared implementation between OnStreamFrame and OnCryptoFrame. + void OnFrameData(QuicStreamOffset byte_offset, + size_t data_len, + const char* data_buffer); + // The stream which owns this sequencer. StreamInterface* stream_;
diff --git a/quic/core/quic_stream_sequencer_buffer.cc b/quic/core/quic_stream_sequencer_buffer.cc index b96a89a..2f09095 100644 --- a/quic/core/quic_stream_sequencer_buffer.cc +++ b/quic/core/quic_stream_sequencer_buffer.cc
@@ -4,10 +4,11 @@ #include "net/third_party/quiche/src/quic/core/quic_stream_sequencer_buffer.h" +#include "net/third_party/quiche/src/quic/core/quic_constants.h" +#include "net/third_party/quiche/src/quic/core/quic_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.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_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
diff --git a/quic/core/quic_stream_sequencer_buffer.h b/quic/core/quic_stream_sequencer_buffer.h index 900fad0..09646b9 100644 --- a/quic/core/quic_stream_sequencer_buffer.h +++ b/quic/core/quic_stream_sequencer_buffer.h
@@ -64,6 +64,7 @@ #include <memory> #include "base/macros.h" +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" #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"
diff --git a/quic/core/quic_stream_test.cc b/quic/core/quic_stream_test.cc index e8338b3..d019f71 100644 --- a/quic/core/quic_stream_test.cc +++ b/quic/core/quic_stream_test.cc
@@ -61,7 +61,6 @@ using QuicStream::CloseWriteSide; using QuicStream::fin_buffered; using QuicStream::OnClose; - using QuicStream::set_ack_listener; using QuicStream::WriteMemSlices; using QuicStream::WriteOrBufferData; using QuicStream::WritevData; @@ -160,17 +159,16 @@ // Index value of 1 has the test run with supported-version[1], which is some // version OTHER than 99. -INSTANTIATE_TEST_CASE_P( - QuicStreamTests, - QuicStreamTest, +INSTANTIATE_TEST_SUITE_P( + QuicStreamTests, QuicStreamTest, ::testing::ValuesIn(ParsedVersionOfIndex(AllSupportedVersions(), 1))); // Make a parameterized version of the QuicStreamTest for those tests // that need to differentiate based on version number. class QuicParameterizedStreamTest : public QuicStreamTestBase {}; -INSTANTIATE_TEST_CASE_P(QuicParameterizedStreamTests, - QuicParameterizedStreamTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(QuicParameterizedStreamTests, + QuicParameterizedStreamTest, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicStreamTest, PendingStreamTooMuchData) { Initialize(); @@ -271,7 +269,9 @@ 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, 0u); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u); connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(stream_, kTestStreamId, _, _, _)) @@ -352,7 +352,9 @@ 1 + QuicPacketCreator::StreamFramePacketOverhead( connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, 0u); + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + VARIABLE_LENGTH_INTEGER_LENGTH_0, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u); connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) @@ -788,9 +790,6 @@ TEST_P(QuicStreamTest, StreamWaitsForAcks) { Initialize(); - QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( - new StrictMock<MockAckListener>); - stream_->set_ack_listener(mock_ack_listener); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Stream is not waiting for acks initially. @@ -801,9 +800,10 @@ stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero())); + QuicByteCount newly_acked_length = 0; + EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(9u, newly_acked_length); // Stream is not waiting for acks as all sent data is acked. EXPECT_FALSE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); @@ -818,21 +818,20 @@ EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // kData2 is retransmitted. - EXPECT_CALL(*mock_ack_listener, OnPacketRetransmitted(9)); stream_->OnStreamFrameRetransmitted(9, 9, false); // kData2 is acked. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero())); + EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(9u, newly_acked_length); // Stream is waiting for acks as FIN is not acked. EXPECT_TRUE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); // FIN is acked. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(18, 0, true, QuicTime::Delta::Zero())); + EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 0, true, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(0u, newly_acked_length); EXPECT_FALSE(stream_->IsWaitingForAcks()); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); } @@ -849,19 +848,24 @@ EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero())); + QuicByteCount newly_acked_length = 0; + EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(9u, newly_acked_length); EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size()); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(18, 9, false, QuicTime::Delta::Zero())); + EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(9u, newly_acked_length); EXPECT_EQ(3u, QuicStreamPeer::SendBuffer(stream_).size()); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero())); + EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(9u, newly_acked_length); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); // FIN is not acked yet. EXPECT_TRUE(stream_->IsWaitingForAcks()); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero())); + EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(0u, newly_acked_length); EXPECT_FALSE(stream_->IsWaitingForAcks()); } @@ -1183,9 +1187,6 @@ TEST_P(QuicStreamTest, StreamDataGetAckedMultipleTimes) { Initialize(); - QuicReferenceCountedPointer<MockAckListener> mock_ack_listener( - new StrictMock<MockAckListener>); - stream_->set_ack_listener(mock_ack_listener); EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); // Send [0, 27) and fin. @@ -1197,42 +1198,41 @@ // Ack [0, 9), [5, 22) and [18, 26) // Verify [0, 9) 9 bytes are acked. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(9, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero())); + QuicByteCount newly_acked_length = 0; + EXPECT_TRUE(stream_->OnStreamFrameAcked(0, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(9u, newly_acked_length); EXPECT_EQ(2u, QuicStreamPeer::SendBuffer(stream_).size()); // Verify [9, 22) 13 bytes are acked. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(13, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(5, 17, false, QuicTime::Delta::Zero())); + EXPECT_TRUE(stream_->OnStreamFrameAcked(5, 17, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(13u, newly_acked_length); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); // Verify [22, 26) 4 bytes are acked. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(4, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(18, 8, false, QuicTime::Delta::Zero())); + EXPECT_TRUE(stream_->OnStreamFrameAcked(18, 8, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(4u, newly_acked_length); EXPECT_EQ(1u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Ack [0, 27). - // Verify [26, 27) 1 byte is acked. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(1, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(26, 1, false, QuicTime::Delta::Zero())); + // Ack [0, 27). Verify [26, 27) 1 byte is acked. + EXPECT_TRUE(stream_->OnStreamFrameAcked(26, 1, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(1u, newly_acked_length); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_TRUE(stream_->IsWaitingForAcks()); - // Ack Fin. Verify OnPacketAcked is called. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(0, _)); - EXPECT_TRUE( - stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero())); + // Ack Fin. + EXPECT_TRUE(stream_->OnStreamFrameAcked(27, 0, true, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(0u, newly_acked_length); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_FALSE(stream_->IsWaitingForAcks()); - // Ack [10, 27) and fin. - // No new data is acked, verify OnPacketAcked is not called. - EXPECT_CALL(*mock_ack_listener, OnPacketAcked(_, _)).Times(0); - EXPECT_FALSE( - stream_->OnStreamFrameAcked(10, 17, true, QuicTime::Delta::Zero())); + // Ack [10, 27) and fin. No new data is acked. + EXPECT_FALSE(stream_->OnStreamFrameAcked( + 10, 17, true, QuicTime::Delta::Zero(), &newly_acked_length)); + EXPECT_EQ(0u, newly_acked_length); EXPECT_EQ(0u, QuicStreamPeer::SendBuffer(stream_).size()); EXPECT_FALSE(stream_->IsWaitingForAcks()); } @@ -1282,8 +1282,10 @@ EXPECT_TRUE(stream_->HasPendingRetransmission()); // Ack [9, 18). - EXPECT_TRUE( - stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero())); + QuicByteCount newly_acked_length = 0; + EXPECT_TRUE(stream_->OnStreamFrameAcked(9, 9, false, QuicTime::Delta::Zero(), + &newly_acked_length)); + EXPECT_EQ(9u, newly_acked_length); EXPECT_FALSE(stream_->IsStreamFrameOutstanding(9, 3, false)); EXPECT_TRUE(stream_->HasPendingRetransmission()); // This OnCanWrite causes [18, 27) and fin to be retransmitted. Verify fin can @@ -1385,8 +1387,10 @@ stream_->WriteOrBufferData(kData1, false, nullptr); stream_->WriteOrBufferData(kData1, true, nullptr); // Ack [10, 13). - stream_->OnStreamFrameAcked(10, 3, false, QuicTime::Delta::Zero()); - + QuicByteCount newly_acked_length = 0; + stream_->OnStreamFrameAcked(10, 3, false, QuicTime::Delta::Zero(), + &newly_acked_length); + EXPECT_EQ(3u, newly_acked_length); // Retransmit [0, 18) with fin, and only [0, 8) is consumed. EXPECT_CALL(*session_, WritevData(_, stream_->id(), 10, 0, NO_FIN)) .WillOnce(InvokeWithoutArgs([this]() {
diff --git a/quic/core/quic_time_wait_list_manager.cc b/quic/core/quic_time_wait_list_manager.cc index 731df3e..5335455 100644 --- a/quic/core/quic_time_wait_list_manager.cc +++ b/quic/core/quic_time_wait_list_manager.cc
@@ -336,9 +336,6 @@ QuicUint128 QuicTimeWaitListManager::GetStatelessResetToken( QuicConnectionId connection_id) const { - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { - return QuicConnectionIdToUInt64(connection_id); - } return QuicUtils::GenerateStatelessResetToken(connection_id); }
diff --git a/quic/core/quic_time_wait_list_manager_test.cc b/quic/core/quic_time_wait_list_manager_test.cc index 0d3244b..263702a 100644 --- a/quic/core/quic_time_wait_list_manager_test.cc +++ b/quic/core/quic_time_wait_list_manager_test.cc
@@ -55,9 +55,6 @@ } bool IsValidStatelessResetToken(QuicUint128 token) const override { - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { - return token == QuicConnectionIdToUInt64(connection_id_); - } return token == QuicUtils::GenerateStatelessResetToken(connection_id_); } @@ -144,8 +141,6 @@ void SetUp() override { EXPECT_CALL(writer_, IsWriteBlocked()) .WillRepeatedly(ReturnPointee(&writer_is_blocked_)); - EXPECT_CALL(writer_, IsWriteBlockedDataBuffered()) - .WillRepeatedly(Return(false)); } void AddConnectionId(QuicConnectionId connection_id, @@ -221,14 +216,8 @@ QuicIetfStatelessResetPacket stateless_reset = visitor.stateless_reset_packet(); - QuicUint128 expected_stateless_reset_token; - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER)) { - expected_stateless_reset_token = - QuicConnectionIdToUInt64(expected_connection_id); - } else { - expected_stateless_reset_token = - QuicUtils::GenerateStatelessResetToken(expected_connection_id); - } + QuicUint128 expected_stateless_reset_token = + QuicUtils::GenerateStatelessResetToken(expected_connection_id); bool stateless_reset_is_valid = stateless_reset.stateless_reset_token == expected_stateless_reset_token;
diff --git a/quic/core/quic_trace_visitor.cc b/quic/core/quic_trace_visitor.cc index b0fc8ae..ba2ed7f 100644 --- a/quic/core/quic_trace_visitor.cc +++ b/quic/core/quic_trace_visitor.cc
@@ -13,7 +13,7 @@ switch (level) { case ENCRYPTION_NONE: return quic_trace::ENCRYPTION_INITIAL; - case ENCRYPTION_INITIAL: + case ENCRYPTION_ZERO_RTT: return quic_trace::ENCRYPTION_0RTT; case ENCRYPTION_FORWARD_SECURE: return quic_trace::ENCRYPTION_1RTT; @@ -26,20 +26,8 @@ QuicTraceVisitor::QuicTraceVisitor(const QuicConnection* connection) : connection_(connection), start_time_(connection_->clock()->ApproximateNow()) { - QuicString binary_connection_id; - if (!QuicConnectionIdSupportsVariableLength(connection->perspective())) { - // QUIC CIDs are currently represented in memory as a converted - // representation of the on-wire ID. Convert it back to wire format before - // recording, since the standard treats it as an opaque blob. - uint64_t connection_id = QuicEndian::HostToNet64( - QuicConnectionIdToUInt64(connection->connection_id())); - binary_connection_id = QuicString( - reinterpret_cast<const char*>(&connection_id), sizeof(connection_id)); - } else { - binary_connection_id.assign(connection->connection_id().data(), - connection->connection_id().length()); - } - + QuicString binary_connection_id(connection->connection_id().data(), + connection->connection_id().length()); // We assume that the connection ID in gQUIC is equivalent to the // server-chosen client-selected ID. switch (connection->perspective()) { @@ -338,4 +326,4 @@ } } -}; // namespace quic +} // namespace quic
diff --git a/quic/core/quic_trace_visitor.h b/quic/core/quic_trace_visitor.h index efbbee3..a3e7dda 100644 --- a/quic/core/quic_trace_visitor.h +++ b/quic/core/quic_trace_visitor.h
@@ -65,6 +65,6 @@ const QuicTime start_time_; }; -}; // namespace quic +} // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_TRACE_VISITOR_H_
diff --git a/quic/core/quic_types.h b/quic/core/quic_types.h index 7718468..bf7943d 100644 --- a/quic/core/quic_types.h +++ b/quic/core/quic_types.h
@@ -177,6 +177,7 @@ BLOCKED_FRAME = 5, STOP_WAITING_FRAME = 6, PING_FRAME = 7, + CRYPTO_FRAME = 8, // STREAM and ACK frames are special frames. They are encoded differently on // the wire and their values do not need to be stable. @@ -197,7 +198,6 @@ PATH_CHALLENGE_FRAME, STOP_SENDING_FRAME, MESSAGE_FRAME, - CRYPTO_FRAME, NEW_TOKEN_FRAME, RETIRE_CONNECTION_ID_FRAME, @@ -234,15 +234,14 @@ // 0x09 through 0x0f are various flag settings of the IETF_STREAM frame. IETF_MAX_DATA = 0x10, IETF_MAX_STREAM_DATA = 0x11, - IETF_MAX_STREAM_ID = 0x12, // TODO(fkastenholz): Will become IETF_MAX_STREAMS - // 0x13 reserved, a flag setting for IETF_MAX_STREAMS. + IETF_MAX_STREAMS_BIDIRECTIONAL = 0x12, + IETF_MAX_STREAMS_UNIDIRECTIONAL = 0x13, IETF_BLOCKED = 0x14, // TODO(fkastenholz): Should, eventually, be renamed to // IETF_DATA_BLOCKED IETF_STREAM_BLOCKED = 0x15, // TODO(fkastenholz): Should, eventually, be // renamed to IETF_STREAM_DATA_BLOCKED - IETF_STREAM_ID_BLOCKED = - 0x16, // TODO(fkastenholz): Will become IETF_STREAMS_BLOCKED - // 0x17 reserved, a flag setting for IETF_STREAMS_BLOCKED + IETF_STREAMS_BLOCKED_BIDIRECTIONAL = 0x16, + IETF_STREAMS_BLOCKED_UNIDIRECTIONAL = 0x17, IETF_NEW_CONNECTION_ID = 0x18, IETF_RETIRE_CONNECTION_ID = 0x19, IETF_PATH_CHALLENGE = 0x1a, @@ -271,10 +270,25 @@ #define IETF_STREAM_FRAME_LEN_BIT 0x02 #define IETF_STREAM_FRAME_OFF_BIT 0x04 +enum QuicVariableLengthIntegerLength : uint8_t { + // Length zero means the variable length integer is not present. + VARIABLE_LENGTH_INTEGER_LENGTH_0 = 0, + VARIABLE_LENGTH_INTEGER_LENGTH_1 = 1, + VARIABLE_LENGTH_INTEGER_LENGTH_2 = 2, + VARIABLE_LENGTH_INTEGER_LENGTH_4 = 4, + VARIABLE_LENGTH_INTEGER_LENGTH_8 = 8, +}; + +// By default we write the IETF long header length using the 2-byte encoding +// of variable length integers, even when the length is below 64, which allows +// us to fill in the length before knowing what the length actually is. +const QuicVariableLengthIntegerLength kQuicDefaultLongHeaderLengthLength = + VARIABLE_LENGTH_INTEGER_LENGTH_2; + enum QuicPacketNumberLength : uint8_t { PACKET_1BYTE_PACKET_NUMBER = 1, PACKET_2BYTE_PACKET_NUMBER = 2, - PACKET_3BYTE_PACKET_NUMBER = 3, // Used in version > QUIC_VERSION_46. + PACKET_3BYTE_PACKET_NUMBER = 3, // Used in version > QUIC_VERSION_44. PACKET_4BYTE_PACKET_NUMBER = 4, // TODO(rch): Remove this when we remove QUIC_VERSION_39. PACKET_6BYTE_PACKET_NUMBER = 6, @@ -359,7 +373,7 @@ // understand. enum EncryptionLevel : int8_t { ENCRYPTION_NONE = 0, - ENCRYPTION_INITIAL = 1, + ENCRYPTION_ZERO_RTT = 1, ENCRYPTION_FORWARD_SECURE = 2, NUM_ENCRYPTION_LEVELS, @@ -551,6 +565,16 @@ READ_UNIDIRECTIONAL, }; +// A packet number space is the context in which a packet can be processed and +// acknowledged. +enum PacketNumberSpace : uint8_t { + INITIAL_DATA = 0, // Only used in IETF QUIC. + HANDSHAKE_DATA = 1, + APPLICATION_DATA = 2, + + NUM_PACKET_NUMBER_SPACES, +}; + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_TYPES_H_
diff --git a/quic/core/quic_unacked_packet_map.cc b/quic/core/quic_unacked_packet_map.cc index 32fd272..859bf39 100644 --- a/quic/core/quic_unacked_packet_map.cc +++ b/quic/core/quic_unacked_packet_map.cc
@@ -24,13 +24,20 @@ } } // namespace -QuicUnackedPacketMap::QuicUnackedPacketMap() - : least_unacked_(FirstSendingPacketNumber()), +QuicUnackedPacketMap::QuicUnackedPacketMap(Perspective perspective) + : perspective_(perspective), + least_unacked_(FirstSendingPacketNumber()), bytes_in_flight_(0), pending_crypto_packet_count_(0), last_crypto_packet_sent_time_(QuicTime::Zero()), session_notifier_(nullptr), - session_decides_what_to_write_(false) {} + session_decides_what_to_write_(false), + use_uber_loss_algorithm_( + GetQuicReloadableFlag(quic_use_uber_loss_algorithm)) { + if (use_uber_loss_algorithm_) { + QUIC_RELOADABLE_FLAG_COUNT(quic_use_uber_loss_algorithm); + } +} QuicUnackedPacketMap::~QuicUnackedPacketMap() { for (QuicTransmissionInfo& transmission_info : unacked_packets_) { @@ -76,7 +83,12 @@ if (set_in_flight) { bytes_in_flight_ += bytes_sent; info.in_flight = true; - largest_sent_retransmittable_packet_ = packet_number; + if (use_uber_loss_algorithm_) { + largest_sent_retransmittable_packets_[GetPacketNumberSpace( + info.encryption_level)] = packet_number; + } else { + largest_sent_retransmittable_packet_ = packet_number; + } } unacked_packets_.push_back(info); // Swap the retransmittable frames to avoid allocations. @@ -216,6 +228,20 @@ largest_acked_ = largest_acked; } +void QuicUnackedPacketMap::MaybeUpdateLargestAckedOfPacketNumberSpace( + EncryptionLevel encryption_level, + QuicPacketNumber packet_number) { + DCHECK(use_uber_loss_algorithm_); + const PacketNumberSpace packet_number_space = + GetPacketNumberSpace(encryption_level); + if (!largest_acked_packets_[packet_number_space].IsInitialized()) { + largest_acked_packets_[packet_number_space] = packet_number; + } else { + largest_acked_packets_[packet_number_space] = + std::max(largest_acked_packets_[packet_number_space], packet_number); + } +} + bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt( QuicPacketNumber packet_number, const QuicTransmissionInfo& info) const { @@ -475,6 +501,45 @@ aggregated_stream_frame_.stream_id = -1; } +PacketNumberSpace QuicUnackedPacketMap::GetPacketNumberSpace( + QuicPacketNumber packet_number) const { + DCHECK(use_uber_loss_algorithm_); + return GetPacketNumberSpace( + GetTransmissionInfo(packet_number).encryption_level); +} + +PacketNumberSpace QuicUnackedPacketMap::GetPacketNumberSpace( + EncryptionLevel encryption_level) const { + DCHECK(use_uber_loss_algorithm_); + if (perspective_ == Perspective::IS_CLIENT) { + return encryption_level == ENCRYPTION_NONE ? HANDSHAKE_DATA + : APPLICATION_DATA; + } + return encryption_level == ENCRYPTION_FORWARD_SECURE ? APPLICATION_DATA + : HANDSHAKE_DATA; +} + +QuicPacketNumber QuicUnackedPacketMap::GetLargestAckedOfPacketNumberSpace( + PacketNumberSpace packet_number_space) const { + DCHECK(use_uber_loss_algorithm_); + if (packet_number_space >= NUM_PACKET_NUMBER_SPACES) { + QUIC_BUG << "Invalid packet number space: " << packet_number_space; + return QuicPacketNumber(); + } + return largest_acked_packets_[packet_number_space]; +} + +QuicPacketNumber +QuicUnackedPacketMap::GetLargestSentRetransmittableOfPacketNumberSpace( + PacketNumberSpace packet_number_space) const { + DCHECK(use_uber_loss_algorithm_); + if (packet_number_space >= NUM_PACKET_NUMBER_SPACES) { + QUIC_BUG << "Invalid packet number space: " << packet_number_space; + return QuicPacketNumber(); + } + return largest_sent_retransmittable_packets_[packet_number_space]; +} + void QuicUnackedPacketMap::SetSessionDecideWhatToWrite( bool session_decides_what_to_write) { if (largest_sent_packet_.IsInitialized()) {
diff --git a/quic/core/quic_unacked_packet_map.h b/quic/core/quic_unacked_packet_map.h index b4d13c5..b6f7af5 100644 --- a/quic/core/quic_unacked_packet_map.h +++ b/quic/core/quic_unacked_packet_map.h
@@ -26,7 +26,7 @@ // 3) Track sent time of packets to provide RTT measurements from acks. class QUIC_EXPORT_PRIVATE QuicUnackedPacketMap { public: - QuicUnackedPacketMap(); + QuicUnackedPacketMap(Perspective perspective); QuicUnackedPacketMap(const QuicUnackedPacketMap&) = delete; QuicUnackedPacketMap& operator=(const QuicUnackedPacketMap&) = delete; ~QuicUnackedPacketMap(); @@ -93,6 +93,7 @@ // Returns the largest retransmittable packet number that has been sent. QuicPacketNumber largest_sent_retransmittable_packet() const { + DCHECK(!use_uber_loss_algorithm_); return largest_sent_retransmittable_packet_; } @@ -165,6 +166,12 @@ // |largest_acked| are discarded if they are only for the RTT purposes. void IncreaseLargestAcked(QuicPacketNumber largest_acked); + // Called when |packet_number| gets acked. Maybe increase the largest acked of + // corresponding packet number space of |encryption_level|. + void MaybeUpdateLargestAckedOfPacketNumberSpace( + EncryptionLevel encryption_level, + QuicPacketNumber packet_number); + // Remove any packets no longer needed for retransmission, congestion, or // RTT measurement purposes. void RemoveObsoletePackets(); @@ -180,6 +187,24 @@ // stream id. void NotifyAggregatedStreamFrameAcked(QuicTime::Delta ack_delay); + // Returns packet number space that |packet_number| belongs to. Please use + // GetPacketNumberSpace(EncryptionLevel) whenever encryption level is + // available. + PacketNumberSpace GetPacketNumberSpace(QuicPacketNumber packet_number) const; + + // Returns packet number space of |encryption_level|. + PacketNumberSpace GetPacketNumberSpace( + EncryptionLevel encryption_level) const; + + // Returns largest acked packet number of |packet_number_space|. + QuicPacketNumber GetLargestAckedOfPacketNumberSpace( + PacketNumberSpace packet_number_space) const; + + // Returns largest sent retransmittable packet number of + // |packet_number_space|. + QuicPacketNumber GetLargestSentRetransmittableOfPacketNumberSpace( + PacketNumberSpace packet_number_space) const; + // Called to start/stop letting session decide what to write. void SetSessionDecideWhatToWrite(bool session_decides_what_to_write); @@ -189,6 +214,10 @@ return session_decides_what_to_write_; } + bool use_uber_loss_algorithm() const { return use_uber_loss_algorithm_; } + + Perspective perspective() const { return perspective_; } + private: friend class test::QuicUnackedPacketMapPeer; @@ -218,13 +247,24 @@ bool IsPacketUseless(QuicPacketNumber packet_number, const QuicTransmissionInfo& info) const; + const Perspective perspective_; + QuicPacketNumber largest_sent_packet_; // The largest sent packet we expect to receive an ack for. + // TODO(fayang): Remove largest_sent_retransmittable_packet_ when deprecating + // quic_use_uber_loss_algorithm. QuicPacketNumber largest_sent_retransmittable_packet_; + // The largest sent packet we expect to receive an ack for per packet number + // space. Only used if use_uber_loss_algorithm_ is true. + QuicPacketNumber + largest_sent_retransmittable_packets_[NUM_PACKET_NUMBER_SPACES]; // The largest sent largest_acked in an ACK frame. QuicPacketNumber largest_sent_largest_acked_; // The largest received largest_acked from an ACK frame. QuicPacketNumber largest_acked_; + // The largest received largest_acked from ACK frame per packet number space. + // Only used if use_uber_loss_algorithm_ is true. + QuicPacketNumber largest_acked_packets_[NUM_PACKET_NUMBER_SPACES]; // Newly serialized retransmittable packets are added to this map, which // contains owning pointers to any contained frames. If a packet is @@ -254,6 +294,9 @@ // If true, let session decides what to write. bool session_decides_what_to_write_; + + // Latched value of quic_use_uber_loss_algorithm. + const bool use_uber_loss_algorithm_; }; } // namespace quic
diff --git a/quic/core/quic_unacked_packet_map_test.cc b/quic/core/quic_unacked_packet_map_test.cc index df14321..cf725fa 100644 --- a/quic/core/quic_unacked_packet_map_test.cc +++ b/quic/core/quic_unacked_packet_map_test.cc
@@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h" using testing::_; using testing::Return; @@ -18,27 +19,46 @@ namespace quic { namespace test { - -class QuicUnackedPacketMapPeer { - public: - static const QuicStreamFrame& GetAggregatedStreamFrame( - const QuicUnackedPacketMap& unacked_packets) { - return unacked_packets.aggregated_stream_frame_; - } -}; - namespace { // Default packet length. const uint32_t kDefaultLength = 1000; -class QuicUnackedPacketMapTest : public QuicTestWithParam<bool> { +struct TestParams { + TestParams(Perspective perspective, bool session_decides_what_to_write) + : perspective(perspective), + session_decides_what_to_write(session_decides_what_to_write) {} + + friend std::ostream& operator<<(std::ostream& os, const TestParams& p) { + os << "{ Perspective: " << p.perspective + << " session_decides_what_to_write: " << p.session_decides_what_to_write + << " }"; + return os; + } + + Perspective perspective; + bool session_decides_what_to_write; +}; + +std::vector<TestParams> GetTestParams() { + std::vector<TestParams> params; + for (Perspective perspective : + {Perspective::IS_CLIENT, Perspective::IS_SERVER}) { + for (bool session_decides_what_to_write : {true, false}) { + params.push_back(TestParams(perspective, session_decides_what_to_write)); + } + } + return params; +} + +class QuicUnackedPacketMapTest : public QuicTestWithParam<TestParams> { protected: QuicUnackedPacketMapTest() - : unacked_packets_(), + : unacked_packets_(GetParam().perspective), now_(QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1000)) { unacked_packets_.SetSessionNotifier(¬ifier_); - unacked_packets_.SetSessionDecideWhatToWrite(GetParam()); + unacked_packets_.SetSessionDecideWhatToWrite( + GetParam().session_decides_what_to_write); EXPECT_CALL(notifier_, IsFrameOutstanding(_)).WillRepeatedly(Return(true)); EXPECT_CALL(notifier_, OnStreamFrameRetransmitted(_)) .Times(testing::AnyNumber()); @@ -178,7 +198,9 @@ StrictMock<MockSessionNotifier> notifier_; }; -INSTANTIATE_TEST_CASE_P(Tests, QuicUnackedPacketMapTest, testing::Bool()); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicUnackedPacketMapTest, + ::testing::ValuesIn(GetTestParams())); TEST_P(QuicUnackedPacketMapTest, RttOnly) { // Acks are only tracked for RTT measurement purposes.
diff --git a/quic/core/quic_utils.cc b/quic/core/quic_utils.cc index be6eeea..0801f41 100644 --- a/quic/core/quic_utils.cc +++ b/quic/core/quic_utils.cc
@@ -143,7 +143,7 @@ const char* QuicUtils::EncryptionLevelToString(EncryptionLevel level) { switch (level) { RETURN_STRING_LITERAL(ENCRYPTION_NONE); - RETURN_STRING_LITERAL(ENCRYPTION_INITIAL); + RETURN_STRING_LITERAL(ENCRYPTION_ZERO_RTT); RETURN_STRING_LITERAL(ENCRYPTION_FORWARD_SECURE); RETURN_STRING_LITERAL(NUM_ENCRYPTION_LEVELS); } @@ -290,6 +290,13 @@ } // static +struct iovec QuicUtils::MakeIovec(QuicStringPiece data) { + struct iovec iov = {const_cast<char*>(data.data()), + static_cast<size_t>(data.size())}; + return iov; +} + +// static bool QuicUtils::IsAckable(SentPacketState state) { return state != NEVER_SENT && state != ACKED && state != UNACKABLE; } @@ -308,6 +315,17 @@ } // static +bool QuicUtils::IsHandshakeFrame(const QuicFrame& frame, + QuicTransportVersion transport_version) { + if (transport_version < QUIC_VERSION_47) { + return frame.type == STREAM_FRAME && + frame.stream_frame.stream_id == GetCryptoStreamId(transport_version); + } else { + return frame.type == CRYPTO_FRAME; + } +} + +// static SentPacketState QuicUtils::RetransmissionTypeToPacketState( TransmissionType retransmission_type) { switch (retransmission_type) { @@ -347,11 +365,14 @@ // static QuicStreamId QuicUtils::GetInvalidStreamId(QuicTransportVersion version) { - return version == QUIC_VERSION_99 ? -1 : 0; + return version == QUIC_VERSION_99 ? std::numeric_limits<QuicStreamId>::max() + : 0; } // static QuicStreamId QuicUtils::GetCryptoStreamId(QuicTransportVersion version) { + // TODO(nharper): Change this to return GetInvalidStreamId for version 47 or + // greater. Currently, too many things break with that change. return version == QUIC_VERSION_99 ? 0 : 1; } @@ -384,11 +405,30 @@ } // static -StreamType QuicUtils::GetStreamType(QuicStreamId id, bool peer_initiated) { +StreamType QuicUtils::GetStreamType(QuicStreamId id, + Perspective perspective, + bool peer_initiated) { if (IsBidirectionalStreamId(id)) { return BIDIRECTIONAL; } - return peer_initiated ? READ_UNIDIRECTIONAL : WRITE_UNIDIRECTIONAL; + + if (peer_initiated) { + if (perspective == Perspective::IS_SERVER) { + DCHECK_EQ(2, id % 4); + } else { + DCHECK_EQ(Perspective::IS_CLIENT, perspective); + DCHECK_EQ(3, id % 4); + } + return READ_UNIDIRECTIONAL; + } + + if (perspective == Perspective::IS_SERVER) { + DCHECK_EQ(3, id % 4); + } else { + DCHECK_EQ(Perspective::IS_CLIENT, perspective); + DCHECK_EQ(2, id % 4); + } + return WRITE_UNIDIRECTIONAL; } // static @@ -422,21 +462,7 @@ } // static -QuicConnectionId QuicUtils::CreateRandomConnectionId(Perspective perspective) { - return CreateRandomConnectionId(QuicRandom::GetInstance(), perspective); -} - -// static QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random) { - return CreateRandomConnectionId(random, Perspective::IS_SERVER); -} - -// static -QuicConnectionId QuicUtils::CreateRandomConnectionId(QuicRandom* random, - Perspective perspective) { - if (!QuicConnectionIdSupportsVariableLength(perspective)) { - return QuicConnectionIdFromUInt64(random->RandUint64()); - } char connection_id_bytes[kQuicDefaultConnectionIdLength]; random->RandBytes(connection_id_bytes, QUIC_ARRAYSIZE(connection_id_bytes)); return QuicConnectionId(static_cast<char*>(connection_id_bytes), @@ -453,10 +479,6 @@ // static QuicConnectionId QuicUtils::CreateZeroConnectionId( QuicTransportVersion version) { - if (!QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER) || - !QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT)) { - return QuicConnectionIdFromUInt64(0); - } if (!VariableLengthConnectionIdAllowedForVersion(version)) { char connection_id_bytes[8] = {0, 0, 0, 0, 0, 0, 0, 0}; return QuicConnectionId(static_cast<char*>(connection_id_bytes), @@ -476,9 +498,6 @@ QuicUint128 QuicUtils::GenerateStatelessResetToken( QuicConnectionId connection_id) { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return QuicConnectionIdToUInt64(connection_id); - } uint64_t data_bytes[3] = {0, 0, 0}; static_assert(sizeof(data_bytes) >= kQuicMaxConnectionIdLength, "kQuicMaxConnectionIdLength changed");
diff --git a/quic/core/quic_utils.h b/quic/core/quic_utils.h index 111080a..28ea15b 100644 --- a/quic/core/quic_utils.h +++ b/quic/core/quic_utils.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/frames/quic_frame.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_versions.h" @@ -79,6 +80,9 @@ size_t buffer_length, char* buffer); + // Creates an iovec pointing to the same data as |data|. + static struct iovec MakeIovec(QuicStringPiece data); + // Returns true if a packet is ackable. A packet is unackable if it can never // be acked. Occurs when a packet is never sent, after it is acknowledged // once, or if it's a crypto packet we never expect to receive an ack for. @@ -88,6 +92,10 @@ // frame should be retransmitted if it is detected as lost. static bool IsRetransmittableFrame(QuicFrameType type); + // Returns true if |frame| is a handshake frame in version |version|. + static bool IsHandshakeFrame(const QuicFrame& frame, + QuicTransportVersion transport_version); + // Returns packet state corresponding to |retransmission_type|. static SentPacketState RetransmissionTypeToPacketState( TransmissionType retransmission_type); @@ -121,9 +129,12 @@ // v99. static bool IsBidirectionalStreamId(QuicStreamId id); - // Returns stream type according to |id| and |peer_initiated|. Only used in - // v99. - static StreamType GetStreamType(QuicStreamId id, bool peer_initiated); + // Returns stream type. Either |perspective| or |peer_initiated| would be + // enough together with |id|. This method enforces that the three parameters + // are consistent. Only used in v99. + static StreamType GetStreamType(QuicStreamId id, + Perspective perspective, + bool peer_initiated); // Returns the delta between consecutive stream IDs of the same type. static QuicStreamId StreamIdDelta(QuicTransportVersion version); @@ -141,16 +152,9 @@ // Generates a random 64bit connection ID. static QuicConnectionId CreateRandomConnectionId(); - // Generates a random 64bit connection ID. - static QuicConnectionId CreateRandomConnectionId(Perspective perspective); - // Generates a random 64bit connection ID using the provided QuicRandom. static QuicConnectionId CreateRandomConnectionId(QuicRandom* random); - // Generates a random 64bit connection ID using the provided QuicRandom. - static QuicConnectionId CreateRandomConnectionId(QuicRandom* random, - Perspective perspective); - // Returns true if the QUIC version allows variable length connection IDs. static bool VariableLengthConnectionIdAllowedForVersion( QuicTransportVersion version);
diff --git a/quic/core/quic_utils_test.cc b/quic/core/quic_utils_test.cc index d1b5268..de4c76b 100644 --- a/quic/core/quic_utils_test.cc +++ b/quic/core/quic_utils_test.cc
@@ -168,16 +168,11 @@ MockRandom random(33); QuicConnectionId connection_id = QuicUtils::CreateRandomConnectionId(&random); EXPECT_EQ(connection_id.length(), sizeof(uint64_t)); - if (!QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_SERVER) || - !QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_CLIENT)) { - EXPECT_EQ(connection_id, QuicConnectionIdFromUInt64(random.RandUint64())); - } else { char connection_id_bytes[sizeof(uint64_t)]; random.RandBytes(connection_id_bytes, QUIC_ARRAYSIZE(connection_id_bytes)); EXPECT_EQ(connection_id, QuicConnectionId(static_cast<char*>(connection_id_bytes), QUIC_ARRAYSIZE(connection_id_bytes))); - } EXPECT_NE(connection_id, EmptyQuicConnectionId()); EXPECT_NE(connection_id, TestConnectionId()); EXPECT_NE(connection_id, TestConnectionId(1)); @@ -185,19 +180,15 @@ TEST_F(QuicUtilsTest, VariableLengthConnectionId) { EXPECT_FALSE( - QuicUtils::VariableLengthConnectionIdAllowedForVersion(QUIC_VERSION_35)); + QuicUtils::VariableLengthConnectionIdAllowedForVersion(QUIC_VERSION_39)); EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion( - QuicUtils::CreateZeroConnectionId(QUIC_VERSION_35), QUIC_VERSION_35)); + QuicUtils::CreateZeroConnectionId(QUIC_VERSION_39), QUIC_VERSION_39)); EXPECT_TRUE(QuicUtils::IsConnectionIdValidForVersion( QuicUtils::CreateZeroConnectionId(QUIC_VERSION_99), QUIC_VERSION_99)); - if (!QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_SERVER) || - !QuicConnectionIdSupportsVariableLength(quic::Perspective::IS_CLIENT)) { - return; - } - EXPECT_NE(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_35), + EXPECT_NE(QuicUtils::CreateZeroConnectionId(QUIC_VERSION_39), EmptyQuicConnectionId()); EXPECT_FALSE(QuicUtils::IsConnectionIdValidForVersion(EmptyQuicConnectionId(), - QUIC_VERSION_35)); + QUIC_VERSION_39)); } TEST_F(QuicUtilsTest, StatelessResetToken) {
diff --git a/quic/core/quic_version_manager.cc b/quic/core/quic_version_manager.cc index 064e932..62b2e44 100644 --- a/quic/core/quic_version_manager.cc +++ b/quic/core/quic_version_manager.cc
@@ -17,10 +17,9 @@ : enable_version_99_(GetQuicReloadableFlag(quic_enable_version_99)), enable_version_47_(GetQuicReloadableFlag(quic_enable_version_47)), enable_version_46_(GetQuicReloadableFlag(quic_enable_version_46)), - enable_version_45_(GetQuicReloadableFlag(quic_enable_version_45)), enable_version_44_(GetQuicReloadableFlag(quic_enable_version_44)), enable_version_43_(GetQuicReloadableFlag(quic_enable_version_43)), - disable_version_35_(GetQuicReloadableFlag(quic_disable_version_35)), + disable_version_39_(GetQuicReloadableFlag(quic_disable_version_39)), allowed_supported_versions_(std::move(supported_versions)) { RefilterSupportedVersions(); } @@ -42,17 +41,15 @@ if (enable_version_99_ != GetQuicReloadableFlag(quic_enable_version_99) || enable_version_47_ != GetQuicReloadableFlag(quic_enable_version_47) || enable_version_46_ != GetQuicReloadableFlag(quic_enable_version_46) || - enable_version_45_ != GetQuicReloadableFlag(quic_enable_version_45) || enable_version_44_ != GetQuicReloadableFlag(quic_enable_version_44) || enable_version_43_ != GetQuicReloadableFlag(quic_enable_version_43) || - disable_version_35_ != GetQuicReloadableFlag(quic_disable_version_35)) { + disable_version_39_ != GetQuicReloadableFlag(quic_disable_version_39)) { enable_version_99_ = GetQuicReloadableFlag(quic_enable_version_99); enable_version_47_ = GetQuicReloadableFlag(quic_enable_version_47); enable_version_46_ = GetQuicReloadableFlag(quic_enable_version_46); - enable_version_45_ = GetQuicReloadableFlag(quic_enable_version_45); enable_version_44_ = GetQuicReloadableFlag(quic_enable_version_44); enable_version_43_ = GetQuicReloadableFlag(quic_enable_version_43); - disable_version_35_ = GetQuicReloadableFlag(quic_disable_version_35); + disable_version_39_ = GetQuicReloadableFlag(quic_disable_version_39); RefilterSupportedVersions(); } }
diff --git a/quic/core/quic_version_manager.h b/quic/core/quic_version_manager.h index 1196c31..ab06868 100644 --- a/quic/core/quic_version_manager.h +++ b/quic/core/quic_version_manager.h
@@ -41,14 +41,12 @@ bool enable_version_47_; // quic_enable_version_46 flag bool enable_version_46_; - // quic_enable_version_45 flag - bool enable_version_45_; // quic_enable_version_44 flag bool enable_version_44_; // quic_enable_version_43 flag bool enable_version_43_; - // quic_disable_version_35 flag - bool disable_version_35_; + // quic_disable_version_39 flag + bool disable_version_39_; // The list of versions that may be supported. ParsedQuicVersionVector allowed_supported_versions_; // This vector contains QUIC versions which are currently supported based on
diff --git a/quic/core/quic_version_manager_test.cc b/quic/core/quic_version_manager_test.cc index b734b89..7c7a08d 100644 --- a/quic/core/quic_version_manager_test.cc +++ b/quic/core/quic_version_manager_test.cc
@@ -16,62 +16,50 @@ class QuicVersionManagerTest : public QuicTest {}; TEST_F(QuicVersionManagerTest, QuicVersionManager) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); SetQuicReloadableFlag(quic_enable_version_99, false); SetQuicReloadableFlag(quic_enable_version_47, false); SetQuicReloadableFlag(quic_enable_version_46, false); - SetQuicReloadableFlag(quic_enable_version_45, false); SetQuicReloadableFlag(quic_enable_version_44, false); SetQuicReloadableFlag(quic_enable_version_43, false); - SetQuicReloadableFlag(quic_disable_version_35, true); + SetQuicReloadableFlag(quic_disable_version_39, true); QuicVersionManager manager(AllSupportedVersions()); EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()), manager.GetSupportedTransportVersions()); + EXPECT_TRUE(manager.GetSupportedTransportVersions().empty()); + + SetQuicReloadableFlag(quic_disable_version_39, false); EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_39}), manager.GetSupportedTransportVersions()); - SetQuicReloadableFlag(quic_disable_version_35, false); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_39, QUIC_VERSION_35}), - manager.GetSupportedTransportVersions()); - SetQuicReloadableFlag(quic_enable_version_43, true); - EXPECT_EQ(QuicTransportVersionVector( - {QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}), + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_43, QUIC_VERSION_39}), manager.GetSupportedTransportVersions()); SetQuicReloadableFlag(quic_enable_version_44, true); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_44, QUIC_VERSION_43, - QUIC_VERSION_39, QUIC_VERSION_35}), - manager.GetSupportedTransportVersions()); - - SetQuicReloadableFlag(quic_enable_version_45, true); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_45, QUIC_VERSION_44, - QUIC_VERSION_43, QUIC_VERSION_39, - QUIC_VERSION_35}), + EXPECT_EQ(QuicTransportVersionVector( + {QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39}), manager.GetSupportedTransportVersions()); SetQuicReloadableFlag(quic_enable_version_46, true); - EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_46, QUIC_VERSION_45, - QUIC_VERSION_44, QUIC_VERSION_43, - QUIC_VERSION_39, QUIC_VERSION_35}), + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_46, QUIC_VERSION_44, + QUIC_VERSION_43, QUIC_VERSION_39}), manager.GetSupportedTransportVersions()); SetQuicReloadableFlag(quic_enable_version_47, true); - EXPECT_EQ( - QuicTransportVersionVector( - {QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44, - QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}), - manager.GetSupportedTransportVersions()); + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_47, QUIC_VERSION_46, + QUIC_VERSION_44, QUIC_VERSION_43, + QUIC_VERSION_39}), + manager.GetSupportedTransportVersions()); SetQuicReloadableFlag(quic_enable_version_99, true); - EXPECT_EQ( - QuicTransportVersionVector( - {QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, - QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}), - manager.GetSupportedTransportVersions()); + EXPECT_EQ(QuicTransportVersionVector({QUIC_VERSION_99, QUIC_VERSION_47, + QUIC_VERSION_46, QUIC_VERSION_44, + QUIC_VERSION_43, QUIC_VERSION_39}), + manager.GetSupportedTransportVersions()); // Ensure that all versions are now supported. EXPECT_EQ(FilterSupportedTransportVersions(AllSupportedTransportVersions()),
diff --git a/quic/core/quic_versions.cc b/quic/core/quic_versions.cc index 6f050dd..efc823d 100644 --- a/quic/core/quic_versions.cc +++ b/quic/core/quic_versions.cc
@@ -54,16 +54,12 @@ return 0; } switch (parsed_version.transport_version) { - case QUIC_VERSION_35: - return MakeVersionLabel(proto, '0', '3', '5'); case QUIC_VERSION_39: return MakeVersionLabel(proto, '0', '3', '9'); case QUIC_VERSION_43: return MakeVersionLabel(proto, '0', '4', '3'); case QUIC_VERSION_44: return MakeVersionLabel(proto, '0', '4', '4'); - case QUIC_VERSION_45: - return MakeVersionLabel(proto, '0', '4', '5'); case QUIC_VERSION_46: return MakeVersionLabel(proto, '0', '4', '6'); case QUIC_VERSION_47: @@ -123,6 +119,11 @@ continue; } for (QuicTransportVersion version : kSupportedTransportVersions) { + if (protocol == PROTOCOL_TLS1_3 && version < QUIC_VERSION_47) { + // The TLS handshake is only deployable if CRYPTO frames are also used, + // which are added in v47. + continue; + } supported_versions.push_back(ParsedQuicVersion(protocol, version)); } } @@ -163,7 +164,6 @@ if (GetQuicReloadableFlag(quic_enable_version_99) && GetQuicReloadableFlag(quic_enable_version_47) && GetQuicReloadableFlag(quic_enable_version_46) && - GetQuicReloadableFlag(quic_enable_version_45) && GetQuicReloadableFlag(quic_enable_version_44) && GetQuicReloadableFlag(quic_enable_version_43)) { filtered_versions.push_back(version); @@ -171,20 +171,12 @@ } else if (version.transport_version == QUIC_VERSION_47) { if (GetQuicReloadableFlag(quic_enable_version_47) && GetQuicReloadableFlag(quic_enable_version_46) && - GetQuicReloadableFlag(quic_enable_version_45) && GetQuicReloadableFlag(quic_enable_version_44) && GetQuicReloadableFlag(quic_enable_version_43)) { filtered_versions.push_back(version); } } else if (version.transport_version == QUIC_VERSION_46) { if (GetQuicReloadableFlag(quic_enable_version_46) && - GetQuicReloadableFlag(quic_enable_version_45) && - GetQuicReloadableFlag(quic_enable_version_44) && - GetQuicReloadableFlag(quic_enable_version_43)) { - filtered_versions.push_back(version); - } - } else if (version.transport_version == QUIC_VERSION_45) { - if (GetQuicReloadableFlag(quic_enable_version_45) && GetQuicReloadableFlag(quic_enable_version_44) && GetQuicReloadableFlag(quic_enable_version_43)) { filtered_versions.push_back(version); @@ -198,8 +190,8 @@ if (GetQuicReloadableFlag(quic_enable_version_43)) { filtered_versions.push_back(version); } - } else if (version.transport_version == QUIC_VERSION_35) { - if (!GetQuicReloadableFlag(quic_disable_version_35)) { + } else if (version.transport_version == QUIC_VERSION_39) { + if (!GetQuicReloadableFlag(quic_disable_version_39)) { filtered_versions.push_back(version); } } else { @@ -290,11 +282,9 @@ QuicString QuicVersionToString(QuicTransportVersion transport_version) { switch (transport_version) { - RETURN_STRING_LITERAL(QUIC_VERSION_35); RETURN_STRING_LITERAL(QUIC_VERSION_39); RETURN_STRING_LITERAL(QUIC_VERSION_43); RETURN_STRING_LITERAL(QUIC_VERSION_44); - RETURN_STRING_LITERAL(QUIC_VERSION_45); RETURN_STRING_LITERAL(QUIC_VERSION_46); RETURN_STRING_LITERAL(QUIC_VERSION_47); RETURN_STRING_LITERAL(QUIC_VERSION_99);
diff --git a/quic/core/quic_versions.h b/quic/core/quic_versions.h index 2c3ba1f..c0fa34a 100644 --- a/quic/core/quic_versions.h +++ b/quic/core/quic_versions.h
@@ -76,9 +76,7 @@ // private flag from packet header and changed the ACK format to // specify ranges of packets acknowledged rather than missing // ranges. - - QUIC_VERSION_35 = 35, // Allows endpoints to independently set stream limit. - + // Version 35 allows endpoints to independently set stream limit. // Version 36 added support for forced head-of-line blocking experiments. // Version 37 added perspective into null encryption. // Version 38 switched to IETF padding frame format and support for NSTP (no @@ -100,10 +98,12 @@ QUIC_VERSION_43 = 43, // PRIORITY frames are sent by client and accepted by // server. QUIC_VERSION_44 = 44, // Use IETF header format. - QUIC_VERSION_45 = 45, // Added MESSAGE frame. - QUIC_VERSION_46 = 46, // Use CRYPTO frames for QuicCryptoStreams. - QUIC_VERSION_47 = 47, // Use IETF draft-17 header format with demultiplexing + + // Version 45 added MESSAGE frame. + + QUIC_VERSION_46 = 46, // Use IETF draft-17 header format with demultiplexing // bit. + QUIC_VERSION_47 = 47, // Use CRYPTO frames for QuicCryptoStreams. QUIC_VERSION_99 = 99, // Dumping ground for IETF QUIC changes which are not // yet ready for production. }; @@ -166,8 +166,9 @@ // // See go/new-quic-version for more details on how to roll out new versions. static const QuicTransportVersion kSupportedTransportVersions[] = { - QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, - QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}; + QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, + QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, +}; // This vector contains all crypto handshake protocols that are supported. static const HandshakeProtocol kSupportedHandshakeProtocols[] = { @@ -308,6 +309,38 @@ std::numeric_limits<size_t>::max()); } +// Returns true if QuicSpdyStream encodes body using HTTP/3 specification and +// sends data frame header along with body. +QUIC_EXPORT_PRIVATE inline bool VersionHasDataFrameHeader( + QuicTransportVersion transport_version) { + return transport_version == QUIC_VERSION_99; +} + +// Returns true if QuicSpdySession instantiates a QPACK encoder and decoder. +// TODO(123528590): Implement the following features and gate them on this +// function as well, optionally renaming this function as appropriate. +// Send HEADERS on the request/response stream instead of the headers stream. +// Send PUSH_PROMISE on the request/response stream instead of headers stream. +// Send PRIORITY on the request/response stream instead of the headers stream. +// Do not instantiate the headers stream object. +QUIC_EXPORT_PRIVATE inline bool VersionUsesQpack( + QuicTransportVersion transport_version) { + const bool uses_qpack = (transport_version == QUIC_VERSION_99); + if (uses_qpack) { + DCHECK(VersionHasDataFrameHeader(transport_version)); + } + return uses_qpack; +} + +// Returns whether the transport_version supports the variable length integer +// length field as defined by IETF QUIC draft-13 and later. +QUIC_EXPORT_PRIVATE inline bool QuicVersionHasLongHeaderLengths( + QuicTransportVersion transport_version) { + // TODO(dschinazi) if we enable long header lengths before v99, we need to + // add support for fixing up lengths in QuicFramer::BuildDataPacket. + return transport_version == QUIC_VERSION_99; +} + } // namespace quic #endif // QUICHE_QUIC_CORE_QUIC_VERSIONS_H_
diff --git a/quic/core/quic_versions_test.cc b/quic/core/quic_versions_test.cc index a0f664e..db7f53a 100644 --- a/quic/core/quic_versions_test.cc +++ b/quic/core/quic_versions_test.cc
@@ -34,8 +34,8 @@ log.StartCapturingLogs(); // Explicitly test a specific version. - EXPECT_EQ(MakeQuicTag('5', '3', '0', 'Q'), - QuicVersionToQuicVersionLabel(QUIC_VERSION_35)); + EXPECT_EQ(MakeQuicTag('9', '3', '0', 'Q'), + QuicVersionToQuicVersionLabel(QUIC_VERSION_39)); // Loop over all supported versions and make sure that we never hit the // default case (i.e. all supported versions should be successfully converted @@ -72,8 +72,8 @@ log.StartCapturingLogs(); // Explicitly test specific versions. - EXPECT_EQ(QUIC_VERSION_35, - QuicVersionLabelToQuicVersion(MakeQuicTag('5', '3', '0', 'Q'))); + EXPECT_EQ(QUIC_VERSION_39, + QuicVersionLabelToQuicVersion(MakeQuicTag('9', '3', '0', 'Q'))); for (size_t i = 0; i < QUIC_ARRAYSIZE(kSupportedTransportVersions); ++i) { QuicTransportVersion version = kSupportedTransportVersions[i]; @@ -130,16 +130,12 @@ } TEST_F(QuicVersionsTest, ParseQuicVersionLabel) { - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35), - ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '3', '5'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '3', '9'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '3'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '4'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45), - ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '5'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46), ParseQuicVersionLabel(MakeVersionLabel('Q', '0', '4', '6'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_47), @@ -147,16 +143,12 @@ // Test a TLS version: FLAGS_quic_supports_tls_handshake = true; - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_35), - ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '5'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '3', '9'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_43), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '3'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4'))); - EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45), - ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6'))); EXPECT_EQ(ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_47), @@ -180,9 +172,6 @@ } TEST_F(QuicVersionsTest, CreateQuicVersionLabel) { - EXPECT_EQ(MakeVersionLabel('Q', '0', '3', '5'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35))); EXPECT_EQ(MakeVersionLabel('Q', '0', '3', '9'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39))); @@ -192,9 +181,6 @@ EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '4'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44))); - EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '5'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45))); EXPECT_EQ(MakeVersionLabel('Q', '0', '4', '6'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46))); @@ -204,9 +190,6 @@ // Test a TLS version: FLAGS_quic_supports_tls_handshake = true; - EXPECT_EQ(MakeVersionLabel('T', '0', '3', '5'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_35))); EXPECT_EQ(MakeVersionLabel('T', '0', '3', '9'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_39))); @@ -216,9 +199,6 @@ EXPECT_EQ(MakeVersionLabel('T', '0', '4', '4'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_44))); - EXPECT_EQ(MakeVersionLabel('T', '0', '4', '5'), - CreateQuicVersionLabel( - ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_45))); EXPECT_EQ(MakeVersionLabel('T', '0', '4', '6'), CreateQuicVersionLabel( ParsedQuicVersion(PROTOCOL_TLS1_3, QUIC_VERSION_46))); @@ -236,8 +216,6 @@ EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '4'))); EXPECT_EQ(UnsupportedQuicVersion(), - ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '5'))); - EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '6'))); EXPECT_EQ(UnsupportedQuicVersion(), ParseQuicVersionLabel(MakeVersionLabel('T', '0', '4', '7'))); @@ -261,25 +239,25 @@ } TEST_F(QuicVersionsTest, QuicVersionToString) { - EXPECT_EQ("QUIC_VERSION_35", QuicVersionToString(QUIC_VERSION_35)); + EXPECT_EQ("QUIC_VERSION_39", QuicVersionToString(QUIC_VERSION_39)); EXPECT_EQ("QUIC_VERSION_UNSUPPORTED", QuicVersionToString(QUIC_VERSION_UNSUPPORTED)); - QuicTransportVersion single_version[] = {QUIC_VERSION_35}; + QuicTransportVersion single_version[] = {QUIC_VERSION_39}; QuicTransportVersionVector versions_vector; for (size_t i = 0; i < QUIC_ARRAYSIZE(single_version); ++i) { versions_vector.push_back(single_version[i]); } - EXPECT_EQ("QUIC_VERSION_35", + EXPECT_EQ("QUIC_VERSION_39", QuicTransportVersionVectorToString(versions_vector)); QuicTransportVersion multiple_versions[] = {QUIC_VERSION_UNSUPPORTED, - QUIC_VERSION_35}; + QUIC_VERSION_39}; versions_vector.clear(); for (size_t i = 0; i < QUIC_ARRAYSIZE(multiple_versions); ++i) { versions_vector.push_back(multiple_versions[i]); } - EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_35", + EXPECT_EQ("QUIC_VERSION_UNSUPPORTED,QUIC_VERSION_39", QuicTransportVersionVectorToString(versions_vector)); // Make sure that all supported versions are present in QuicVersionToString. @@ -291,16 +269,16 @@ TEST_F(QuicVersionsTest, ParsedQuicVersionToString) { ParsedQuicVersion unsupported = UnsupportedQuicVersion(); - ParsedQuicVersion version35(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35); - EXPECT_EQ("Q035", ParsedQuicVersionToString(version35)); + ParsedQuicVersion version39(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_39); + EXPECT_EQ("Q039", ParsedQuicVersionToString(version39)); EXPECT_EQ("0", ParsedQuicVersionToString(unsupported)); - ParsedQuicVersionVector versions_vector = {version35}; - EXPECT_EQ("Q035", ParsedQuicVersionVectorToString(versions_vector)); + ParsedQuicVersionVector versions_vector = {version39}; + EXPECT_EQ("Q039", ParsedQuicVersionVectorToString(versions_vector)); - versions_vector = {unsupported, version35}; - EXPECT_EQ("0,Q035", ParsedQuicVersionVectorToString(versions_vector)); - EXPECT_EQ("0:Q035", ParsedQuicVersionVectorToString(versions_vector, ":", + versions_vector = {unsupported, version39}; + EXPECT_EQ("0,Q039", ParsedQuicVersionVectorToString(versions_vector)); + EXPECT_EQ("0:Q039", ParsedQuicVersionVectorToString(versions_vector, ":", versions_vector.size())); EXPECT_EQ("0|...", ParsedQuicVersionVectorToString(versions_vector, "|", 0)); @@ -324,10 +302,9 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsAllVersions) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, false); + SetQuicReloadableFlag(quic_disable_version_39, false); SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); - SetQuicReloadableFlag(quic_enable_version_45, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, true); SetQuicReloadableFlag(quic_enable_version_99, true); @@ -336,8 +313,8 @@ parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, - QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}; + QUIC_VERSION_99, QUIC_VERSION_47, QUIC_VERSION_46, + QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -350,10 +327,9 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo99) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, false); + SetQuicReloadableFlag(quic_disable_version_39, false); SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); - SetQuicReloadableFlag(quic_enable_version_45, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, true); SetQuicReloadableFlag(quic_enable_version_99, false); @@ -362,8 +338,8 @@ parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44, - QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}; + QUIC_VERSION_47, QUIC_VERSION_46, QUIC_VERSION_44, QUIC_VERSION_43, + QUIC_VERSION_39}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -376,10 +352,9 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo47) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, false); + SetQuicReloadableFlag(quic_disable_version_39, false); SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); - SetQuicReloadableFlag(quic_enable_version_45, true); SetQuicReloadableFlag(quic_enable_version_46, true); SetQuicReloadableFlag(quic_enable_version_47, false); SetQuicReloadableFlag(quic_enable_version_99, false); @@ -388,8 +363,7 @@ parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_46, QUIC_VERSION_45, QUIC_VERSION_44, - QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}; + QUIC_VERSION_46, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -402,10 +376,9 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo46) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, false); + SetQuicReloadableFlag(quic_disable_version_39, false); SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, true); - SetQuicReloadableFlag(quic_enable_version_45, true); SetQuicReloadableFlag(quic_enable_version_46, false); SetQuicReloadableFlag(quic_enable_version_47, false); SetQuicReloadableFlag(quic_enable_version_99, false); @@ -414,33 +387,7 @@ parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } QuicTransportVersionVector expected_versions = { - QUIC_VERSION_45, QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, - QUIC_VERSION_35}; - ParsedQuicVersionVector expected_parsed_versions; - for (QuicTransportVersion version : expected_versions) { - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - - ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions)); - ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); -} - -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo45) { - QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, false); - SetQuicReloadableFlag(quic_enable_version_43, true); - SetQuicReloadableFlag(quic_enable_version_44, true); - SetQuicReloadableFlag(quic_enable_version_45, false); - SetQuicReloadableFlag(quic_enable_version_46, false); - SetQuicReloadableFlag(quic_enable_version_47, false); - SetQuicReloadableFlag(quic_enable_version_99, false); - ParsedQuicVersionVector parsed_versions; - for (QuicTransportVersion version : all_versions) { - parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - QuicTransportVersionVector expected_versions = { - QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}; + QUIC_VERSION_44, QUIC_VERSION_43, QUIC_VERSION_39}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -453,10 +400,9 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo44) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, false); + SetQuicReloadableFlag(quic_disable_version_39, false); SetQuicReloadableFlag(quic_enable_version_43, true); SetQuicReloadableFlag(quic_enable_version_44, false); - SetQuicReloadableFlag(quic_enable_version_45, false); SetQuicReloadableFlag(quic_enable_version_46, false); SetQuicReloadableFlag(quic_enable_version_47, false); SetQuicReloadableFlag(quic_enable_version_99, false); @@ -464,8 +410,8 @@ for (QuicTransportVersion version : all_versions) { parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); } - QuicTransportVersionVector expected_versions = { - QUIC_VERSION_43, QUIC_VERSION_39, QUIC_VERSION_35}; + QuicTransportVersionVector expected_versions = {QUIC_VERSION_43, + QUIC_VERSION_39}; ParsedQuicVersionVector expected_parsed_versions; for (QuicTransportVersion version : expected_versions) { expected_parsed_versions.push_back( @@ -478,35 +424,9 @@ TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo43) { QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, false); + SetQuicReloadableFlag(quic_disable_version_39, false); SetQuicReloadableFlag(quic_enable_version_43, false); SetQuicReloadableFlag(quic_enable_version_44, false); - SetQuicReloadableFlag(quic_enable_version_45, false); - SetQuicReloadableFlag(quic_enable_version_46, false); - SetQuicReloadableFlag(quic_enable_version_47, false); - SetQuicReloadableFlag(quic_enable_version_99, false); - ParsedQuicVersionVector parsed_versions; - for (QuicTransportVersion version : all_versions) { - parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - QuicTransportVersionVector expected_versions = {QUIC_VERSION_39, - QUIC_VERSION_35}; - ParsedQuicVersionVector expected_parsed_versions; - for (QuicTransportVersion version : expected_versions) { - expected_parsed_versions.push_back( - ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); - } - - ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions)); - ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); -} - -TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo35) { - QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); - SetQuicReloadableFlag(quic_disable_version_35, true); - SetQuicReloadableFlag(quic_enable_version_43, false); - SetQuicReloadableFlag(quic_enable_version_44, false); - SetQuicReloadableFlag(quic_enable_version_45, false); SetQuicReloadableFlag(quic_enable_version_46, false); SetQuicReloadableFlag(quic_enable_version_47, false); SetQuicReloadableFlag(quic_enable_version_99, false); @@ -525,8 +445,31 @@ ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); } +TEST_F(QuicVersionsTest, FilterSupportedTransportVersionsNo39) { + QuicTransportVersionVector all_versions = AllSupportedTransportVersions(); + SetQuicReloadableFlag(quic_disable_version_39, true); + SetQuicReloadableFlag(quic_enable_version_43, true); + SetQuicReloadableFlag(quic_enable_version_44, false); + SetQuicReloadableFlag(quic_enable_version_46, false); + SetQuicReloadableFlag(quic_enable_version_47, false); + SetQuicReloadableFlag(quic_enable_version_99, false); + ParsedQuicVersionVector parsed_versions; + for (QuicTransportVersion version : all_versions) { + parsed_versions.push_back(ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); + } + QuicTransportVersionVector expected_versions = {QUIC_VERSION_43}; + ParsedQuicVersionVector expected_parsed_versions; + for (QuicTransportVersion version : expected_versions) { + expected_parsed_versions.push_back( + ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, version)); + } + + ASSERT_EQ(expected_versions, FilterSupportedTransportVersions(all_versions)); + ASSERT_EQ(expected_parsed_versions, FilterSupportedVersions(parsed_versions)); +} + TEST_F(QuicVersionsTest, LookUpVersionByIndex) { - QuicTransportVersionVector all_versions = {QUIC_VERSION_35, QUIC_VERSION_39}; + QuicTransportVersionVector all_versions = {QUIC_VERSION_39}; int version_count = all_versions.size(); for (int i = -5; i <= version_count + 1; ++i) { if (i >= 0 && i < version_count) { @@ -564,13 +507,11 @@ // yet a typo was made in doing the #defines and it was caught // only in some test far removed from here... Better safe than sorry. TEST_F(QuicVersionsTest, CheckVersionNumbersForTypos) { - static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 8u, + static_assert(QUIC_ARRAYSIZE(kSupportedTransportVersions) == 6u, "Supported versions out of sync"); - EXPECT_EQ(QUIC_VERSION_35, 35); EXPECT_EQ(QUIC_VERSION_39, 39); EXPECT_EQ(QUIC_VERSION_43, 43); EXPECT_EQ(QUIC_VERSION_44, 44); - EXPECT_EQ(QUIC_VERSION_45, 45); EXPECT_EQ(QUIC_VERSION_46, 46); EXPECT_EQ(QUIC_VERSION_47, 47); EXPECT_EQ(QUIC_VERSION_99, 99);
diff --git a/quic/core/stateless_rejector_test.cc b/quic/core/stateless_rejector_test.cc index 497fe54..19eef64 100644 --- a/quic/core/stateless_rejector_test.cc +++ b/quic/core/stateless_rejector_test.cc
@@ -169,10 +169,9 @@ QuicString stk_hex_; }; -INSTANTIATE_TEST_CASE_P(Flags, - StatelessRejectorTest, - ::testing::ValuesIn(GetTestParams()), - TestParamToString); +INSTANTIATE_TEST_SUITE_P(Flags, StatelessRejectorTest, + ::testing::ValuesIn(GetTestParams()), + TestParamToString); TEST_P(StatelessRejectorTest, InvalidChlo) { // clang-format off
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc index a471aa4..e2efa0f 100644 --- a/quic/core/tls_handshaker.cc +++ b/quic/core/tls_handshaker.cc
@@ -108,7 +108,7 @@ return ENCRYPTION_NONE; case ssl_encryption_early_data: case ssl_encryption_handshake: - return ENCRYPTION_INITIAL; + return ENCRYPTION_ZERO_RTT; case ssl_encryption_application: return ENCRYPTION_FORWARD_SECURE; } @@ -120,7 +120,7 @@ switch (level) { case ENCRYPTION_NONE: return ssl_encryption_initial; - case ENCRYPTION_INITIAL: + case ENCRYPTION_ZERO_RTT: return ssl_encryption_handshake; case ENCRYPTION_FORWARD_SECURE: return ssl_encryption_application; @@ -214,7 +214,7 @@ // alternative decrypter instead of the primary decrypter. One reason for // this is that after the forward secure keys become available, the server // still has crypto handshake messages to read at the handshake encryption - // level, meaning that both the ENCRYPTION_INITIAL and + // level, meaning that both the ENCRYPTION_ZERO_RTT and // ENCRYPTION_FORWARD_SECURE decrypters need to be available. (Tests also // assume that an alternative decrypter gets set, so at some point we need // to call SetAlternativeDecrypter.)
diff --git a/quic/core/uber_quic_stream_id_manager_test.cc b/quic/core/uber_quic_stream_id_manager_test.cc index a413a0b..353e35d 100644 --- a/quic/core/uber_quic_stream_id_manager_test.cc +++ b/quic/core/uber_quic_stream_id_manager_test.cc
@@ -67,10 +67,9 @@ QuicFrame frame_; }; -INSTANTIATE_TEST_CASE_P(Tests, - UberQuicStreamIdManagerTest, - ::testing::ValuesIn({Perspective::IS_CLIENT, - Perspective::IS_SERVER})); +INSTANTIATE_TEST_SUITE_P(Tests, UberQuicStreamIdManagerTest, + ::testing::ValuesIn({Perspective::IS_CLIENT, + Perspective::IS_SERVER})); TEST_P(UberQuicStreamIdManagerTest, Initialization) { if (GetParam() == Perspective::IS_SERVER) {
diff --git a/quic/platform/api/quic_containers.h b/quic/platform/api/quic_containers.h index 04c462e..7cfb311 100644 --- a/quic/platform/api/quic_containers.h +++ b/quic/platform/api/quic_containers.h
@@ -33,11 +33,6 @@ template <typename Key, typename Value, int Size> using QuicSmallMap = QuicSmallMapImpl<Key, Value, Size>; -// A data structure used to represent a sorted set of non-empty, non-adjacent, -// and mutually disjoint intervals. -template <typename T> -using QuicIntervalSet = QuicIntervalSetImpl<T>; - // Represents a simple queue which may be backed by a list or // a flat circular buffer. //
diff --git a/quic/platform/api/quic_default_proof_providers.h b/quic/platform/api/quic_default_proof_providers.h new file mode 100644 index 0000000..ab683c1 --- /dev/null +++ b/quic/platform/api/quic_default_proof_providers.h
@@ -0,0 +1,24 @@ +// 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_QUIC_PLATFORM_API_QUIC_DEFAULT_PROOF_PROVIDERS_H_ +#define QUICHE_QUIC_PLATFORM_API_QUIC_DEFAULT_PROOF_PROVIDERS_H_ + +#include <memory> + +#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" +#include "net/quic/platform/impl/quic_default_proof_providers_impl.h" + +namespace quic { + +// Provides a default proof verifier. The verifier has to do a good faith +// attempt at verifying the certificate against a reasonable root store, and not +// just always return success. +std::unique_ptr<ProofVerifier> CreateDefaultProofVerifier() { + return CreateDefaultProofVerifierImpl(); +} + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_API_QUIC_DEFAULT_PROOF_PROVIDERS_H_
diff --git a/quic/platform/api/quic_epoll.h b/quic/platform/api/quic_epoll.h index c289ef4..e429ef8 100644 --- a/quic/platform/api/quic_epoll.h +++ b/quic/platform/api/quic_epoll.h
@@ -1,3 +1,7 @@ +// 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_QUIC_PLATFORM_API_QUIC_EPOLL_H_ #define QUICHE_QUIC_PLATFORM_API_QUIC_EPOLL_H_
diff --git a/quic/platform/api/quic_error_code_wrappers.h b/quic/platform/api/quic_error_code_wrappers.h new file mode 100644 index 0000000..733572e --- /dev/null +++ b/quic/platform/api/quic_error_code_wrappers.h
@@ -0,0 +1,14 @@ +// 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_QUIC_PLATFORM_API_QUIC_ERROR_CODE_WRAPPERS_H_ +#define QUICHE_QUIC_PLATFORM_API_QUIC_ERROR_CODE_WRAPPERS_H_ + +#include "net/quic/platform/impl/quic_error_code_wrappers_impl.h" + +// TODO(vasilvv): ensure WRITE_STATUS_MSG_TOO_BIG works everywhere and remove +// this. +#define QUIC_EMSGSIZE QUIC_EMSGSIZE_IMPL + +#endif // QUICHE_QUIC_PLATFORM_API_QUIC_ERROR_CODE_WRAPPERS_H_
diff --git a/quic/platform/api/quic_exported_stats.h b/quic/platform/api/quic_exported_stats.h index b911c70..28c82ec 100644 --- a/quic/platform/api/quic_exported_stats.h +++ b/quic/platform/api/quic_exported_stats.h
@@ -64,9 +64,9 @@ #define QUIC_HISTOGRAM_TIMES(name, sample, min, max, bucket_count, docstring) \ do { \ QUIC_CLIENT_HISTOGRAM_TIMES_IMPL(name, sample, min, max, bucket_count, \ - docstring) \ + docstring); \ QUIC_SERVER_HISTOGRAM_TIMES_IMPL(name, sample, min, max, bucket_count, \ - docstring) \ + docstring); \ } while (0) //------------------------------------------------------------------------------
diff --git a/quic/platform/api/quic_flags.h b/quic/platform/api/quic_flags.h index 6ddc13a..45145a7 100644 --- a/quic/platform/api/quic_flags.h +++ b/quic/platform/api/quic_flags.h
@@ -5,8 +5,16 @@ #ifndef QUICHE_QUIC_PLATFORM_API_QUIC_FLAGS_H_ #define QUICHE_QUIC_PLATFORM_API_QUIC_FLAGS_H_ +#include <vector> + +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" #include "net/quic/platform/impl/quic_flags_impl.h" +// Define a command-line flag that can be automatically set via +// QuicParseCommandLineFlags(). +#define DEFINE_QUIC_COMMAND_LINE_FLAG(type, name, default_value, help) \ + DEFINE_QUIC_COMMAND_LINE_FLAG_IMPL(type, name, default_value, help) + #define GetQuicReloadableFlag(flag) GetQuicReloadableFlagImpl(flag) #define SetQuicReloadableFlag(flag, value) \ SetQuicReloadableFlagImpl(flag, value) @@ -15,4 +23,26 @@ #define GetQuicFlag(flag) GetQuicFlagImpl(flag) #define SetQuicFlag(flag, value) SetQuicFlagImpl(flag, value) +namespace quic { + +// Parses command-line flags, setting flag variables defined using +// DEFINE_QUIC_COMMAND_LINE_FLAG if they appear in the command line, and +// returning a list of any non-flag arguments specified in the command line. If +// the command line specifies '-h' or '--help', prints a usage message with flag +// descriptions to stdout and exits with status 0. If a flag has an unparsable +// value, writes an error message to stderr and exits with status 1. +inline std::vector<QuicString> QuicParseCommandLineFlags( + const char* usage, + int argc, + const char* const* argv) { + return QuicParseCommandLineFlagsImpl(usage, argc, argv); +} + +// Prints a usage message with flag descriptions to stdout. +inline void QuicPrintCommandLineFlagHelp(const char* usage) { + QuicPrintCommandLineFlagHelpImpl(usage); +} + +} // namespace quic + #endif // QUICHE_QUIC_PLATFORM_API_QUIC_FLAGS_H_
diff --git a/quic/platform/api/quic_interval.h b/quic/platform/api/quic_interval.h deleted file mode 100644 index 51d2f52..0000000 --- a/quic/platform/api/quic_interval.h +++ /dev/null
@@ -1,17 +0,0 @@ -// Copyright 2018 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_INTERVAL_H_ -#define QUICHE_QUIC_PLATFORM_API_QUIC_INTERVAL_H_ - -#include "net/quic/platform/impl/quic_interval_impl.h" - -namespace quic { - -template <class T> -using QuicInterval = QuicIntervalImpl<T>; - -} // namespace quic - -#endif // QUICHE_QUIC_PLATFORM_API_QUIC_INTERVAL_H_
diff --git a/quic/platform/api/quic_macros.h b/quic/platform/api/quic_macros.h new file mode 100644 index 0000000..9dee2e9 --- /dev/null +++ b/quic/platform/api/quic_macros.h
@@ -0,0 +1,13 @@ +// 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_QUIC_PLATFORM_API_QUIC_MACROS_H_ +#define QUICHE_QUIC_PLATFORM_API_QUIC_MACROS_H_ + +#include "net/quic/platform/impl/quic_macros_impl.h" + +#define QUIC_MUST_USE_RESULT QUIC_MUST_USE_RESULT_IMPL +#define QUIC_UNUSED QUIC_UNUSED_IMPL + +#endif // QUICHE_QUIC_PLATFORM_API_QUIC_MACROS_H_
diff --git a/quic/platform/api/quic_mem_slice_span.h b/quic/platform/api/quic_mem_slice_span.h index 39436be..781382e 100644 --- a/quic/platform/api/quic_mem_slice_span.h +++ b/quic/platform/api/quic_mem_slice_span.h
@@ -35,6 +35,12 @@ return impl_.SaveMemSlicesInSendBuffer(send_buffer); } + // Save data buffers as message data in |message_frame|. |message_frame| will + // hold a reference to all data buffers. + void SaveMemSlicesAsMessageData(QuicMessageFrame* message_frame) { + impl_.SaveMemSlicesAsMessageData(message_frame); + } + // Return data of the span at |index| by the form of a QuicStringPiece. QuicStringPiece GetData(int index) { return impl_.GetData(index); }
diff --git a/quic/platform/api/quic_mem_slice_storage_test.cc b/quic/platform/api/quic_mem_slice_storage_test.cc index d5a5b8f..72623e1 100644 --- a/quic/platform/api/quic_mem_slice_storage_test.cc +++ b/quic/platform/api/quic_mem_slice_storage_test.cc
@@ -4,7 +4,6 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_mem_slice_storage.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" - #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic {
diff --git a/quic/platform/api/quic_port_utils.h b/quic/platform/api/quic_port_utils.h new file mode 100644 index 0000000..aa85fc5 --- /dev/null +++ b/quic/platform/api/quic_port_utils.h
@@ -0,0 +1,26 @@ +// 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_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_ +#define QUICHE_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_ + +#include "net/quic/platform/impl/quic_port_utils_impl.h" + +namespace quic { + +// Returns a UDP port that is currently unused. Check-fails if none are +// available. +inline int QuicPickUnusedPortOrDie() { + return QuicPickUnusedPortOrDieImpl(); +} + +// Indicates that a specified port previously returned by +// QuicPickUnusedPortOrDie is no longer used. +inline void QuicRecyclePort(int port) { + return QuicRecyclePortImpl(port); +} + +} // namespace quic + +#endif // QUICHE_QUIC_PLATFORM_API_QUIC_PORT_UTILS_H_
diff --git a/quic/quartc/quartc_connection_helper.cc b/quic/quartc/quartc_connection_helper.cc new file mode 100644 index 0000000..6c6ee97 --- /dev/null +++ b/quic/quartc/quartc_connection_helper.cc
@@ -0,0 +1,24 @@ +// 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 "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" + +namespace quic { + +QuartcConnectionHelper::QuartcConnectionHelper(const QuicClock* clock) + : clock_(clock) {} + +const QuicClock* QuartcConnectionHelper::GetClock() const { + return clock_; +} + +QuicRandom* QuartcConnectionHelper::GetRandomGenerator() { + return QuicRandom::GetInstance(); +} + +QuicBufferAllocator* QuartcConnectionHelper::GetStreamSendBufferAllocator() { + return &buffer_allocator_; +} + +} // namespace quic
diff --git a/quic/quartc/quartc_connection_helper.h b/quic/quartc/quartc_connection_helper.h new file mode 100644 index 0000000..2b1d62f --- /dev/null +++ b/quic/quartc/quartc_connection_helper.h
@@ -0,0 +1,33 @@ +// 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. + +#ifndef QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_ +#define QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" +#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h" +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" + +namespace quic { + +// Simple implementation of QuicConnectionHelperInterface for Quartc. +class QuartcConnectionHelper : public QuicConnectionHelperInterface { + public: + explicit QuartcConnectionHelper(const QuicClock* clock); + + // QuicConnectionHelperInterface overrides. + const QuicClock* GetClock() const override; + QuicRandom* GetRandomGenerator() override; + QuicBufferAllocator* GetStreamSendBufferAllocator() override; + + private: + const QuicClock* clock_; + SimpleBufferAllocator buffer_allocator_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_QUARTC_QUARTC_CONNECTION_HELPER_H_
diff --git a/quic/quartc/quartc_crypto_helpers.cc b/quic/quartc/quartc_crypto_helpers.cc new file mode 100644 index 0000000..865fec4 --- /dev/null +++ b/quic/quartc/quartc_crypto_helpers.cc
@@ -0,0 +1,162 @@ +// 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 "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.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" + +namespace quic { + +void DummyProofSource::GetProof(const QuicSocketAddress& server_address, + const QuicString& hostname, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + std::unique_ptr<Callback> callback) { + QuicReferenceCountedPointer<ProofSource::Chain> chain = + GetCertChain(server_address, hostname); + QuicCryptoProof proof; + proof.signature = "Dummy signature"; + proof.leaf_cert_scts = "Dummy timestamp"; + callback->Run(true, chain, proof, nullptr /* details */); +} + +QuicReferenceCountedPointer<DummyProofSource::Chain> +DummyProofSource::GetCertChain(const QuicSocketAddress& server_address, + const QuicString& hostname) { + std::vector<QuicString> certs; + certs.push_back(kDummyCertName); + return QuicReferenceCountedPointer<ProofSource::Chain>( + new ProofSource::Chain(certs)); +} + +void DummyProofSource::ComputeTlsSignature( + const QuicSocketAddress& server_address, + const QuicString& hostname, + uint16_t signature_algorithm, + QuicStringPiece in, + std::unique_ptr<SignatureCallback> callback) { + callback->Run(true, "Dummy signature"); +} + +QuicAsyncStatus InsecureProofVerifier::VerifyProof( + const QuicString& hostname, + const uint16_t port, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + const std::vector<QuicString>& certs, + const QuicString& cert_sct, + const QuicString& signature, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* verify_details, + std::unique_ptr<ProofVerifierCallback> callback) { + return QUIC_SUCCESS; +} + +QuicAsyncStatus InsecureProofVerifier::VerifyCertChain( + const QuicString& hostname, + const std::vector<QuicString>& certs, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) { + return QUIC_SUCCESS; +} + +std::unique_ptr<ProofVerifyContext> +InsecureProofVerifier::CreateDefaultContext() { + return nullptr; +} + +QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject( + QuicTransportVersion version, + QuicConnectionId connection_id) const { + // TODO(b/124399417): Request a zero-length connection id here when the QUIC + // server perspective supports it. Right now, the stateless rejector requires + // a connection id that is not the same as the client-chosen connection id. + return QuicUtils::CreateRandomConnectionId(); +} + +bool QuartcCryptoServerStreamHelper::CanAcceptClientHello( + const CryptoHandshakeMessage& message, + const QuicSocketAddress& client_address, + const QuicSocketAddress& peer_address, + const QuicSocketAddress& self_address, + QuicString* error_details) const { + return true; +} + +std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig( + QuicStringPiece pre_shared_key) { + auto config = QuicMakeUnique<QuicCryptoClientConfig>( + QuicMakeUnique<InsecureProofVerifier>(), + TlsClientHandshaker::CreateSslCtx()); + config->set_pad_inchoate_hello(false); + config->set_pad_full_hello(false); + if (!pre_shared_key.empty()) { + config->set_pre_shared_key(pre_shared_key); + } + return config; +} + +CryptoServerConfig CreateCryptoServerConfig(QuicRandom* random, + const QuicClock* clock, + QuicStringPiece pre_shared_key) { + CryptoServerConfig crypto_server_config; + + // Generate a random source address token secret. For long-running servers + // it's better to not regenerate it for each connection to enable zero-RTT + // handshakes, but for transient clients it does not matter. + char source_address_token_secret[kInputKeyingMaterialLength]; + random->RandBytes(source_address_token_secret, kInputKeyingMaterialLength); + auto config = QuicMakeUnique<QuicCryptoServerConfig>( + QuicString(source_address_token_secret, kInputKeyingMaterialLength), + random, QuicMakeUnique<DummyProofSource>(), KeyExchangeSource::Default(), + TlsServerHandshaker::CreateSslCtx()); + + // We run QUIC over ICE, and ICE is verifying remote side with STUN pings. + // We disable source address token validation in order to allow for 0-rtt + // setup (plus source ip addresses are changing even during the connection + // when ICE is used). + config->set_validate_source_address_token(false); + + // Effectively disables the anti-amplification measures (we don't need + // them because we use ICE, and we need to disable them because we disable + // padding of crypto packets). + // This multiplier must be large enough so that the crypto handshake packet + // (approx. 300 bytes) multiplied by this multiplier is larger than a fully + // sized packet (currently 1200 bytes). + // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and + // your largest MTU would be below 1500 bytes, 1500*1 >= + // any_packet_that_you_can_imagine_sending. + // (again, we hardcode packet size to 1200, so we are not dealing with jumbo + // frames). + config->set_chlo_multiplier(1500); + + // We are sending small client hello, we must not validate its size. + config->set_validate_chlo_size(false); + + // Provide server with serialized config string to prove ownership. + QuicCryptoServerConfig::ConfigOptions options; + // The |message| is used to handle the return value of AddDefaultConfig + // which is raw pointer of the CryptoHandshakeMessage. + std::unique_ptr<CryptoHandshakeMessage> message( + config->AddDefaultConfig(random, clock, options)); + config->set_pad_rej(false); + config->set_pad_shlo(false); + if (!pre_shared_key.empty()) { + config->set_pre_shared_key(pre_shared_key); + } + crypto_server_config.config = std::move(config); + const QuicData& data = message->GetSerialized(); + + crypto_server_config.serialized_crypto_config = + QuicString(data.data(), data.length()); + return crypto_server_config; +} + +} // namespace quic
diff --git a/quic/quartc/quartc_crypto_helpers.h b/quic/quartc/quartc_crypto_helpers.h new file mode 100644 index 0000000..2b280b5 --- /dev/null +++ b/quic/quartc/quartc_crypto_helpers.h
@@ -0,0 +1,121 @@ +// 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. + +#ifndef QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_ +#define QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_source.h" +#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h" +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.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_string.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" + +namespace quic { + +// Never, ever, change this certificate name. You will break 0-rtt handshake if +// you do. +static constexpr char kDummyCertName[] = "Dummy cert"; + +struct CryptoServerConfig { + std::unique_ptr<QuicCryptoServerConfig> config; + QuicString serialized_crypto_config; +}; + +// Length of HKDF input keying material, equal to its number of bytes. +// https://tools.ietf.org/html/rfc5869#section-2.2. +// TODO(zhihuang): Verify that input keying material length is correct. +constexpr size_t kInputKeyingMaterialLength = 32; + +// Used by QuicCryptoServerConfig to provide dummy proof credentials. +// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. +class DummyProofSource : public ProofSource { + public: + DummyProofSource() {} + ~DummyProofSource() override {} + + // ProofSource overrides. + void GetProof(const QuicSocketAddress& server_address, + const QuicString& hostname, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + std::unique_ptr<Callback> callback) override; + + QuicReferenceCountedPointer<Chain> GetCertChain( + const QuicSocketAddress& server_address, + const QuicString& hostname) override; + + void ComputeTlsSignature( + const QuicSocketAddress& server_address, + const QuicString& hostname, + uint16_t signature_algorithm, + QuicStringPiece in, + std::unique_ptr<SignatureCallback> callback) override; +}; + +// Used by QuicCryptoClientConfig to ignore the peer's credentials +// and establish an insecure QUIC connection. +// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. +class InsecureProofVerifier : public ProofVerifier { + public: + InsecureProofVerifier() {} + ~InsecureProofVerifier() override {} + + // ProofVerifier overrides. + QuicAsyncStatus VerifyProof( + const QuicString& hostname, + const uint16_t port, + const QuicString& server_config, + QuicTransportVersion transport_version, + QuicStringPiece chlo_hash, + const std::vector<QuicString>& certs, + const QuicString& cert_sct, + const QuicString& signature, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* verify_details, + std::unique_ptr<ProofVerifierCallback> callback) override; + + QuicAsyncStatus VerifyCertChain( + const QuicString& hostname, + const std::vector<QuicString>& certs, + const ProofVerifyContext* context, + QuicString* error_details, + std::unique_ptr<ProofVerifyDetails>* details, + std::unique_ptr<ProofVerifierCallback> callback) override; + + std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override; +}; + +// Implementation of the server-side crypto stream helper. +class QuartcCryptoServerStreamHelper : public QuicCryptoServerStream::Helper { + public: + QuicConnectionId GenerateConnectionIdForReject( + QuicTransportVersion version, + QuicConnectionId connection_id) const override; + + bool CanAcceptClientHello(const CryptoHandshakeMessage& message, + const QuicSocketAddress& client_address, + const QuicSocketAddress& peer_address, + const QuicSocketAddress& self_address, + QuicString* error_details) const override; +}; + +std::unique_ptr<QuicCryptoClientConfig> CreateCryptoClientConfig( + QuicStringPiece pre_shared_key); + +CryptoServerConfig CreateCryptoServerConfig(QuicRandom* random, + const QuicClock* clock, + QuicStringPiece pre_shared_key); + +} // namespace quic + +#endif // QUICHE_QUIC_QUARTC_QUARTC_CRYPTO_HELPERS_H_
diff --git a/quic/quartc/quartc_dispatcher.cc b/quic/quartc/quartc_dispatcher.cc new file mode 100644 index 0000000..7c398e2 --- /dev/null +++ b/quic/quartc/quartc_dispatcher.cc
@@ -0,0 +1,79 @@ +// 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 "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h" + +#include "net/third_party/quiche/src/quic/core/quic_versions.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" + +namespace quic { + +QuartcDispatcher::QuartcDispatcher( + std::unique_ptr<QuicConfig> config, + std::unique_ptr<QuicCryptoServerConfig> crypto_config, + QuicStringPiece crypto_config_serialized, + std::unique_ptr<QuicVersionManager> version_manager, + std::unique_ptr<QuicConnectionHelperInterface> helper, + std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, + std::unique_ptr<QuicAlarmFactory> alarm_factory, + std::unique_ptr<QuartcPacketWriter> packet_writer, + Delegate* delegate) + : QuicDispatcher(config.get(), + crypto_config.get(), + version_manager.get(), + std::move(helper), + std::move(session_helper), + std::move(alarm_factory)), + owned_quic_config_(std::move(config)), + owned_crypto_config_(std::move(crypto_config)), + crypto_config_(crypto_config_serialized), + owned_version_manager_(std::move(version_manager)), + delegate_(delegate), + packet_writer_(packet_writer.get()) { + // QuicDispatcher takes ownership of the writer. + QuicDispatcher::InitializeWithWriter(packet_writer.release()); + // NB: This must happen *after* InitializeWithWriter. It can call us back + // with OnTransportCanWrite() immediately, and the dispatcher needs to be + // fully initialized to handle that. + packet_writer_->SetPacketTransportDelegate(this); +} + +QuartcDispatcher::~QuartcDispatcher() { + packet_writer_->SetPacketTransportDelegate(nullptr); +} + +QuartcSession* QuartcDispatcher::CreateQuicSession( + QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + QuicStringPiece alpn, + const ParsedQuicVersion& version) { + std::unique_ptr<QuicConnection> connection = CreateQuicConnection( + connection_id, client_address, helper(), alarm_factory(), writer(), + Perspective::IS_SERVER, ParsedQuicVersionVector{version}); + QuartcSession* session = new QuartcServerSession( + std::move(connection), /*visitor=*/this, config(), GetSupportedVersions(), + helper()->GetClock(), crypto_config(), compressed_certs_cache(), + session_helper()); + delegate_->OnSessionCreated(session); + return session; +} + +void QuartcDispatcher::OnTransportCanWrite() { + OnCanWrite(); +} + +void QuartcDispatcher::OnTransportReceived(const char* data, size_t data_len) { + // QuartcPacketTransport does not surface real peer addresses, so the + // dispatcher uses a dummy address when processing incoming packets. Note that + // the dispatcher refuses to process anything with port 0. + static const QuicSocketAddress* dummy_address = + new QuicSocketAddress(QuicIpAddress::Any4(), /*port=*/1); + + QuicReceivedPacket packet(data, data_len, helper()->GetClock()->Now()); + ProcessPacket(/*self_address=*/*dummy_address, + /*peer_address=*/*dummy_address, packet); +} + +} // namespace quic
diff --git a/quic/quartc/quartc_dispatcher.h b/quic/quartc/quartc_dispatcher.h new file mode 100644 index 0000000..6022720 --- /dev/null +++ b/quic/quartc/quartc_dispatcher.h
@@ -0,0 +1,74 @@ +// 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. + +#ifndef QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_ +#define QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_ + +#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h" +#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" +#include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/core/quic_connection.h" +#include "net/third_party/quiche/src/quic/core/quic_connection_id.h" +#include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" +#include "net/third_party/quiche/src/quic/core/quic_dispatcher.h" +#include "net/third_party/quiche/src/quic/core/quic_version_manager.h" +#include "net/third_party/quiche/src/quic/core/quic_versions.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_piece.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_session.h" + +namespace quic { + +class QuartcDispatcher : public QuicDispatcher, + QuartcPacketTransport::Delegate { + public: + class Delegate { + public: + virtual ~Delegate() = default; + virtual void OnSessionCreated(QuartcSession* session) = 0; + }; + + QuartcDispatcher( + std::unique_ptr<QuicConfig> config, + std::unique_ptr<QuicCryptoServerConfig> crypto_config, + QuicStringPiece crypto_config_serialized, + std::unique_ptr<QuicVersionManager> version_manager, + std::unique_ptr<QuicConnectionHelperInterface> helper, + std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, + std::unique_ptr<QuicAlarmFactory> alarm_factory, + std::unique_ptr<QuartcPacketWriter> packet_writer, + Delegate* delegate); + ~QuartcDispatcher() override; + + QuartcSession* CreateQuicSession(QuicConnectionId connection_id, + const QuicSocketAddress& client_address, + QuicStringPiece alpn, + const ParsedQuicVersion& version) override; + + // QuartcPacketTransport::Delegate overrides. + void OnTransportCanWrite() override; + void OnTransportReceived(const char* data, size_t data_len) override; + + // A serialized server config in quic wire format. + QuicStringPiece server_crypto_config() const { return crypto_config_; } + + private: + // Members owned by QuartcDispatcher but not QuicDispatcher. + std::unique_ptr<QuicConfig> owned_quic_config_; + std::unique_ptr<QuicCryptoServerConfig> owned_crypto_config_; + QuicString crypto_config_; + std::unique_ptr<QuicVersionManager> owned_version_manager_; + + // Delegate invoked when the dispatcher creates a new session. + Delegate* delegate_; + + // The packet writer used by this dispatcher. Owned by the base class, but + // the base class upcasts it to QuicPacketWriter (which prevents detaching the + // transport delegate without a downcast). + QuartcPacketWriter* packet_writer_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_QUARTC_QUARTC_DISPATCHER_H_
diff --git a/quic/quartc/quartc_endpoint.cc b/quic/quartc/quartc_endpoint.cc new file mode 100644 index 0000000..8d03b0a --- /dev/null +++ b/quic/quartc/quartc_endpoint.cc
@@ -0,0 +1,107 @@ +// 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 "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" +#include "net/third_party/quiche/src/quic/core/quic_version_manager.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h" + +namespace quic { + +namespace { + +// Wrapper around a QuicAlarmFactory which delegates to the wrapped factory. +// Usee to convert an unowned pointer into an owned pointer, so that the new +// "owner" does not delete the underlying factory. Note that this is only valid +// when the unowned pointer is already guaranteed to outlive the new "owner". +class QuartcAlarmFactoryWrapper : public QuicAlarmFactory { + public: + explicit QuartcAlarmFactoryWrapper(QuicAlarmFactory* impl) : impl_(impl) {} + + QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override; + QuicArenaScopedPtr<QuicAlarm> CreateAlarm( + QuicArenaScopedPtr<QuicAlarm::Delegate> delegate, + QuicConnectionArena* arena) override; + + private: + QuicAlarmFactory* impl_; +}; + +QuicAlarm* QuartcAlarmFactoryWrapper::CreateAlarm( + QuicAlarm::Delegate* delegate) { + return impl_->CreateAlarm(delegate); +} + +QuicArenaScopedPtr<QuicAlarm> QuartcAlarmFactoryWrapper::CreateAlarm( + QuicArenaScopedPtr<QuicAlarm::Delegate> delegate, + QuicConnectionArena* arena) { + return impl_->CreateAlarm(std::move(delegate), arena); +} + +QuartcFactoryConfig CreateFactoryConfig(QuicAlarmFactory* alarm_factory, + const QuicClock* clock) { + QuartcFactoryConfig config; + config.alarm_factory = alarm_factory; + config.clock = clock; + return config; +} + +} // namespace + +QuartcClientEndpoint::QuartcClientEndpoint( + QuicAlarmFactory* alarm_factory, + const QuicClock* clock, + QuartcEndpoint::Delegate* delegate, + QuicStringPiece serialized_server_config) + : alarm_factory_(alarm_factory), + clock_(clock), + delegate_(delegate), + serialized_server_config_(serialized_server_config), + create_session_alarm_(QuicWrapUnique( + alarm_factory_->CreateAlarm(new CreateSessionDelegate(this)))), + factory_(QuicMakeUnique<QuartcFactory>( + CreateFactoryConfig(alarm_factory, clock))) {} + +void QuartcClientEndpoint::Connect(const QuartcSessionConfig& config) { + config_ = config; + create_session_alarm_->Set(clock_->Now()); +} + +void QuartcClientEndpoint::OnCreateSessionAlarm() { + session_ = + factory_->CreateQuartcClientSession(config_, serialized_server_config_); + delegate_->OnSessionCreated(session_.get()); +} + +QuartcServerEndpoint::QuartcServerEndpoint(QuicAlarmFactory* alarm_factory, + const QuicClock* clock, + QuartcEndpoint::Delegate* delegate) + : alarm_factory_(alarm_factory), clock_(clock), delegate_(delegate) {} + +void QuartcServerEndpoint::Connect(const QuartcSessionConfig& config) { + auto connection_helper = QuicMakeUnique<QuartcConnectionHelper>(clock_); + auto crypto_config = CreateCryptoServerConfig( + connection_helper->GetRandomGenerator(), clock_, config.pre_shared_key); + dispatcher_ = QuicMakeUnique<QuartcDispatcher>( + QuicMakeUnique<QuicConfig>(CreateQuicConfig(config)), + std::move(crypto_config.config), crypto_config.serialized_crypto_config, + QuicMakeUnique<QuicVersionManager>(AllSupportedVersions()), + std::move(connection_helper), + QuicMakeUnique<QuartcCryptoServerStreamHelper>(), + QuicMakeUnique<QuartcAlarmFactoryWrapper>(alarm_factory_), + QuicMakeUnique<QuartcPacketWriter>(config.packet_transport, + config.max_packet_size), + this); + // The dispatcher requires at least one call to |ProcessBufferedChlos| to + // set the number of connections it is allowed to create. + dispatcher_->ProcessBufferedChlos(/*max_connections_to_create=*/1); +} + +void QuartcServerEndpoint::OnSessionCreated(QuartcSession* session) { + delegate_->OnSessionCreated(session); +} + +} // namespace quic
diff --git a/quic/quartc/quartc_endpoint.h b/quic/quartc/quartc_endpoint.h new file mode 100644 index 0000000..108fe12 --- /dev/null +++ b/quic/quartc/quartc_endpoint.h
@@ -0,0 +1,156 @@ +// 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. + +#ifndef QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_ +#define QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_ + +#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" +#include "net/third_party/quiche/src/quic/core/quic_error_codes.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_dispatcher.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" + +namespace quic { + +// Private implementation of QuartcEndpoint. Enables different implementations +// for client and server endpoints. +class QuartcEndpointImpl { + public: + virtual ~QuartcEndpointImpl() = default; + + virtual QuicStringPiece server_crypto_config() const = 0; +}; + +// Endpoint (client or server) in a peer-to-peer Quartc connection. +class QuartcEndpoint { + public: + class Delegate { + public: + virtual ~Delegate() = default; + + // Called when an endpoint creates a new session, before any packets are + // processed or sent. The callee should perform any additional + // configuration required, such as setting a session delegate, before + // returning. |session| is owned by the endpoint, but remains safe to use + // until another call to |OnSessionCreated| occurs, at which point previous + // session is destroyed. + virtual void OnSessionCreated(QuartcSession* session) = 0; + + // Called if the endpoint fails to establish a session after a call to + // Connect. (The most likely cause is a network idle timeout.) + virtual void OnConnectError(QuicErrorCode error, + const QuicString& error_details) = 0; + }; + + virtual ~QuartcEndpoint() = default; + + // Connects the endpoint using the given session config. After |Connect| is + // called, the endpoint will asynchronously create a session, then call + // |Delegate::OnSessionCreated|. + virtual void Connect(const QuartcSessionConfig& config) = 0; +}; + +// Implementation of QuartcEndpoint which immediately (but asynchronously) +// creates a session by scheduling a QuicAlarm. Only suitable for use with the +// client perspective. +class QuartcClientEndpoint : public QuartcEndpoint { + public: + // |alarm_factory|, |clock|, and |delegate| are owned by the caller and must + // outlive the endpoint. + QuartcClientEndpoint(QuicAlarmFactory* alarm_factory, + const QuicClock* clock, + Delegate* delegate, + QuicStringPiece serialized_server_config); + + void Connect(const QuartcSessionConfig& config) override; + + private: + friend class CreateSessionDelegate; + class CreateSessionDelegate : public QuicAlarm::Delegate { + public: + CreateSessionDelegate(QuartcClientEndpoint* endpoint) + : endpoint_(endpoint) {} + + void OnAlarm() override { endpoint_->OnCreateSessionAlarm(); } + + private: + QuartcClientEndpoint* endpoint_; + }; + + // Callback which occurs when |create_session_alarm_| fires. + void OnCreateSessionAlarm(); + + // Implementation of QuicAlarmFactory used by this endpoint. Unowned. + QuicAlarmFactory* alarm_factory_; + + // Implementation of QuicClock used by this endpoint. Unowned. + const QuicClock* clock_; + + // Delegate which receives callbacks for newly created sessions. + QuartcEndpoint::Delegate* delegate_; + + // Server config. If valid, used to perform a 0-RTT connection. + const QuicString serialized_server_config_; + + // Alarm for creating sessions asynchronously. The alarm is set when + // Connect() is called. When it fires, the endpoint creates a session and + // calls the delegate. + std::unique_ptr<QuicAlarm> create_session_alarm_; + + // QuartcFactory used by this endpoint to create sessions. This is an + // implementation detail of the QuartcEndpoint, and will eventually be + // replaced by a dispatcher (for servers) or version-negotiation agent (for + // clients). + std::unique_ptr<QuartcFactory> factory_; + + // Config to be used for new sessions. + QuartcSessionConfig config_; + + // The currently-active session. Nullptr until |Connect| and + // |Delegate::OnSessionCreated| are called. + std::unique_ptr<QuartcSession> session_; +}; + +// Implementation of QuartcEndpoint which uses a QuartcDispatcher to listen for +// an incoming CHLO and create a session when one arrives. Only suitable for +// use with the server perspective. +class QuartcServerEndpoint : public QuartcEndpoint, + public QuartcDispatcher::Delegate { + public: + QuartcServerEndpoint(QuicAlarmFactory* alarm_factory, + const QuicClock* clock, + QuartcEndpoint::Delegate* delegate); + + // Implements QuartcEndpoint. + void Connect(const QuartcSessionConfig& config) override; + + // Implements QuartcDispatcher::Delegate. + void OnSessionCreated(QuartcSession* session) override; + + // Accessor to retrieve the server crypto config. May only be called after + // Connect(). + QuicStringPiece server_crypto_config() const { + return dispatcher_->server_crypto_config(); + } + + private: + // Implementation of QuicAlarmFactory used by this endpoint. Unowned. + QuicAlarmFactory* alarm_factory_; + + // Implementation of QuicClock used by this endpoint. Unowned. + const QuicClock* clock_; + + // Delegate which receives callbacks for newly created sessions. + QuartcEndpoint::Delegate* delegate_; + + // QuartcDispatcher waits for an incoming CHLO, then either rejects it or + // creates a session to respond to it. The dispatcher owns all sessions it + // creates. + std::unique_ptr<QuartcDispatcher> dispatcher_; +}; + +} // namespace quic + +#endif // QUICHE_QUIC_QUARTC_QUARTC_ENDPOINT_H_
diff --git a/quic/quartc/quartc_endpoint_test.cc b/quic/quartc/quartc_endpoint_test.cc new file mode 100644 index 0000000..59ca847 --- /dev/null +++ b/quic/quartc/quartc_endpoint_test.cc
@@ -0,0 +1,64 @@ +// 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 "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_test.h" +#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" + +namespace quic { +namespace { + +static QuicByteCount kDefaultMaxPacketSize = 1200; + +class FakeEndpointDelegate : public QuartcEndpoint::Delegate { + public: + void OnSessionCreated(QuartcSession* session) override { + last_session_ = session; + } + + void OnConnectError(QuicErrorCode /*error*/, + const QuicString& /*error_details*/) override {} + + QuartcSession* last_session() { return last_session_; } + + private: + QuartcSession* last_session_ = nullptr; +}; + +class QuartcEndpointTest : public QuicTest { + protected: + QuartcEndpointTest() + : transport_(&simulator_, + "client_transport", + "server_transport", + 10 * kDefaultMaxPacketSize) {} + + simulator::Simulator simulator_; + simulator::SimulatedQuartcPacketTransport transport_; + FakeEndpointDelegate delegate_; +}; + +// After calling Connect, the client endpoint must wait for an async callback. +// The callback occurs after a finite amount of time and produces a session. +TEST_F(QuartcEndpointTest, ClientCreatesSessionAsynchronously) { + QuartcClientEndpoint endpoint_(simulator_.GetAlarmFactory(), + simulator_.GetClock(), &delegate_, + /*serialized_server_config=*/""); + QuartcSessionConfig config; + config.packet_transport = &transport_; + config.max_packet_size = kDefaultMaxPacketSize; + endpoint_.Connect(config); + + EXPECT_EQ(delegate_.last_session(), nullptr); + + EXPECT_TRUE(simulator_.RunUntil( + [this] { return delegate_.last_session() != nullptr; })); +} + +} // namespace +} // namespace quic
diff --git a/quic/quartc/quartc_factory.cc b/quic/quartc/quartc_factory.cc index ee637e5..336ca14 100644 --- a/quic/quartc/quartc_factory.cc +++ b/quic/quartc/quartc_factory.cc
@@ -5,40 +5,63 @@ #include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.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_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_connection_helper.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" #include "net/third_party/quiche/src/quic/quartc/quartc_session.h" namespace quic { QuartcFactory::QuartcFactory(const QuartcFactoryConfig& factory_config) : alarm_factory_(factory_config.alarm_factory), - clock_(factory_config.clock) {} + clock_(factory_config.clock), + connection_helper_(QuicMakeUnique<QuartcConnectionHelper>(clock_)), + compressed_certs_cache_(QuicMakeUnique<QuicCompressedCertsCache>( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)), + stream_helper_(QuicMakeUnique<QuartcCryptoServerStreamHelper>()) {} -QuartcFactory::~QuartcFactory() {} - -std::unique_ptr<QuartcSession> QuartcFactory::CreateQuartcSession( - const QuartcSessionConfig& quartc_session_config) { +std::unique_ptr<QuartcSession> QuartcFactory::CreateQuartcClientSession( + const QuartcSessionConfig& quartc_session_config, + QuicStringPiece server_crypto_config) { DCHECK(quartc_session_config.packet_transport); - Perspective perspective = quartc_session_config.perspective; - // QuartcSession will eventually own both |writer| and |quic_connection|. auto writer = QuicMakeUnique<QuartcPacketWriter>(quartc_session_config.packet_transport, quartc_session_config.max_packet_size); + // While the QuicConfig is not directly used by the connection, creating it + // also sets flag values which must be set before creating the connection. + QuicConfig quic_config = CreateQuicConfig(quartc_session_config); + std::unique_ptr<QuicConnection> quic_connection = + CreateQuicConnection(Perspective::IS_CLIENT, writer.get()); + + return QuicMakeUnique<QuartcClientSession>( + std::move(quic_connection), quic_config, CurrentSupportedVersions(), + clock_, std::move(writer), + CreateCryptoClientConfig(quartc_session_config.pre_shared_key), + server_crypto_config); +} + +QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config) { + // TODO(b/124398962): Figure out a better way to initialize QUIC flags. + // Creating a config shouldn't have global side-effects on flags. However, + // this has the advantage of ensuring that flag values stay in sync with the + // options requested by configs, so simply splitting the config and flag + // settings doesn't seem preferable. + // Fixes behavior of StopReading() with level-triggered stream sequencers. SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true); // Fix b/110259444. SetQuicReloadableFlag(quic_fix_spurious_ack_alarm, true); - // Enable version 45+ to enable SendMessage API. - // Enable version 47+ to enable 'quic bit' per draft 17. - SetQuicReloadableFlag(quic_enable_version_45, true); + // Enable version 46+ to enable SendMessage API and 'quic bit' per draft 17. SetQuicReloadableFlag(quic_enable_version_46, true); - SetQuicReloadableFlag(quic_enable_version_47, true); // Fix for inconsistent reporting of crypto handshake. SetQuicReloadableFlag(quic_fix_has_pending_crypto_data, true); @@ -57,9 +80,6 @@ // to implement negotiation outside of QuicConnection. SetQuicRestartFlag(quic_no_server_conn_ver_negotiation2, false); - std::unique_ptr<QuicConnection> quic_connection = - CreateQuicConnection(perspective, writer.get()); - QuicTagVector copt; copt.push_back(kNSTP); @@ -78,22 +98,6 @@ // Enable time-based loss detection. copt.push_back(kTIME); - QuicSentPacketManager& sent_packet_manager = - quic_connection->sent_packet_manager(); - - // Default delayed ack time is 25ms. - // If data packets are sent less often (e.g. because p-time was modified), - // we would force acks to be sent every 25ms regardless, increasing - // overhead. Since generally we guarantee a packet every 20ms, changing - // this value should have miniscule effect on quality on good connections, - // but on poor connections, changing this number significantly reduced the - // number of ack-only packets. - // The p-time can go up to as high as 120ms, and when it does, it's - // when the low overhead is the most important thing. Ideally it should be - // above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms. - sent_packet_manager.set_delayed_ack_time( - QuicTime::Delta::FromMilliseconds(100)); - // Note: flag settings have no effect for Exoblaze builds since // SetQuicReloadableFlag() gets stubbed out. SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true); // Enable BBR6,7,8. @@ -115,15 +119,6 @@ copt.push_back(kNTLP); } - quic_connection->set_fill_up_link_during_probing(true); - - // We start ack decimation after 15 packets. Typically, we would see - // 1-2 crypto handshake packets, one media packet, and 10 probing packets. - // We want to get acks for the probing packets as soon as possible, - // but we can start using ack decimation right after first probing completes. - // The default was to not start ack decimation for the first 100 packets. - quic_connection->set_min_received_before_ack_decimation(15); - // TODO(b/112192153): Test and possible enable slower startup when pipe // filling is ready to use. Slower startup is kBBRS. @@ -175,42 +170,63 @@ // number of open streams gives sufficient headroom to recover before QUIC // refuses new streams. quic_config.SetMaxIncomingDynamicStreamsToSend(1000); - return QuicMakeUnique<QuartcSession>( - std::move(quic_connection), quic_config, CurrentSupportedVersions(), - quartc_session_config.unique_remote_server_id, perspective, - this /*QuicConnectionHelperInterface*/, clock_, std::move(writer)); + + return quic_config; } std::unique_ptr<QuicConnection> QuartcFactory::CreateQuicConnection( Perspective perspective, QuartcPacketWriter* packet_writer) { - // dummy_id and dummy_address are used because Quartc network layer will not - // use these two. - QuicConnectionId dummy_id; - if (!QuicConnectionIdSupportsVariableLength(perspective)) { - dummy_id = QuicConnectionIdFromUInt64(0); - } else { + // |dummy_id| and |dummy_address| are used because Quartc network layer will + // not use these two. char connection_id_bytes[sizeof(uint64_t)] = {}; - dummy_id = QuicConnectionId(static_cast<char*>(connection_id_bytes), - sizeof(connection_id_bytes)); - } - QuicSocketAddress dummy_address(QuicIpAddress::Any4(), 0 /*Port*/); - return QuicMakeUnique<QuicConnection>( - dummy_id, dummy_address, this, /*QuicConnectionHelperInterface*/ - alarm_factory_ /*QuicAlarmFactory*/, packet_writer, /*owns_writer=*/false, - perspective, CurrentSupportedVersions()); + QuicConnectionId dummy_id = QuicConnectionId( + static_cast<char*>(connection_id_bytes), sizeof(connection_id_bytes)); + QuicSocketAddress dummy_address(QuicIpAddress::Any4(), /*port=*/0); + return quic::CreateQuicConnection( + dummy_id, dummy_address, connection_helper_.get(), alarm_factory_, + packet_writer, perspective, CurrentSupportedVersions()); } -const QuicClock* QuartcFactory::GetClock() const { - return clock_; -} +std::unique_ptr<QuicConnection> CreateQuicConnection( + QuicConnectionId connection_id, + const QuicSocketAddress& peer_address, + QuicConnectionHelperInterface* connection_helper, + QuicAlarmFactory* alarm_factory, + QuicPacketWriter* packet_writer, + Perspective perspective, + ParsedQuicVersionVector supported_versions) { + auto quic_connection = QuicMakeUnique<QuicConnection>( + connection_id, peer_address, connection_helper, alarm_factory, + packet_writer, + /*owns_writer=*/false, perspective, supported_versions); -QuicRandom* QuartcFactory::GetRandomGenerator() { - return QuicRandom::GetInstance(); -} + QuicSentPacketManager& sent_packet_manager = + quic_connection->sent_packet_manager(); -QuicBufferAllocator* QuartcFactory::GetStreamSendBufferAllocator() { - return &buffer_allocator_; + // Default delayed ack time is 25ms. + // If data packets are sent less often (e.g. because p-time was modified), + // we would force acks to be sent every 25ms regardless, increasing + // overhead. Since generally we guarantee a packet every 20ms, changing + // this value should have miniscule effect on quality on good connections, + // but on poor connections, changing this number significantly reduced the + // number of ack-only packets. + // The p-time can go up to as high as 120ms, and when it does, it's + // when the low overhead is the most important thing. Ideally it should be + // above 120ms, but it cannot be higher than 0.5*RTO, which equals to 100ms. + sent_packet_manager.set_delayed_ack_time( + QuicTime::Delta::FromMilliseconds(100)); + + quic_connection->set_fill_up_link_during_probing(true); + + // We start ack decimation after 15 packets. Typically, we would see + // 1-2 crypto handshake packets, one media packet, and 10 probing packets. + // We want to get acks for the probing packets as soon as possible, + // but we can start using ack decimation right after first probing completes. + // The default was to not start ack decimation for the first 100 packets. + quic_connection->set_min_received_before_ack_decimation(15); + + return quic_connection; } std::unique_ptr<QuartcFactory> CreateQuartcFactory(
diff --git a/quic/quartc/quartc_factory.h b/quic/quartc/quartc_factory.h index c4ea67f..ec9fd7b 100644 --- a/quic/quartc/quartc_factory.h +++ b/quic/quartc/quartc_factory.h
@@ -26,20 +26,18 @@ }; struct QuartcSessionConfig { - // When using Quartc, there are two endpoints. The QuartcSession on one - // endpoint must act as a server and the one on the other side must act as a - // client. - Perspective perspective = Perspective::IS_CLIENT; - // This is only needed when is_server = false. It must be unique - // for each endpoint the local endpoint may communicate with. For example, - // a WebRTC client could use the remote endpoint's crypto fingerprint - QuicString unique_remote_server_id; + // If a pre-shared cryptographic key is available for this session, specify it + // here. This value will only be used if non-empty. + QuicString pre_shared_key; + // The way the QuicConnection will send and receive packets, like a virtual // UDP socket. For WebRTC, this will typically be an IceTransport. QuartcPacketTransport* packet_transport = nullptr; + // The maximum size of the packet can be written with the packet writer. // 1200 bytes by default. QuicPacketLength max_packet_size = 1200; + // Timeouts for the crypto handshake. Set them to higher values to // prevent closing the session before it started on a slow network. // Zero entries are ignored and QUIC defaults are used in that case. @@ -57,21 +55,14 @@ // Factory that creates instances of QuartcSession. Implements the // QuicConnectionHelperInterface used by the QuicConnections. Only one // QuartcFactory is expected to be created. -class QUIC_EXPORT_PRIVATE QuartcFactory : public QuicConnectionHelperInterface { +class QUIC_EXPORT_PRIVATE QuartcFactory { public: explicit QuartcFactory(const QuartcFactoryConfig& factory_config); - ~QuartcFactory() override; // Creates a new QuartcSession using the given configuration. - std::unique_ptr<QuartcSession> CreateQuartcSession( - const QuartcSessionConfig& quartc_session_config); - - // QuicConnectionHelperInterface overrides. - const QuicClock* GetClock() const override; - - QuicRandom* GetRandomGenerator() override; - - QuicBufferAllocator* GetStreamSendBufferAllocator() override; + std::unique_ptr<QuartcSession> CreateQuartcClientSession( + const QuartcSessionConfig& quartc_session_config, + QuicStringPiece server_crypto_config); private: std::unique_ptr<QuicConnection> CreateQuicConnection( @@ -84,9 +75,28 @@ // Used to implement the QuicConnectionHelperInterface. Owned by the user and // must outlive QuartcFactory. const QuicClock* clock_; - SimpleBufferAllocator buffer_allocator_; + + // Helper used by all QuicConnections. + std::unique_ptr<QuicConnectionHelperInterface> connection_helper_; + + // Used by QuicCryptoServerStream to track most recently compressed certs. + std::unique_ptr<QuicCompressedCertsCache> compressed_certs_cache_; + + // This helper is needed to create QuicCryptoServerStreams. + std::unique_ptr<QuicCryptoServerStream::Helper> stream_helper_; }; +QuicConfig CreateQuicConfig(const QuartcSessionConfig& quartc_session_config); + +std::unique_ptr<QuicConnection> CreateQuicConnection( + QuicConnectionId connection_id, + const QuicSocketAddress& peer_address, + QuicConnectionHelperInterface* connection_helper, + QuicAlarmFactory* alarm_factory, + QuicPacketWriter* packet_writer, + Perspective perspective, + ParsedQuicVersionVector supported_versions); + // Creates a new instance of QuartcFactory. std::unique_ptr<QuartcFactory> CreateQuartcFactory( const QuartcFactoryConfig& factory_config);
diff --git a/quic/quartc/quartc_interval_counter.h b/quic/quartc/quartc_interval_counter.h index a9b827c..fe3b083 100644 --- a/quic/quartc/quartc_interval_counter.h +++ b/quic/quartc/quartc_interval_counter.h
@@ -8,8 +8,8 @@ #include <stddef.h> #include <vector> -#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" +#include "net/third_party/quiche/src/quic/core/quic_interval.h" +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" namespace quic {
diff --git a/quic/quartc/quartc_interval_counter_test.cc b/quic/quartc/quartc_interval_counter_test.cc index 9ba14b2..9bc9af5 100644 --- a/quic/quartc/quartc_interval_counter_test.cc +++ b/quic/quartc/quartc_interval_counter_test.cc
@@ -6,7 +6,7 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" +#include "net/third_party/quiche/src/quic/core/quic_interval.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" namespace quic {
diff --git a/quic/quartc/quartc_packet_writer.cc b/quic/quartc/quartc_packet_writer.cc index 84a8bcf..64a72a8 100644 --- a/quic/quartc/quartc_packet_writer.cc +++ b/quic/quartc/quartc_packet_writer.cc
@@ -6,6 +6,10 @@ namespace quic { +std::unique_ptr<PerPacketOptions> QuartcPerPacketOptions::Clone() const { + return QuicMakeUnique<QuartcPerPacketOptions>(*this); +} + QuartcPacketWriter::QuartcPacketWriter(QuartcPacketTransport* packet_transport, QuicByteCount max_packet_size) : packet_transport_(packet_transport), max_packet_size_(max_packet_size) {} @@ -19,10 +23,12 @@ DCHECK(packet_transport_); QuartcPacketTransport::PacketInfo info; - if (connection_) { - info.packet_number = connection_->packet_generator().packet_number(); + QuartcPerPacketOptions* quartc_options = + static_cast<QuartcPerPacketOptions*>(options); + if (quartc_options && quartc_options->connection) { + info.packet_number = + quartc_options->connection->packet_generator().packet_number(); } - int bytes_written = packet_transport_->Write(buffer, buf_len, info); if (bytes_written <= 0) { writable_ = false; @@ -31,10 +37,6 @@ return WriteResult(WRITE_STATUS_OK, bytes_written); } -bool QuartcPacketWriter::IsWriteBlockedDataBuffered() const { - return false; -} - bool QuartcPacketWriter::IsWriteBlocked() const { return !writable_; }
diff --git a/quic/quartc/quartc_packet_writer.h b/quic/quartc/quartc_packet_writer.h index 3efb8a8..517d143 100644 --- a/quic/quartc/quartc_packet_writer.h +++ b/quic/quartc/quartc_packet_writer.h
@@ -51,6 +51,13 @@ virtual void SetDelegate(Delegate* delegate) = 0; }; +struct QUIC_EXPORT_PRIVATE QuartcPerPacketOptions : public PerPacketOptions { + std::unique_ptr<PerPacketOptions> Clone() const override; + + // The connection which is sending this packet. + QuicConnection* connection = nullptr; +}; + // Implements a QuicPacketWriter using a QuartcPacketTransport, which allows a // QuicConnection to use (for example), a WebRTC IceTransport. class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter { @@ -67,9 +74,6 @@ const QuicSocketAddress& peer_address, PerPacketOptions* options) override; - // This is always set to false so that QuicConnection buffers unsent packets. - bool IsWriteBlockedDataBuffered() const override; - // Whether the underneath |transport_| is blocked. If this returns true, // outgoing QUIC packets are queued by QuicConnection until SetWritable() is // called. @@ -93,10 +97,6 @@ WriteResult Flush() override; - // Sets the connection which sends packets using this writer. Connection must - // be set in order to attach packet info (eg. packet numbers) to writes. - void set_connection(QuicConnection* connection) { connection_ = connection; } - void SetPacketTransportDelegate(QuartcPacketTransport::Delegate* delegate); private: @@ -105,9 +105,6 @@ // The maximum size of the packet can be written by this writer. QuicByteCount max_packet_size_; - // The current connection sending packets using this writer. - QuicConnection* connection_; - // Whether packets can be written. bool writable_ = false; };
diff --git a/quic/quartc/quartc_session.cc b/quic/quartc/quartc_session.cc index 37d2cbe..e169e82 100644 --- a/quic/quartc/quartc_session.cc +++ b/quic/quartc/quartc_session.cc
@@ -7,202 +7,33 @@ #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_mem_slice_storage.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_crypto_helpers.h" namespace quic { - namespace { // Arbitrary server port number for net::QuicCryptoClientConfig. const int kQuicServerPort = 0; -// Length of HKDF input keying material, equal to its number of bytes. -// https://tools.ietf.org/html/rfc5869#section-2.2. -// TODO(zhihuang): Verify that input keying material length is correct. -const size_t kInputKeyingMaterialLength = 32; - -// Used by QuicCryptoServerConfig to provide dummy proof credentials. -// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. -class DummyProofSource : public ProofSource { - public: - DummyProofSource() {} - ~DummyProofSource() override {} - - // ProofSource override. - void GetProof(const QuicSocketAddress& server_address, - const QuicString& hostname, - const QuicString& server_config, - QuicTransportVersion transport_version, - QuicStringPiece chlo_hash, - std::unique_ptr<Callback> callback) override { - QuicReferenceCountedPointer<ProofSource::Chain> chain = - GetCertChain(server_address, hostname); - QuicCryptoProof proof; - proof.signature = "Dummy signature"; - proof.leaf_cert_scts = "Dummy timestamp"; - callback->Run(true, chain, proof, nullptr /* details */); - } - - QuicReferenceCountedPointer<Chain> GetCertChain( - const QuicSocketAddress& server_address, - const QuicString& hostname) override { - std::vector<QuicString> certs; - certs.push_back("Dummy cert"); - return QuicReferenceCountedPointer<ProofSource::Chain>( - new ProofSource::Chain(certs)); - } - - void ComputeTlsSignature( - const QuicSocketAddress& server_address, - const QuicString& hostname, - uint16_t signature_algorithm, - QuicStringPiece in, - std::unique_ptr<SignatureCallback> callback) override { - callback->Run(true, "Dummy signature"); - } -}; - -// Used by QuicCryptoClientConfig to ignore the peer's credentials -// and establish an insecure QUIC connection. -// TODO(zhihuang): Remove when secure P2P QUIC handshake is possible. -class InsecureProofVerifier : public ProofVerifier { - public: - InsecureProofVerifier() {} - ~InsecureProofVerifier() override {} - - // ProofVerifier override. - QuicAsyncStatus VerifyProof( - const QuicString& hostname, - const uint16_t port, - const QuicString& server_config, - QuicTransportVersion transport_version, - QuicStringPiece chlo_hash, - const std::vector<QuicString>& certs, - const QuicString& cert_sct, - const QuicString& signature, - const ProofVerifyContext* context, - QuicString* error_details, - std::unique_ptr<ProofVerifyDetails>* verify_details, - std::unique_ptr<ProofVerifierCallback> callback) override { - return QUIC_SUCCESS; - } - - QuicAsyncStatus VerifyCertChain( - const QuicString& hostname, - const std::vector<QuicString>& certs, - const ProofVerifyContext* context, - QuicString* error_details, - std::unique_ptr<ProofVerifyDetails>* details, - std::unique_ptr<ProofVerifierCallback> callback) override { - return QUIC_SUCCESS; - } - - std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override { - return nullptr; - } -}; - } // namespace -QuicConnectionId QuartcCryptoServerStreamHelper::GenerateConnectionIdForReject( - QuicTransportVersion version, - QuicConnectionId connection_id) const { - return QuicUtils::CreateZeroConnectionId(version); -} - -bool QuartcCryptoServerStreamHelper::CanAcceptClientHello( - const CryptoHandshakeMessage& message, - const QuicSocketAddress& client_address, - const QuicSocketAddress& peer_address, - const QuicSocketAddress& self_address, - QuicString* error_details) const { - return true; -} - QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection, + Visitor* visitor, const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, - const QuicString& unique_remote_server_id, - Perspective perspective, - QuicConnectionHelperInterface* helper, - const QuicClock* clock, - std::unique_ptr<QuartcPacketWriter> packet_writer) - : QuicSession(connection.get(), - nullptr /*visitor*/, - config, - supported_versions), - unique_remote_server_id_(unique_remote_server_id), - perspective_(perspective), - packet_writer_(std::move(packet_writer)), + const QuicClock* clock) + : QuicSession(connection.get(), visitor, config, supported_versions), connection_(std::move(connection)), - helper_(helper), - clock_(clock) { - packet_writer_->set_connection(connection_.get()); - - // Initialization with default crypto configuration. - if (perspective_ == Perspective::IS_CLIENT) { - std::unique_ptr<ProofVerifier> proof_verifier(new InsecureProofVerifier); - quic_crypto_client_config_ = QuicMakeUnique<QuicCryptoClientConfig>( - std::move(proof_verifier), TlsClientHandshaker::CreateSslCtx()); - quic_crypto_client_config_->set_pad_inchoate_hello(false); - quic_crypto_client_config_->set_pad_full_hello(false); - } else { - std::unique_ptr<ProofSource> proof_source(new DummyProofSource); - // Generate a random source address token secret. For long-running servers - // it's better to not regenerate it for each connection to enable zero-RTT - // handshakes, but for transient clients it does not matter. - char source_address_token_secret[kInputKeyingMaterialLength]; - helper_->GetRandomGenerator()->RandBytes(source_address_token_secret, - kInputKeyingMaterialLength); - quic_crypto_server_config_ = QuicMakeUnique<QuicCryptoServerConfig>( - QuicString(source_address_token_secret, kInputKeyingMaterialLength), - helper_->GetRandomGenerator(), std::move(proof_source), - KeyExchangeSource::Default(), TlsServerHandshaker::CreateSslCtx()); - - // Effectively disables the anti-amplification measures (we don't need - // them because we use ICE, and we need to disable them because we disable - // padding of crypto packets). - // This multiplier must be large enough so that the crypto handshake packet - // (approx. 300 bytes) multiplied by this multiplier is larger than a fully - // sized packet (currently 1200 bytes). - // 1500 is a bit extreme: if you can imagine sending a 1 byte packet, and - // your largest MTU would be below 1500 bytes, 1500*1 >= - // any_packet_that_you_can_imagine_sending. - // (again, we hardcode packet size to 1200, so we are not dealing with jumbo - // frames). - quic_crypto_server_config_->set_chlo_multiplier(1500); - - // We are sending small client hello, we must not validate its size. - quic_crypto_server_config_->set_validate_chlo_size(false); - - // We run QUIC over ICE, and ICE is verifying remote side with STUN pings. - // We disable source address token validation in order to allow for 0-rtt - // setup (plus source ip addresses are changing even during the connection - // when ICE is used). - quic_crypto_server_config_->set_validate_source_address_token(false); - - // Provide server with serialized config string to prove ownership. - QuicCryptoServerConfig::ConfigOptions options; - // The |message| is used to handle the return value of AddDefaultConfig - // which is raw pointer of the CryptoHandshakeMessage. - std::unique_ptr<CryptoHandshakeMessage> message( - quic_crypto_server_config_->AddDefaultConfig( - helper_->GetRandomGenerator(), helper_->GetClock(), options)); - quic_crypto_server_config_->set_pad_rej(false); - quic_crypto_server_config_->set_pad_shlo(false); - } + clock_(clock), + per_packet_options_(QuicMakeUnique<QuartcPerPacketOptions>()) { + per_packet_options_->connection = connection_.get(); + connection_->set_per_packet_options(per_packet_options_.get()); } QuartcSession::~QuartcSession() {} -const QuicCryptoStream* QuartcSession::GetCryptoStream() const { - return crypto_stream_.get(); -} - -QuicCryptoStream* QuartcSession::GetMutableCryptoStream() { - return crypto_stream_.get(); -} - QuartcStream* QuartcSession::CreateOutgoingBidirectionalStream() { // Use default priority for incoming QUIC streams. // TODO(zhihuang): Determine if this value is correct. @@ -234,7 +65,12 @@ void QuartcSession::ProcessSendMessageQueue() { while (!send_message_queue_.empty()) { - MessageResult result = SendMessage(send_message_queue_.front()); + struct iovec iov = {const_cast<char*>(send_message_queue_.front().data()), + send_message_queue_.front().length()}; + QuicMemSliceStorage storage( + &iov, 1, connection()->helper()->GetStreamSendBufferAllocator(), + send_message_queue_.front().length()); + MessageResult result = SendMessage(storage.ToSpan()); const size_t message_size = send_message_queue_.front().size(); @@ -346,45 +182,6 @@ QuicSession::OnConnectionClosed(error, error_details, source); DCHECK(session_delegate_); session_delegate_->OnConnectionClosed(error, error_details, source); - - // The session may be deleted after OnConnectionClosed(), so |this| must be - // removed from the packet transport's delegate before it is deleted. - packet_writer_->SetPacketTransportDelegate(nullptr); -} - -void QuartcSession::SetPreSharedKey(QuicStringPiece key) { - if (perspective_ == Perspective::IS_CLIENT) { - quic_crypto_client_config_->set_pre_shared_key(key); - } else { - quic_crypto_server_config_->set_pre_shared_key(key); - } -} - -void QuartcSession::StartCryptoHandshake() { - if (perspective_ == Perspective::IS_CLIENT) { - QuicServerId server_id(unique_remote_server_id_, kQuicServerPort, - /*privacy_mode_enabled=*/false); - QuicCryptoClientStream* crypto_stream = new QuicCryptoClientStream( - server_id, this, - quic_crypto_client_config_->proof_verifier()->CreateDefaultContext(), - quic_crypto_client_config_.get(), this); - crypto_stream_.reset(crypto_stream); - QuicSession::Initialize(); - crypto_stream->CryptoConnect(); - } else { - quic_compressed_certs_cache_.reset(new QuicCompressedCertsCache( - QuicCompressedCertsCache::kQuicCompressedCertsCacheSize)); - bool use_stateless_rejects_if_peer_supported = false; - QuicCryptoServerStream* crypto_stream = new QuicCryptoServerStream( - quic_crypto_server_config_.get(), quic_compressed_certs_cache_.get(), - use_stateless_rejects_if_peer_supported, this, &stream_helper_); - crypto_stream_.reset(crypto_stream); - QuicSession::Initialize(); - } - - // QUIC is ready to process incoming packets after QuicSession::Initialize(). - // Set the packet transport delegate to begin receiving packets. - packet_writer_->SetPacketTransportDelegate(this); } void QuartcSession::CloseConnection(const QuicString& details) { @@ -418,16 +215,6 @@ session_delegate_->OnMessageReceived(message); } -void QuartcSession::OnProofValid( - const QuicCryptoClientConfig::CachedState& cached) { - // TODO(zhihuang): Handle the proof verification. -} - -void QuartcSession::OnProofVerifyDetailsAvailable( - const ProofVerifyDetails& verify_details) { - // TODO(zhihuang): Handle the proof verification. -} - QuicStream* QuartcSession::CreateIncomingStream(QuicStreamId id) { return ActivateDataStream(CreateDataStream(id, QuicStream::kDefaultPriority)); } @@ -440,7 +227,8 @@ std::unique_ptr<QuartcStream> QuartcSession::CreateDataStream( QuicStreamId id, spdy::SpdyPriority priority) { - if (crypto_stream_ == nullptr || !crypto_stream_->encryption_established()) { + if (GetCryptoStream() == nullptr || + !GetCryptoStream()->encryption_established()) { // Encryption not active so no stream created return nullptr; } @@ -481,4 +269,124 @@ return raw; } +QuartcClientSession::QuartcClientSession( + std::unique_ptr<QuicConnection> connection, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + const QuicClock* clock, + std::unique_ptr<QuartcPacketWriter> packet_writer, + std::unique_ptr<QuicCryptoClientConfig> client_crypto_config, + QuicStringPiece server_crypto_config) + : QuartcSession(std::move(connection), + /*visitor=*/nullptr, + config, + supported_versions, + clock), + packet_writer_(std::move(packet_writer)), + client_crypto_config_(std::move(client_crypto_config)), + server_config_(server_crypto_config) { + DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_CLIENT); +} + +QuartcClientSession::~QuartcClientSession() { + // The client session is the packet transport delegate, so it must be unset + // before the session is deleted. + packet_writer_->SetPacketTransportDelegate(nullptr); +} + +void QuartcClientSession::Initialize() { + DCHECK(crypto_stream_) << "Do not call QuartcSession::Initialize(), call " + "StartCryptoHandshake() instead."; + QuartcSession::Initialize(); + + // QUIC is ready to process incoming packets after Initialize(). + // Set the packet transport delegate to begin receiving packets. + packet_writer_->SetPacketTransportDelegate(this); +} + +const QuicCryptoStream* QuartcClientSession::GetCryptoStream() const { + return crypto_stream_.get(); +} + +QuicCryptoStream* QuartcClientSession::GetMutableCryptoStream() { + return crypto_stream_.get(); +} + +void QuartcClientSession::StartCryptoHandshake() { + QuicServerId server_id(/*host=*/"", kQuicServerPort, + /*privacy_mode_enabled=*/false); + + if (!server_config_.empty()) { + QuicCryptoServerConfig::ConfigOptions options; + + QuicString error; + QuicWallTime now = clock()->WallNow(); + QuicCryptoClientConfig::CachedState::ServerConfigState result = + client_crypto_config_->LookupOrCreate(server_id)->SetServerConfig( + server_config_, now, + /*expiry_time=*/now.Add(QuicTime::Delta::Infinite()), &error); + + if (result == QuicCryptoClientConfig::CachedState::SERVER_CONFIG_VALID) { + DCHECK_EQ(error, ""); + client_crypto_config_->LookupOrCreate(server_id)->SetProof( + std::vector<QuicString>{kDummyCertName}, /*cert_sct=*/"", + /*chlo_hash=*/"", /*signature=*/"anything"); + } else { + LOG(DFATAL) << "Unable to set server config, error=" << error; + } + } + + crypto_stream_ = QuicMakeUnique<QuicCryptoClientStream>( + server_id, this, + client_crypto_config_->proof_verifier()->CreateDefaultContext(), + client_crypto_config_.get(), this); + Initialize(); + crypto_stream_->CryptoConnect(); +} + +void QuartcClientSession::OnProofValid( + const QuicCryptoClientConfig::CachedState& cached) { + // TODO(zhihuang): Handle the proof verification. +} + +void QuartcClientSession::OnProofVerifyDetailsAvailable( + const ProofVerifyDetails& verify_details) { + // TODO(zhihuang): Handle the proof verification. +} + +QuartcServerSession::QuartcServerSession( + std::unique_ptr<QuicConnection> connection, + Visitor* visitor, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + const QuicClock* clock, + const QuicCryptoServerConfig* server_crypto_config, + QuicCompressedCertsCache* const compressed_certs_cache, + QuicCryptoServerStream::Helper* const stream_helper) + : QuartcSession(std::move(connection), + visitor, + config, + supported_versions, + clock), + server_crypto_config_(server_crypto_config), + compressed_certs_cache_(compressed_certs_cache), + stream_helper_(stream_helper) { + DCHECK_EQ(QuartcSession::connection()->perspective(), Perspective::IS_SERVER); +} + +const QuicCryptoStream* QuartcServerSession::GetCryptoStream() const { + return crypto_stream_.get(); +} + +QuicCryptoStream* QuartcServerSession::GetMutableCryptoStream() { + return crypto_stream_.get(); +} + +void QuartcServerSession::StartCryptoHandshake() { + crypto_stream_ = QuicMakeUnique<QuicCryptoServerStream>( + server_crypto_config_, compressed_certs_cache_, + /*use_stateless_rejects_if_peer_supported=*/false, this, stream_helper_); + Initialize(); +} + } // namespace quic
diff --git a/quic/quartc/quartc_session.h b/quic/quartc/quartc_session.h index 411c94c..0c414d8 100644 --- a/quic/quartc/quartc_session.h +++ b/quic/quartc/quartc_session.h
@@ -20,43 +20,21 @@ namespace quic { -// A helper class is used by the QuicCryptoServerStream. -class QuartcCryptoServerStreamHelper : public QuicCryptoServerStream::Helper { - public: - QuicConnectionId GenerateConnectionIdForReject( - QuicTransportVersion version, - QuicConnectionId connection_id) const override; - - bool CanAcceptClientHello(const CryptoHandshakeMessage& message, - const QuicSocketAddress& client_address, - const QuicSocketAddress& peer_address, - const QuicSocketAddress& self_address, - QuicString* error_details) const override; -}; - // QuartcSession owns and manages a QUIC connection. class QUIC_EXPORT_PRIVATE QuartcSession : public QuicSession, - public QuartcPacketTransport::Delegate, - public QuicCryptoClientStream::ProofHandler { + public QuartcPacketTransport::Delegate { public: QuartcSession(std::unique_ptr<QuicConnection> connection, + Visitor* visitor, const QuicConfig& config, const ParsedQuicVersionVector& supported_versions, - const QuicString& unique_remote_server_id, - Perspective perspective, - QuicConnectionHelperInterface* helper, - const QuicClock* clock, - std::unique_ptr<QuartcPacketWriter> packet_writer); + const QuicClock* clock); QuartcSession(const QuartcSession&) = delete; QuartcSession& operator=(const QuartcSession&) = delete; ~QuartcSession() override; // QuicSession overrides. - QuicCryptoStream* GetMutableCryptoStream() override; - - const QuicCryptoStream* GetCryptoStream() const override; - QuartcStream* CreateOutgoingBidirectionalStream(); // Sends short unreliable message using quic message frame (message must fit @@ -81,7 +59,7 @@ // Return true if transport support message frame. bool CanSendMessage() const { - return connection()->transport_version() >= QUIC_VERSION_45; + return connection()->transport_version() > QUIC_VERSION_44; } void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override; @@ -96,12 +74,7 @@ ConnectionCloseSource source) override; // QuartcSession methods. - - // Sets a pre-shared key for use during the crypto handshake. Must be set - // before StartCryptoHandshake() is called. - void SetPreSharedKey(QuicStringPiece key); - - void StartCryptoHandshake(); + virtual void StartCryptoHandshake() = 0; // Closes the connection with the given human-readable error details. // The connection closes with the QUIC_CONNECTION_CANCELLED error code to @@ -171,15 +144,6 @@ void OnMessageReceived(QuicStringPiece message) override; - // ProofHandler overrides. - void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override; - - // Called by the client crypto handshake when proof verification details - // become available, either because proof verification is complete, or when - // cached details are used. - void OnProofVerifyDetailsAvailable( - const ProofVerifyDetails& verify_details) override; - // Returns number of queued (not sent) messages submitted by // SendOrQueueMessage. Messages are queued if connection is congestion // controlled. @@ -200,6 +164,8 @@ void ResetStream(QuicStreamId stream_id, QuicRstStreamErrorCode error); + const QuicClock* clock() { return clock_; } + private: std::unique_ptr<QuartcStream> InitializeDataStream( std::unique_ptr<QuartcStream> stream, @@ -207,32 +173,19 @@ void ProcessSendMessageQueue(); - // For crypto handshake. - std::unique_ptr<QuicCryptoStream> crypto_stream_; - const QuicString unique_remote_server_id_; - Perspective perspective_; - - // Packet writer used by |connection_|. - std::unique_ptr<QuartcPacketWriter> packet_writer_; - // Take ownership of the QuicConnection. Note: if |connection_| changes, // the new value of |connection_| must be given to |packet_writer_| before any // packets are written. Otherwise, |packet_writer_| will crash. std::unique_ptr<QuicConnection> connection_; - // Not owned by QuartcSession. From the QuartcFactory. - QuicConnectionHelperInterface* helper_; + // For recording packet receipt time const QuicClock* clock_; + // Not owned by QuartcSession. Delegate* session_delegate_ = nullptr; - // Used by QUIC crypto server stream to track most recently compressed certs. - std::unique_ptr<QuicCompressedCertsCache> quic_compressed_certs_cache_; - // This helper is needed when create QuicCryptoServerStream. - QuartcCryptoServerStreamHelper stream_helper_; - // Config for QUIC crypto client stream, used by the client. - std::unique_ptr<QuicCryptoClientConfig> quic_crypto_client_config_; - // Config for QUIC crypto server stream, used by the server. - std::unique_ptr<QuicCryptoServerConfig> quic_crypto_server_config_; + + // Options passed to the packet writer for each packet. + std::unique_ptr<QuartcPerPacketOptions> per_packet_options_; // Queue of pending messages sent by SendQuartcMessage that were not sent // yet or blocked by congestion control. Messages are queued in the order @@ -240,6 +193,94 @@ QuicDeque<QuicString> send_message_queue_; }; +class QUIC_EXPORT_PRIVATE QuartcClientSession + : public QuartcSession, + public QuicCryptoClientStream::ProofHandler { + public: + QuartcClientSession( + std::unique_ptr<QuicConnection> connection, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + const QuicClock* clock, + std::unique_ptr<QuartcPacketWriter> packet_writer, + std::unique_ptr<QuicCryptoClientConfig> client_crypto_config, + QuicStringPiece server_crypto_config); + QuartcClientSession(const QuartcClientSession&) = delete; + QuartcClientSession& operator=(const QuartcClientSession&) = delete; + + ~QuartcClientSession() override; + + // Initialize should not be called on a QuartcSession. Instead, call + // StartCryptoHandshake(). + // TODO(mellem): Move creation of the crypto stream into Initialize() and + // remove StartCryptoHandshake() to bring QuartcSession in line with other + // implementations of QuicSession, which can be started by calling + // Initialize(). + void Initialize() override; + + // Accessors for the client crypto stream. + QuicCryptoStream* GetMutableCryptoStream() override; + const QuicCryptoStream* GetCryptoStream() const override; + + // Initializes the session and sends a handshake. + void StartCryptoHandshake() override; + + // ProofHandler overrides. + void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override; + + // Called by the client crypto handshake when proof verification details + // become available, either because proof verification is complete, or when + // cached details are used. + void OnProofVerifyDetailsAvailable( + const ProofVerifyDetails& verify_details) override; + + private: + // Packet writer used by |connection_|. + std::unique_ptr<QuartcPacketWriter> packet_writer_; + + // Config for QUIC crypto stream. + std::unique_ptr<QuicCryptoClientConfig> client_crypto_config_; + + // Client perspective crypto stream. + std::unique_ptr<QuicCryptoClientStream> crypto_stream_; + + const QuicString server_config_; +}; + +class QUIC_EXPORT_PRIVATE QuartcServerSession : public QuartcSession { + public: + QuartcServerSession(std::unique_ptr<QuicConnection> connection, + Visitor* visitor, + const QuicConfig& config, + const ParsedQuicVersionVector& supported_versions, + const QuicClock* clock, + const QuicCryptoServerConfig* server_crypto_config, + QuicCompressedCertsCache* const compressed_certs_cache, + QuicCryptoServerStream::Helper* const stream_helper); + QuartcServerSession(const QuartcServerSession&) = delete; + QuartcServerSession& operator=(const QuartcServerSession&) = delete; + + // Accessors for the server crypto stream. + QuicCryptoStream* GetMutableCryptoStream() override; + const QuicCryptoStream* GetCryptoStream() const override; + + // Initializes the session and prepares to receive a handshake. + void StartCryptoHandshake() override; + + private: + // Config for QUIC crypto stream. + const QuicCryptoServerConfig* server_crypto_config_; + + // Used by QUIC crypto server stream to track most recently compressed certs. + QuicCompressedCertsCache* const compressed_certs_cache_; + + // This helper is needed to create QuicCryptoServerStream. + QuicCryptoServerStream::Helper* const stream_helper_; + + // Server perspective crypto stream. + std::unique_ptr<QuicCryptoServerStream> crypto_stream_; +}; + } // namespace quic #endif // QUICHE_QUIC_QUARTC_QUARTC_SESSION_H_
diff --git a/quic/quartc/quartc_session_test.cc b/quic/quartc/quartc_session_test.cc index 78efa9e..0ca9a58 100644 --- a/quic/quartc/quartc_session_test.cc +++ b/quic/quartc/quartc_session_test.cc
@@ -16,7 +16,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test_mem_slice_vector.h" #include "net/third_party/quiche/src/quic/quartc/counting_packet_filter.h" -#include "net/third_party/quiche/src/quic/quartc/quartc_factory.h" +#include "net/third_party/quiche/src/quic/quartc/quartc_endpoint.h" #include "net/third_party/quiche/src/quic/quartc/quartc_packet_writer.h" #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" @@ -27,8 +27,40 @@ namespace { +constexpr QuicTime::Delta kPropagationDelay = + QuicTime::Delta::FromMilliseconds(10); +// Propagation delay and a bit, but no more than full RTT. +constexpr QuicTime::Delta kPropagationDelayAndABit = + QuicTime::Delta::FromMilliseconds(12); + static QuicByteCount kDefaultMaxPacketSize = 1200; +class FakeQuartcEndpointDelegate : public QuartcEndpoint::Delegate { + public: + explicit FakeQuartcEndpointDelegate(QuartcSession::Delegate* session_delegate) + : session_delegate_(session_delegate) {} + + void OnSessionCreated(QuartcSession* session) override { + CHECK_EQ(session_, nullptr); + CHECK_NE(session, nullptr); + session_ = session; + session_->SetDelegate(session_delegate_); + session_->StartCryptoHandshake(); + } + + void OnConnectError(QuicErrorCode error, + const QuicString& error_details) override { + LOG(FATAL) << "Unexpected error during QuartcEndpoint::Connect(); error=" + << error << ", error_details=" << error_details; + } + + QuartcSession* session() { return session_; } + + private: + QuartcSession::Delegate* session_delegate_; + QuartcSession* session_ = nullptr; +}; + class FakeQuartcSessionDelegate : public QuartcSession::Delegate { public: explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate, @@ -140,49 +172,61 @@ client_server_link_ = QuicMakeUnique<simulator::SymmetricLink>( client_filter_.get(), server_transport_.get(), - QuicBandwidth::FromKBitsPerSecond(10 * 1000), - QuicTime::Delta::FromMilliseconds(10)); + QuicBandwidth::FromKBitsPerSecond(10 * 1000), kPropagationDelay); client_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>(); client_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>( client_stream_delegate_.get(), simulator_.GetClock()); + client_endpoint_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>( + client_session_delegate_.get()); server_stream_delegate_ = QuicMakeUnique<FakeQuartcStreamDelegate>(); server_session_delegate_ = QuicMakeUnique<FakeQuartcSessionDelegate>( server_stream_delegate_.get(), simulator_.GetClock()); + server_endpoint_delegate_ = QuicMakeUnique<FakeQuartcEndpointDelegate>( + server_session_delegate_.get()); - QuartcFactoryConfig factory_config; - factory_config.alarm_factory = simulator_.GetAlarmFactory(); - factory_config.clock = simulator_.GetClock(); - quartc_factory_ = QuicMakeUnique<QuartcFactory>(factory_config); + client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( + simulator_.GetAlarmFactory(), simulator_.GetClock(), + client_endpoint_delegate_.get(), /*serialized_server_config=*/""); + server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( + simulator_.GetAlarmFactory(), simulator_.GetClock(), + server_endpoint_delegate_.get()); } // Note that input session config will apply to both server and client. // Perspective and packet_transport will be overwritten. - void CreateClientAndServerSessions( - const QuartcSessionConfig& session_config) { - Init(); - - QuartcSessionConfig client_session_config = session_config; - client_session_config.perspective = Perspective::IS_CLIENT; - client_session_config.packet_transport = client_transport_.get(); - client_peer_ = quartc_factory_->CreateQuartcSession(client_session_config); - client_peer_->SetDelegate(client_session_delegate_.get()); + void CreateClientAndServerSessions(const QuartcSessionConfig& session_config, + bool init = true) { + if (init) { + Init(); + } QuartcSessionConfig server_session_config = session_config; - server_session_config.perspective = Perspective::IS_SERVER; server_session_config.packet_transport = server_transport_.get(); - server_peer_ = quartc_factory_->CreateQuartcSession(server_session_config); - server_peer_->SetDelegate(server_session_delegate_.get()); + server_endpoint_->Connect(server_session_config); + + QuartcSessionConfig client_session_config = session_config; + client_session_config.packet_transport = client_transport_.get(); + client_endpoint_->Connect(client_session_config); + + CHECK(simulator_.RunUntil([this] { + return client_endpoint_delegate_->session() != nullptr && + server_endpoint_delegate_->session() != nullptr; + })); + + client_peer_ = client_endpoint_delegate_->session(); + server_peer_ = server_endpoint_delegate_->session(); } // Runs all tasks scheduled in the next 200 ms. void RunTasks() { simulator_.RunFor(QuicTime::Delta::FromMilliseconds(200)); } - void StartHandshake() { - server_peer_->StartCryptoHandshake(); - client_peer_->StartCryptoHandshake(); - RunTasks(); + void AwaitHandshake() { + simulator_.RunUntil([this] { + return client_peer_->IsCryptoHandshakeConfirmed() && + server_peer_->IsCryptoHandshakeConfirmed(); + }); } // Test handshake establishment and sending/receiving of data for two @@ -270,7 +314,7 @@ ASSERT_TRUE(client_peer_->CanSendMessage()); QuartcSession* const peer_sending = - direction_from_server ? server_peer_.get() : client_peer_.get(); + direction_from_server ? server_peer_ : client_peer_; FakeQuartcSessionDelegate* const delegate_receiving = direction_from_server ? client_session_delegate_.get() @@ -334,51 +378,54 @@ protected: simulator::Simulator simulator_; - std::unique_ptr<QuartcFactory> quartc_factory_; - std::unique_ptr<simulator::SimulatedQuartcPacketTransport> client_transport_; std::unique_ptr<simulator::SimulatedQuartcPacketTransport> server_transport_; std::unique_ptr<simulator::CountingPacketFilter> client_filter_; std::unique_ptr<simulator::SymmetricLink> client_server_link_; - std::unique_ptr<QuartcSession> client_peer_; - std::unique_ptr<QuartcSession> server_peer_; - std::unique_ptr<FakeQuartcStreamDelegate> client_stream_delegate_; std::unique_ptr<FakeQuartcSessionDelegate> client_session_delegate_; + std::unique_ptr<FakeQuartcEndpointDelegate> client_endpoint_delegate_; std::unique_ptr<FakeQuartcStreamDelegate> server_stream_delegate_; std::unique_ptr<FakeQuartcSessionDelegate> server_session_delegate_; + std::unique_ptr<FakeQuartcEndpointDelegate> server_endpoint_delegate_; + + std::unique_ptr<QuartcClientEndpoint> client_endpoint_; + std::unique_ptr<QuartcServerEndpoint> server_endpoint_; + + QuartcSession* client_peer_ = nullptr; + QuartcSession* server_peer_ = nullptr; }; TEST_F(QuartcSessionTest, SendReceiveStreams) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); TestSendReceiveStreams(); } TEST_F(QuartcSessionTest, SendReceiveMessages) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); TestSendReceiveMessage(); } TEST_F(QuartcSessionTest, SendReceiveQueuedMessages) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); TestSendReceiveQueuedMessages(/*direction_from_server=*/true); TestSendReceiveQueuedMessages(/*direction_from_server=*/false); } TEST_F(QuartcSessionTest, SendMessageFails) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); TestSendLongMessage(); } TEST_F(QuartcSessionTest, TestCryptoHandshakeCanWriteTriggers) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); RunTasks(); @@ -399,10 +446,10 @@ } TEST_F(QuartcSessionTest, PreSharedKeyHandshake) { - CreateClientAndServerSessions(QuartcSessionConfig()); - client_peer_->SetPreSharedKey("foo"); - server_peer_->SetPreSharedKey("foo"); - StartHandshake(); + QuartcSessionConfig config; + config.pre_shared_key = "foo"; + CreateClientAndServerSessions(config); + AwaitHandshake(); TestSendReceiveStreams(); TestSendReceiveMessage(); } @@ -416,7 +463,7 @@ TEST_F(QuartcSessionTest, CancelQuartcStream) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); @@ -438,7 +485,7 @@ // SimulatedQuartcPacketTransport::last_packet_number(). TEST_F(QuartcSessionTest, WriterGivesPacketNumberToTransport) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); @@ -459,7 +506,7 @@ TEST_F(QuartcSessionTest, CloseConnection) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); @@ -471,7 +518,7 @@ TEST_F(QuartcSessionTest, StreamRetransmissionEnabled) { CreateClientAndServerSessions(QuartcSessionConfig()); - StartHandshake(); + AwaitHandshake(); ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); @@ -504,10 +551,15 @@ // message will be retransmitted to to probe for more bandwidth. client_peer_->connection()->set_fill_up_link_during_probing(false); - StartHandshake(); + AwaitHandshake(); ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed()); ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed()); + // The client sends an ACK for the crypto handshake next. This must be + // flushed before we set the filter to drop the next packet, in order to + // ensure that the filter drops a data-bearing packet instead of just an ack. + RunTasks(); + QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); QuicStreamId stream_id = stream->id(); stream->SetDelegate(client_stream_delegate_.get()); @@ -543,6 +595,85 @@ QUIC_STREAM_CANCELLED); } +TEST_F(QuartcSessionTest, ServerRegistersAsWriteBlocked) { + // Initialize client and server session, but with the server write-blocked. + Init(); + server_transport_->SetWritable(false); + CreateClientAndServerSessions(QuartcSessionConfig(), /*init=*/false); + + // Let the client send a few copies of the CHLO. The server can't respond, as + // it's still write-blocked. + RunTasks(); + + // Making the server's transport writable should trigger a callback that + // reaches the server session, allowing it to write packets. + server_transport_->SetWritable(true); + + // Now the server should respond with the SHLO, encryption should be + // established, and data should flow normally. + // Note that if the server is *not* correctly registered as write-blocked, + // it will crash here (see b/124527328 for details). + AwaitHandshake(); + TestSendReceiveStreams(); +} + +TEST_F(QuartcSessionTest, PreSharedKeyHandshakeIs0RTT) { + QuartcSessionConfig session_config; + session_config.pre_shared_key = "foo"; + + Init(); + + QuartcSessionConfig server_session_config = session_config; + server_session_config.packet_transport = server_transport_.get(); + server_endpoint_->Connect(server_session_config); + + client_endpoint_ = absl::make_unique<QuartcClientEndpoint>( + simulator_.GetAlarmFactory(), simulator_.GetClock(), + client_endpoint_delegate_.get(), + // This is the key line here. It passes through the server config + // from the server to the client. + server_endpoint_->server_crypto_config()); + + QuartcSessionConfig client_session_config = session_config; + QuicString(); + client_session_config.packet_transport = client_transport_.get(); + client_endpoint_->Connect(client_session_config); + + // Running for 1ms. This is shorter than the RTT, so the + // client session should be created, but server won't be created yet. + simulator_.RunFor(QuicTime::Delta::FromMilliseconds(1)); + + client_peer_ = client_endpoint_delegate_->session(); + server_peer_ = server_endpoint_delegate_->session(); + + ASSERT_NE(client_peer_, nullptr); + ASSERT_EQ(server_peer_, nullptr); + + // Write data to the client before running tasks. This should be sent by the + // client and received by the server if the handshake is 0RTT. + // If this test fails, add 'RunTasks()' above, and see what error is sent + // by the server in the rejection message. + QuartcStream* stream = client_peer_->CreateOutgoingBidirectionalStream(); + ASSERT_NE(stream, nullptr); + QuicStreamId stream_id = stream->id(); + stream->SetDelegate(client_stream_delegate_.get()); + + char message[] = "Hello in 0RTTs!"; + test::QuicTestMemSliceVector data({std::make_pair(message, strlen(message))}); + stream->WriteMemSlices(data.span(), /*fin=*/false); + + // This will now run the rest of the connection. But the + // Server peer will receive the CHLO and message after 1 delay. + simulator_.RunFor(kPropagationDelayAndABit); + + // If we can decrypt the data, it means that 0 rtt was successful. + // This is because we waited only a propagation delay. So if the decryption + // failed, we would send sREJ instead of SHLO, but it wouldn't be delivered to + // the client yet. + ASSERT_TRUE(server_stream_delegate_->has_data()); + EXPECT_EQ(server_stream_delegate_->data()[stream_id], message); +} + } // namespace } // namespace quic
diff --git a/quic/quartc/quartc_stream.cc b/quic/quartc/quartc_stream.cc index a0be2c7..49ade23 100644 --- a/quic/quartc/quartc_stream.cc +++ b/quic/quartc/quartc_stream.cc
@@ -76,14 +76,15 @@ bool QuartcStream::OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length, bool fin_acked, - QuicTime::Delta ack_delay_time) { + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length) { // Previous losses of acked data are no longer relevant to the retransmission // count. Once data is acked, it will never be retransmitted. lost_frame_counter_.RemoveInterval( QuicInterval<QuicStreamOffset>(offset, offset + data_length)); return QuicStream::OnStreamFrameAcked(offset, data_length, fin_acked, - ack_delay_time); + ack_delay_time, newly_acked_length); } void QuartcStream::OnStreamFrameRetransmitted(QuicStreamOffset offset,
diff --git a/quic/quartc/quartc_stream.h b/quic/quartc/quartc_stream.h index d34c2c2..e30afbf 100644 --- a/quic/quartc/quartc_stream.h +++ b/quic/quartc/quartc_stream.h
@@ -47,7 +47,8 @@ bool OnStreamFrameAcked(QuicStreamOffset offset, QuicByteCount data_length, bool fin_acked, - QuicTime::Delta ack_delay_time) override; + QuicTime::Delta ack_delay_time, + QuicByteCount* newly_acked_length) override; void OnStreamFrameRetransmitted(QuicStreamOffset offset, QuicByteCount data_length,
diff --git a/quic/quartc/quartc_stream_test.cc b/quic/quartc/quartc_stream_test.cc index 075aca1..87e6170 100644 --- a/quic/quartc/quartc_stream_test.cc +++ b/quic/quartc/quartc_stream_test.cc
@@ -138,9 +138,7 @@ return WriteResult(WRITE_STATUS_ERROR, 0); } - bool IsWriteBlockedDataBuffered() const override { return false; } - - bool IsWriteBlocked() const override { return false; }; + bool IsWriteBlocked() const override { return false; } void SetWritable() override {} @@ -563,8 +561,10 @@ // Ack bytes [0, 7). These bytes should be pruned from the data tracked by // the stream. - stream_->OnStreamFrameAcked(0, 7, false, - QuicTime::Delta::FromMilliseconds(1)); + QuicByteCount newly_acked_length = 0; + stream_->OnStreamFrameAcked(0, 7, false, QuicTime::Delta::FromMilliseconds(1), + &newly_acked_length); + EXPECT_EQ(7u, newly_acked_length); stream_->OnCanWrite(); EXPECT_EQ("Foo barFoo bar", write_buffer_);
diff --git a/quic/quartc/simulated_packet_transport.cc b/quic/quartc/simulated_packet_transport.cc index 66bfb2b..5c0d374 100644 --- a/quic/quartc/simulated_packet_transport.cc +++ b/quic/quartc/simulated_packet_transport.cc
@@ -24,6 +24,9 @@ int SimulatedQuartcPacketTransport::Write(const char* buffer, size_t buf_len, const PacketInfo& info) { + if (!writable_) { + return 0; + } if (egress_queue_.bytes_queued() + buf_len > egress_queue_.capacity()) { return 0; } @@ -69,16 +72,24 @@ } void SimulatedQuartcPacketTransport::OnPacketDequeued() { - if (delegate_) { + if (delegate_ && writable_) { delegate_->OnTransportCanWrite(); } } void SimulatedQuartcPacketTransport::Act() { - if (delegate_) { + if (delegate_ && writable_) { delegate_->OnTransportCanWrite(); } } +void SimulatedQuartcPacketTransport::SetWritable(bool writable) { + writable_ = writable; + if (writable_) { + // May need to call |Delegate::OnTransportCanWrite|. + Schedule(clock_->Now()); + } +} + } // namespace simulator } // namespace quic
diff --git a/quic/quartc/simulated_packet_transport.h b/quic/quartc/simulated_packet_transport.h index 5f1c468..1b190a0 100644 --- a/quic/quartc/simulated_packet_transport.h +++ b/quic/quartc/simulated_packet_transport.h
@@ -53,6 +53,13 @@ // callback to unblock it.) void Act() override; + // Changes whether the transport is writable. If |writable| is false, the + // transport will reject calls to |Write| and will not call + // |Delegate::OnTransportCanWrite|. If |writable| is true, the transport will + // allow calls to |Write| and will call |Delegate::OnTransportCanWrite| + // whenever it is able to write another packet. + void SetWritable(bool writable); + // Last packet number sent over this simulated transport. // TODO(b/112561077): Reorganize tests so that this method can be deleted. // This exists purely for use by quartc_session_test.cc, to test that the @@ -64,6 +71,10 @@ Delegate* delegate_ = nullptr; Queue egress_queue_; QuicPacketNumber last_packet_number_; + + // Controls whether the transport is considered to be writable. Used to + // simulate behavior that arises when the transport is blocked. + bool writable_ = true; }; } // namespace simulator
diff --git a/quic/test_tools/crypto_test_utils.cc b/quic/test_tools/crypto_test_utils.cc index fd270c3..e36ba52 100644 --- a/quic/test_tools/crypto_test_utils.cc +++ b/quic/test_tools/crypto_test_utils.cc
@@ -5,6 +5,7 @@ #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" #include <memory> +#include <string> #include "third_party/boringssl/src/include/openssl/bn.h" #include "third_party/boringssl/src/include/openssl/ec.h" @@ -507,11 +508,19 @@ const CryptoHandshakeMessage& message, Perspective perspective) { const QuicData& data = message.GetSerialized(); - QuicStreamFrame frame( - QuicUtils::GetCryptoStreamId( - QuicStreamPeer::session(stream)->connection()->transport_version()), - false, stream->stream_bytes_read(), data.AsStringPiece()); - stream->OnStreamFrame(frame); + QuicSession* session = QuicStreamPeer::session(stream); + if (session->connection()->transport_version() < QUIC_VERSION_47) { + QuicStreamFrame frame(QuicUtils::GetCryptoStreamId( + session->connection()->transport_version()), + false, stream->crypto_bytes_read(), + data.AsStringPiece()); + stream->OnStreamFrame(frame); + } else { + EncryptionLevel level = session->connection()->last_decrypted_level(); + QuicCryptoFrame frame(level, stream->BytesReadOnLevel(level), + data.AsStringPiece()); + stream->OnCryptoFrame(frame); + } } void CommunicateHandshakeMessages(PacketSavingConnection* client_conn, @@ -589,7 +598,7 @@ uint64_t LeafCertHashForTesting() { QuicReferenceCountedPointer<ProofSource::Chain> chain; - QuicSocketAddress server_address; + QuicSocketAddress server_address(QuicIpAddress::Any4(), 42); QuicCryptoProof proof; std::unique_ptr<ProofSource> proof_source(ProofSourceForTesting()); @@ -724,7 +733,7 @@ QuicFramer* server_framer = QuicConnectionPeer::GetFramer( QuicStreamPeer::session(server)->connection()); const QuicEncrypter* client_encrypter( - QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_INITIAL)); + QuicFramerPeer::GetEncrypter(client_framer, ENCRYPTION_ZERO_RTT)); const QuicDecrypter* client_decrypter( QuicStreamPeer::session(client)->connection()->decrypter()); const QuicEncrypter* client_forward_secure_encrypter( @@ -732,7 +741,7 @@ const QuicDecrypter* client_forward_secure_decrypter( QuicStreamPeer::session(client)->connection()->alternative_decrypter()); const QuicEncrypter* server_encrypter( - QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_INITIAL)); + QuicFramerPeer::GetEncrypter(server_framer, ENCRYPTION_ZERO_RTT)); const QuicDecrypter* server_decrypter( QuicStreamPeer::session(server)->connection()->decrypter()); const QuicEncrypter* server_forward_secure_encrypter( @@ -936,6 +945,7 @@ break; } QuicConnectionPeer::SwapCrypters(dest_conn, framer.framer()); + dest_conn->OnDecryptedPacket(framer.last_decrypted_level()); if (dest_stream->handshake_protocol() == PROTOCOL_TLS1_3) { // Try to process the packet with a framer that only has the NullDecrypter @@ -961,6 +971,9 @@ for (const auto& stream_frame : framer.stream_frames()) { dest_stream->OnStreamFrame(*stream_frame); } + for (const auto& crypto_frame : framer.crypto_frames()) { + dest_stream->OnCryptoFrame(*crypto_frame); + } } *inout_packet_index = index;
diff --git a/quic/test_tools/crypto_test_utils_test.cc b/quic/test_tools/crypto_test_utils_test.cc index 601103c..39a3b23 100644 --- a/quic/test_tools/crypto_test_utils_test.cc +++ b/quic/test_tools/crypto_test_utils_test.cc
@@ -113,7 +113,7 @@ QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), crypto_test_utils::ProofSourceForTesting(), KeyExchangeSource::Default(), TlsServerHandshaker::CreateSslCtx()); - QuicSocketAddress server_addr; + QuicSocketAddress server_addr(QuicIpAddress::Any4(), 5); QuicSocketAddress client_addr(QuicIpAddress::Loopback4(), 1); QuicReferenceCountedPointer<QuicSignedServerConfig> signed_config( new QuicSignedServerConfig);
diff --git a/quic/test_tools/fuzzing/quic_framer_fuzzer.cc b/quic/test_tools/fuzzing/quic_framer_fuzzer.cc index 1d83802..a14f410 100644 --- a/quic/test_tools/fuzzing/quic_framer_fuzzer.cc +++ b/quic/test_tools/fuzzing/quic_framer_fuzzer.cc
@@ -1,3 +1,7 @@ +// 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. + #include "base/commandlineflags.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_framer.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake_message.h"
diff --git a/quic/test_tools/mock_quic_dispatcher.cc b/quic/test_tools/mock_quic_dispatcher.cc index 621a161..d7ccf2c 100644 --- a/quic/test_tools/mock_quic_dispatcher.cc +++ b/quic/test_tools/mock_quic_dispatcher.cc
@@ -10,7 +10,7 @@ namespace test { MockQuicDispatcher::MockQuicDispatcher( - const QuicConfig& config, + const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/test_tools/mock_quic_dispatcher.h b/quic/test_tools/mock_quic_dispatcher.h index 394a90b..93acda9 100644 --- a/quic/test_tools/mock_quic_dispatcher.h +++ b/quic/test_tools/mock_quic_dispatcher.h
@@ -19,7 +19,7 @@ class MockQuicDispatcher : public QuicSimpleDispatcher { public: MockQuicDispatcher( - const QuicConfig& config, + const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/test_tools/packet_dropping_test_writer.cc b/quic/test_tools/packet_dropping_test_writer.cc index d296367..87935d5 100644 --- a/quic/test_tools/packet_dropping_test_writer.cc +++ b/quic/test_tools/packet_dropping_test_writer.cc
@@ -246,7 +246,7 @@ options(std::move(options)), send_time(send_time) {} -PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() {} +PacketDroppingTestWriter::DelayedWrite::~DelayedWrite() = default; } // namespace test } // namespace quic
diff --git a/quic/test_tools/packet_dropping_test_writer.h b/quic/test_tools/packet_dropping_test_writer.h index 404be81..51b3fc7 100644 --- a/quic/test_tools/packet_dropping_test_writer.h +++ b/quic/test_tools/packet_dropping_test_writer.h
@@ -12,6 +12,7 @@ #include "net/third_party/quiche/src/quic/core/quic_alarm.h" #include "net/third_party/quiche/src/quic/core/quic_packet_writer_wrapper.h" #include "net/third_party/quiche/src/quic/platform/api/quic_clock.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_client.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" @@ -117,9 +118,7 @@ } // Useful for reproducing very flaky issues. - ABSL_ATTRIBUTE_UNUSED void set_seed(uint64_t seed) { - simple_random_.set_seed(seed); - } + QUIC_UNUSED void set_seed(uint64_t seed) { simple_random_.set_seed(seed); } private: // Writes out the next packet to the contained writer and returns the time
diff --git a/quic/test_tools/quic_framer_peer.cc b/quic/test_tools/quic_framer_peer.cc index 20cbc49..89b0170 100644 --- a/quic/test_tools/quic_framer_peer.cc +++ b/quic/test_tools/quic_framer_peer.cc
@@ -213,17 +213,18 @@ } // static -bool QuicFramerPeer::AppendMaxStreamIdFrame(QuicFramer* framer, - const QuicMaxStreamIdFrame& frame, - QuicDataWriter* writer) { - return framer->AppendMaxStreamIdFrame(frame, writer); +bool QuicFramerPeer::AppendMaxStreamsFrame(QuicFramer* framer, + const QuicMaxStreamIdFrame& frame, + QuicDataWriter* writer) { + return framer->AppendMaxStreamsFrame(frame, writer); } // static -bool QuicFramerPeer::ProcessMaxStreamIdFrame(QuicFramer* framer, - QuicDataReader* reader, - QuicMaxStreamIdFrame* frame) { - return framer->ProcessMaxStreamIdFrame(reader, frame); +bool QuicFramerPeer::ProcessMaxStreamsFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicMaxStreamIdFrame* frame, + uint64_t frame_type) { + return framer->ProcessMaxStreamsFrame(reader, frame, frame_type); } // static @@ -255,19 +256,19 @@ } // static -bool QuicFramerPeer::AppendStreamIdBlockedFrame( +bool QuicFramerPeer::AppendStreamsBlockedFrame( QuicFramer* framer, const QuicStreamIdBlockedFrame& frame, QuicDataWriter* writer) { - return framer->AppendStreamIdBlockedFrame(frame, writer); + return framer->AppendStreamsBlockedFrame(frame, writer); } // static -bool QuicFramerPeer::ProcessStreamIdBlockedFrame( - QuicFramer* framer, - QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame) { - return framer->ProcessStreamIdBlockedFrame(reader, frame); +bool QuicFramerPeer::ProcessStreamsBlockedFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicStreamIdBlockedFrame* frame, + uint64_t frame_type) { + return framer->ProcessStreamsBlockedFrame(reader, frame, frame_type); } // static
diff --git a/quic/test_tools/quic_framer_peer.h b/quic/test_tools/quic_framer_peer.h index 1fa7351..cfe259a 100644 --- a/quic/test_tools/quic_framer_peer.h +++ b/quic/test_tools/quic_framer_peer.h
@@ -116,12 +116,13 @@ static bool ProcessMaxStreamDataFrame(QuicFramer* framer, QuicDataReader* reader, QuicWindowUpdateFrame* frame); - static bool AppendMaxStreamIdFrame(QuicFramer* framer, - const QuicMaxStreamIdFrame& frame, - QuicDataWriter* writer); - static bool ProcessMaxStreamIdFrame(QuicFramer* framer, - QuicDataReader* reader, - QuicMaxStreamIdFrame* frame); + static bool AppendMaxStreamsFrame(QuicFramer* framer, + const QuicMaxStreamIdFrame& frame, + QuicDataWriter* writer); + static bool ProcessMaxStreamsFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicMaxStreamIdFrame* frame, + uint64_t frame_type); static bool AppendIetfBlockedFrame(QuicFramer* framer, const QuicBlockedFrame& frame, QuicDataWriter* writer); @@ -136,12 +137,13 @@ QuicDataReader* reader, QuicBlockedFrame* frame); - static bool AppendStreamIdBlockedFrame(QuicFramer* framer, - const QuicStreamIdBlockedFrame& frame, - QuicDataWriter* writer); - static bool ProcessStreamIdBlockedFrame(QuicFramer* framer, - QuicDataReader* reader, - QuicStreamIdBlockedFrame* frame); + static bool AppendStreamsBlockedFrame(QuicFramer* framer, + const QuicStreamIdBlockedFrame& frame, + QuicDataWriter* writer); + static bool ProcessStreamsBlockedFrame(QuicFramer* framer, + QuicDataReader* reader, + QuicStreamIdBlockedFrame* frame, + uint64_t frame_type); static bool AppendNewConnectionIdFrame(QuicFramer* framer, const QuicNewConnectionIdFrame& frame,
diff --git a/quic/test_tools/quic_packet_creator_peer.cc b/quic/test_tools/quic_packet_creator_peer.cc index efcda92..51d9588 100644 --- a/quic/test_tools/quic_packet_creator_peer.cc +++ b/quic/test_tools/quic_packet_creator_peer.cc
@@ -43,6 +43,18 @@ return creator->GetPacketNumberLength(); } +// static +QuicVariableLengthIntegerLength +QuicPacketCreatorPeer::GetRetryTokenLengthLength(QuicPacketCreator* creator) { + return creator->GetRetryTokenLengthLength(); +} + +// static +QuicVariableLengthIntegerLength QuicPacketCreatorPeer::GetLengthLength( + QuicPacketCreator* creator) { + return creator->GetLengthLength(); +} + void QuicPacketCreatorPeer::SetPacketNumber(QuicPacketCreator* creator, uint64_t s) { DCHECK_NE(0u, s);
diff --git a/quic/test_tools/quic_packet_creator_peer.h b/quic/test_tools/quic_packet_creator_peer.h index 94c461a..c637ac2 100644 --- a/quic/test_tools/quic_packet_creator_peer.h +++ b/quic/test_tools/quic_packet_creator_peer.h
@@ -27,6 +27,10 @@ QuicPacketNumberLength packet_number_length); static QuicPacketNumberLength GetPacketNumberLength( QuicPacketCreator* creator); + static QuicVariableLengthIntegerLength GetRetryTokenLengthLength( + QuicPacketCreator* creator); + static QuicVariableLengthIntegerLength GetLengthLength( + QuicPacketCreator* creator); static void SetPacketNumber(QuicPacketCreator* creator, uint64_t s); static void ClearPacketNumber(QuicPacketCreator* creator); static void FillPacketHeader(QuicPacketCreator* creator,
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.cc b/quic/test_tools/quic_sent_packet_manager_peer.cc index 469fa40..3057e5e 100644 --- a/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -8,6 +8,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h" namespace quic { namespace test { @@ -41,7 +42,8 @@ void QuicSentPacketManagerPeer::SetPerspective( QuicSentPacketManager* sent_packet_manager, Perspective perspective) { - sent_packet_manager->perspective_ = perspective; + QuicUnackedPacketMapPeer::SetPerspective( + &sent_packet_manager->unacked_packets_, perspective); } // static
diff --git a/quic/test_tools/quic_spdy_session_peer.cc b/quic/test_tools/quic_spdy_session_peer.cc index b84a7da..b739fa1 100644 --- a/quic/test_tools/quic_spdy_session_peer.cc +++ b/quic/test_tools/quic_spdy_session_peer.cc
@@ -50,55 +50,15 @@ } // static -size_t QuicSpdySessionPeer::WriteHeadersImpl( +size_t QuicSpdySessionPeer::WriteHeadersOnHeadersStream( QuicSpdySession* session, QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin, - int weight, - QuicStreamId parent_stream_id, - bool exclusive, + spdy::SpdyPriority priority, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - return session->WriteHeadersImpl(id, std::move(headers), fin, weight, - parent_stream_id, exclusive, - std::move(ack_listener)); -} - -// static -QuicStreamId QuicSpdySessionPeer::StreamIdDelta( - const QuicSpdySession& session) { - return QuicUtils::StreamIdDelta(session.connection()->transport_version()); -} - -// static -QuicStreamId QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - const QuicSpdySession& session, - int n) { - return QuicUtils::GetFirstBidirectionalStreamId( - session.connection()->transport_version(), - Perspective::IS_CLIENT) + - // + 1 because spdy_session contains headers stream. - QuicSpdySessionPeer::StreamIdDelta(session) * (n + 1); -} - -// static -QuicStreamId QuicSpdySessionPeer::GetNthServerInitiatedBidirectionalStreamId( - const QuicSpdySession& session, - int n) { - return QuicUtils::GetFirstBidirectionalStreamId( - session.connection()->transport_version(), - Perspective::IS_SERVER) + - QuicSpdySessionPeer::StreamIdDelta(session) * n; -} - -// static -QuicStreamId QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( - const QuicSpdySession& session, - int n) { - return QuicUtils::GetFirstUnidirectionalStreamId( - session.connection()->transport_version(), - Perspective::IS_SERVER) + - QuicSpdySessionPeer::StreamIdDelta(session) * n; + return session->WriteHeadersOnHeadersStream( + id, std::move(headers), fin, priority, std::move(ack_listener)); } } // namespace test
diff --git a/quic/test_tools/quic_spdy_session_peer.h b/quic/test_tools/quic_spdy_session_peer.h index e0dbddc..1993ec5 100644 --- a/quic/test_tools/quic_spdy_session_peer.h +++ b/quic/test_tools/quic_spdy_session_peer.h
@@ -35,30 +35,13 @@ static void SetMaxUncompressedHeaderBytes( QuicSpdySession* session, size_t set_max_uncompressed_header_bytes); - static size_t WriteHeadersImpl( + static size_t WriteHeadersOnHeadersStream( QuicSpdySession* session, QuicStreamId id, spdy::SpdyHeaderBlock headers, bool fin, - int weight, - QuicStreamId parent_stream_id, - bool exclusive, + spdy::SpdyPriority priority, QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); - // Helper functions for stream ids, to allow test logic to abstract - // over the HTTP stream numbering scheme (i.e. whether one or - // two QUIC streams are used per HTTP transaction). - static QuicStreamId StreamIdDelta(const QuicSpdySession& session); - // n should start at 0. - static QuicStreamId GetNthClientInitiatedBidirectionalStreamId( - const QuicSpdySession& session, - int n); - // n should start at 0. - static QuicStreamId GetNthServerInitiatedBidirectionalStreamId( - const QuicSpdySession& session, - int n); - static QuicStreamId GetNthServerInitiatedUnidirectionalStreamId( - const QuicSpdySession& session, - int n); }; } // namespace test
diff --git a/quic/test_tools/quic_spdy_stream_peer.cc b/quic/test_tools/quic_spdy_stream_peer.cc new file mode 100644 index 0000000..6632ec1 --- /dev/null +++ b/quic/test_tools/quic_spdy_stream_peer.cc
@@ -0,0 +1,26 @@ +// 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. + +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_stream_peer.h" + +#include "net/third_party/quiche/src/quic/core/http/quic_spdy_stream.h" + +namespace quic { +namespace test { + +// static +void QuicSpdyStreamPeer::set_ack_listener( + QuicSpdyStream* stream, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { + stream->set_ack_listener(std::move(ack_listener)); +} + +// static +const QuicIntervalSet<QuicStreamOffset>& +QuicSpdyStreamPeer::unacked_frame_headers_offsets(QuicSpdyStream* stream) { + return stream->unacked_frame_headers_offsets(); +} + +} // namespace test +} // namespace quic
diff --git a/quic/test_tools/quic_spdy_stream_peer.h b/quic/test_tools/quic_spdy_stream_peer.h new file mode 100644 index 0000000..7b3fe7c --- /dev/null +++ b/quic/test_tools/quic_spdy_stream_peer.h
@@ -0,0 +1,31 @@ +// 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_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_ +#define QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_ + +#include "net/third_party/quiche/src/quic/core/quic_ack_listener_interface.h" +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" + +namespace quic { + +class QuicSpdyStream; + +namespace test { + +class QuicSpdyStreamPeer { + public: + static void set_ack_listener( + QuicSpdyStream* stream, + QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); + static const QuicIntervalSet<QuicStreamOffset>& unacked_frame_headers_offsets( + QuicSpdyStream* stream); +}; + +} // namespace test + +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_SPDY_STREAM_PEER_H_
diff --git a/quic/test_tools/quic_stream_peer.cc b/quic/test_tools/quic_stream_peer.cc index e512ba4..7607523 100644 --- a/quic/test_tools/quic_stream_peer.cc +++ b/quic/test_tools/quic_stream_peer.cc
@@ -87,12 +87,5 @@ return stream->send_buffer_; } -// static -void QuicStreamPeer::set_ack_listener( - QuicStream* stream, - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - stream->set_ack_listener(std::move(ack_listener)); -} - } // namespace test } // namespace quic
diff --git a/quic/test_tools/quic_stream_peer.h b/quic/test_tools/quic_stream_peer.h index e1ba33a..e0058ba 100644 --- a/quic/test_tools/quic_stream_peer.h +++ b/quic/test_tools/quic_stream_peer.h
@@ -48,10 +48,6 @@ static QuicSession* session(QuicStream* stream); static QuicStreamSendBuffer& SendBuffer(QuicStream* stream); - - static void set_ack_listener( - QuicStream* stream, - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener); }; } // namespace test
diff --git a/quic/test_tools/quic_test_client.cc b/quic/test_tools/quic_test_client.cc index a6298a6..213a7fd 100644 --- a/quic/test_tools/quic_test_client.cc +++ b/quic/test_tools/quic_test_client.cc
@@ -25,12 +25,10 @@ #include "net/third_party/quiche/src/quic/test_tools/quic_client_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_spdy_session_peer.h" -#include "net/third_party/quiche/src/quic/test_tools/quic_stream_peer.h" +#include "net/third_party/quiche/src/quic/test_tools/quic_spdy_stream_peer.h" #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h" #include "net/third_party/quiche/src/quic/tools/quic_url.h" -using spdy::SpdyHeaderBlock; - namespace quic { namespace test { namespace { @@ -341,9 +339,8 @@ session->connection(), QuicConnection::SEND_ACK_IF_PENDING); ssize_t ret = SendMessage(headers, "", /*fin=*/true, /*flush=*/false); - QuicStreamId stream_id = - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId(*session, - 0); + QuicStreamId stream_id = GetNthClientInitiatedBidirectionalStreamId( + session->connection()->transport_version(), 0); session->SendRstStream(stream_id, QUIC_STREAM_CANCELLED, 0); return ret; } @@ -385,18 +382,18 @@ if (stream == nullptr) { return 0; } - QuicStreamPeer::set_ack_listener(stream, ack_listener); + QuicSpdyStreamPeer::set_ack_listener(stream, ack_listener); ssize_t ret = 0; if (headers != nullptr) { - SpdyHeaderBlock spdy_headers(headers->Clone()); + spdy::SpdyHeaderBlock spdy_headers(headers->Clone()); if (spdy_headers[":authority"].as_string().empty()) { spdy_headers[":authority"] = client_->server_id().host(); } ret = stream->SendRequest(std::move(spdy_headers), body, fin); ++num_requests_; } else { - stream->WriteOrBufferBody(QuicString(body), fin, ack_listener); + stream->WriteOrBufferBody(QuicString(body), fin); ret = body.length(); } if (GetQuicReloadableFlag(enable_quic_stateless_reject_support)) { @@ -741,9 +738,9 @@ open_streams_.erase(id); } -bool QuicTestClient::CheckVary(const SpdyHeaderBlock& client_request, - const SpdyHeaderBlock& promise_request, - const SpdyHeaderBlock& promise_response) { +bool QuicTestClient::CheckVary(const spdy::SpdyHeaderBlock& client_request, + const spdy::SpdyHeaderBlock& promise_request, + const spdy::SpdyHeaderBlock& promise_response) { return true; }
diff --git a/quic/test_tools/quic_test_server.cc b/quic/test_tools/quic_test_server.cc index d2d33d6..220969b 100644 --- a/quic/test_tools/quic_test_server.cc +++ b/quic/test_tools/quic_test_server.cc
@@ -70,7 +70,7 @@ class QuicTestDispatcher : public QuicSimpleDispatcher { public: QuicTestDispatcher( - const QuicConfig& config, + const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper, @@ -165,7 +165,7 @@ QuicDispatcher* QuicTestServer::CreateQuicDispatcher() { return new QuicTestDispatcher( - config(), &crypto_config(), version_manager(), + &config(), &crypto_config(), version_manager(), QuicMakeUnique<QuicEpollConnectionHelper>(epoll_server(), QuicAllocator::BUFFER_POOL), std::unique_ptr<QuicCryptoServerStream::Helper>(
diff --git a/quic/test_tools/quic_test_utils.cc b/quic/test_tools/quic_test_utils.cc index da76b33..b10b509 100644 --- a/quic/test_tools/quic_test_utils.cc +++ b/quic/test_tools/quic_test_utils.cc
@@ -41,9 +41,6 @@ } QuicConnectionId TestConnectionId(uint64_t connection_number) { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return QuicConnectionIdFromUInt64(connection_number); - } const uint64_t connection_id64_net = QuicEndian::HostToNet64(connection_number); return QuicConnectionId(reinterpret_cast<const char*>(&connection_id64_net), @@ -51,9 +48,6 @@ } uint64_t TestConnectionIdToUInt64(QuicConnectionId connection_id) { - if (!QuicConnectionIdUseNetworkByteOrder()) { - return QuicConnectionIdToUInt64(connection_id); - } DCHECK_EQ(connection_id.length(), kQuicDefaultConnectionIdLength); uint64_t connection_id64_net = 0; memcpy(&connection_id64_net, connection_id.data(), @@ -124,14 +118,17 @@ const QuicFrames& frames, size_t packet_size) { char* buffer = new char[packet_size]; - size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size); + size_t length = framer->BuildDataPacket(header, frames, buffer, packet_size, + ENCRYPTION_NONE); DCHECK_NE(0u, length); // Re-construct the data packet with data ownership. return QuicMakeUnique<QuicPacket>( buffer, length, /* owns_buffer */ true, header.destination_connection_id_length, header.source_connection_id_length, header.version_flag, - header.nonce != nullptr, header.packet_number_length); + header.nonce != nullptr, header.packet_number_length, + header.retry_token_length_length, header.retry_token.length(), + header.length_length); } QuicString Sha1Hash(QuicStringPiece data) { @@ -221,6 +218,8 @@ return true; } +void NoOpFramerVisitor::OnCoalescedPacket(const QuicEncryptedPacket& packet) {} + bool NoOpFramerVisitor::OnStreamFrame(const QuicStreamFrame& frame) { return true; } @@ -433,6 +432,11 @@ ON_CALL(*this, OnError(_)) .WillByDefault( Invoke(this, &PacketSavingConnection::QuicConnection_OnError)); + ON_CALL(*this, SendCryptoData(_, _, _)) + .WillByDefault( + Invoke(this, &MockQuicConnection::QuicConnection_SendCryptoData)); + + SetSelfAddress(QuicSocketAddress(QuicIpAddress::Any4(), 5)); } MockQuicConnection::~MockQuicConnection() {} @@ -466,10 +470,11 @@ void PacketSavingConnection::SendOrQueuePacket(SerializedPacket* packet) { encrypted_packets_.push_back(QuicMakeUnique<QuicEncryptedPacket>( CopyBuffer(*packet), packet->encrypted_length, true)); + clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10)); // Transfer ownership of the packet to the SentPacketManager and the // ack notifier to the AckNotifierManager. QuicConnectionPeer::GetSentPacketManager(this)->OnPacketSent( - packet, QuicPacketNumber(), QuicTime::Zero(), NOT_RETRANSMISSION, + packet, QuicPacketNumber(), clock_.ApproximateNow(), NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); } @@ -581,16 +586,6 @@ crypto_stream_.reset(crypto_stream); } -size_t MockQuicSpdySession::WriteHeaders( - QuicStreamId id, - spdy::SpdyHeaderBlock headers, - bool fin, - spdy::SpdyPriority priority, - QuicReferenceCountedPointer<QuicAckListenerInterface> ack_listener) { - write_headers_ = std::move(headers); - return WriteHeadersMock(id, write_headers_, fin, priority, ack_listener); -} - TestQuicSpdyServerSession::TestQuicSpdyServerSession( QuicConnection* connection, const QuicConfig& config, @@ -853,17 +848,27 @@ header.reset_flag = reset_flag; header.packet_number_length = packet_number_length; header.packet_number = QuicPacketNumber(packet_number); - QuicFrame frame(QuicStreamFrame( - QuicUtils::GetCryptoStreamId( - versions != nullptr - ? (*versions)[0].transport_version - : CurrentSupportedVersions()[0].transport_version), - false, 0, QuicStringPiece(data))); + ParsedQuicVersionVector supported_versions = CurrentSupportedVersions(); + if (!versions) { + versions = &supported_versions; + } + if (QuicVersionHasLongHeaderLengths((*versions)[0].transport_version) && + version_flag) { + header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + QuicFrames frames; - frames.push_back(frame); - QuicFramer framer( - versions != nullptr ? *versions : CurrentSupportedVersions(), - QuicTime::Zero(), perspective); + QuicFramer framer(*versions, QuicTime::Zero(), perspective); + if ((*versions)[0].transport_version < QUIC_VERSION_47) { + QuicFrame frame(QuicStreamFrame( + QuicUtils::GetCryptoStreamId((*versions)[0].transport_version), false, + 0, QuicStringPiece(data))); + frames.push_back(frame); + } else { + QuicFrame frame(new QuicCryptoFrame(ENCRYPTION_NONE, 0, data)); + frames.push_back(frame); + } std::unique_ptr<QuicPacket> packet( BuildUnsizedDataPacket(&framer, header, frames)); @@ -873,6 +878,7 @@ framer.EncryptPayload(ENCRYPTION_NONE, QuicPacketNumber(packet_number), *packet, buffer, kMaxPacketSize); EXPECT_NE(0u, encrypted_length); + DeleteFrames(&frames); return new QuicEncryptedPacket(buffer, encrypted_length, true); } @@ -921,7 +927,9 @@ packet->mutable_data())[GetStartOfEncryptedData( framer.transport_version(), destination_connection_id_length, source_connection_id_length, version_flag, - false /* no diversification nonce */, packet_number_length)] = 0x1F; + false /* no diversification nonce */, packet_number_length, + VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)] = + 0x1F; char* buffer = new char[kMaxPacketSize]; size_t encrypted_length = @@ -969,6 +977,8 @@ QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicVariableLengthIntegerLength length_length, size_t* payload_length) { *payload_length = 1; const size_t stream_length = @@ -976,14 +986,16 @@ QuicPacketCreator::StreamFramePacketOverhead( version, destination_connection_id_length, source_connection_id_length, include_version, - include_diversification_nonce, packet_number_length, 0u); + include_diversification_nonce, packet_number_length, + retry_token_length_length, length_length, 0u); const size_t ack_length = NullEncrypter(Perspective::IS_CLIENT) .GetCiphertextSize(QuicFramer::GetMinAckFrameSize( version, PACKET_1BYTE_PACKET_NUMBER)) + GetPacketHeaderSize(version, destination_connection_id_length, source_connection_id_length, include_version, - include_diversification_nonce, packet_number_length); + include_diversification_nonce, packet_number_length, + retry_token_length_length, 0, length_length); if (stream_length < ack_length) { *payload_length = 1 + ack_length - stream_length; } @@ -993,7 +1005,8 @@ QuicPacketCreator::StreamFramePacketOverhead( version, destination_connection_id_length, source_connection_id_length, include_version, - include_diversification_nonce, packet_number_length, 0u); + include_diversification_nonce, packet_number_length, + retry_token_length_length, length_length, 0u); } QuicConfig DefaultQuicConfig() { @@ -1104,12 +1117,52 @@ (*server_connection)->AdvanceTime(connection_start_time); } +QuicStreamId GetNthClientInitiatedBidirectionalStreamId( + QuicTransportVersion version, + int n) { + return QuicUtils::GetFirstBidirectionalStreamId(version, + Perspective::IS_CLIENT) + + // + 1 because spdy_session contains headers stream. + QuicUtils::StreamIdDelta(version) * (n + 1); +} + +QuicStreamId GetNthServerInitiatedBidirectionalStreamId( + QuicTransportVersion version, + int n) { + return QuicUtils::GetFirstBidirectionalStreamId(version, + Perspective::IS_SERVER) + + QuicUtils::StreamIdDelta(version) * n; +} + +QuicStreamId GetNthServerInitiatedUnidirectionalStreamId( + QuicTransportVersion version, + int n) { + return QuicUtils::GetFirstUnidirectionalStreamId(version, + Perspective::IS_SERVER) + + QuicUtils::StreamIdDelta(version) * n; +} + StreamType DetermineStreamType(QuicStreamId id, QuicTransportVersion version, + Perspective perspective, bool is_incoming, StreamType default_type) { - return version == QUIC_VERSION_99 ? QuicUtils::GetStreamType(id, is_incoming) - : default_type; + return version == QUIC_VERSION_99 + ? QuicUtils::GetStreamType(id, perspective, is_incoming) + : default_type; +} + +QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator, + QuicStringPiece message_data, + QuicMemSliceStorage* storage) { + if (message_data.length() == 0) { + *storage = QuicMemSliceStorage(nullptr, 0, allocator, kMaxPacketSize); + return storage->ToSpan(); + } + struct iovec iov = {const_cast<char*>(message_data.data()), + message_data.length()}; + *storage = QuicMemSliceStorage(&iov, 1, allocator, kMaxPacketSize); + return storage->ToSpan(); } } // namespace test
diff --git a/quic/test_tools/quic_test_utils.h b/quic/test_tools/quic_test_utils.h index 8b52d4f..cf4c167 100644 --- a/quic/test_tools/quic_test_utils.h +++ b/quic/test_tools/quic_test_utils.h
@@ -25,6 +25,7 @@ #include "net/third_party/quiche/src/quic/core/quic_packet_writer.h" #include "net/third_party/quiche/src/quic/core/quic_sent_packet_manager.h" #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.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_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h" @@ -164,6 +165,8 @@ QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, QuicPacketNumberLength packet_number_length, + QuicVariableLengthIntegerLength retry_token_length_length, + QuicVariableLengthIntegerLength length_length, size_t* payload_length); // Returns QuicConfig set to default values. @@ -264,6 +267,7 @@ bool(const QuicPacketHeader& header)); MOCK_METHOD1(OnDecryptedPacket, void(EncryptionLevel level)); MOCK_METHOD1(OnPacketHeader, bool(const QuicPacketHeader& header)); + MOCK_METHOD1(OnCoalescedPacket, void(const QuicEncryptedPacket& packet)); MOCK_METHOD1(OnStreamFrame, bool(const QuicStreamFrame& frame)); MOCK_METHOD1(OnCryptoFrame, bool(const QuicCryptoFrame& frame)); MOCK_METHOD2(OnAckFrameStart, bool(QuicPacketNumber, QuicTime::Delta)); @@ -316,6 +320,7 @@ bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override {} bool OnPacketHeader(const QuicPacketHeader& header) override; + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override; bool OnStreamFrame(const QuicStreamFrame& frame) override; bool OnCryptoFrame(const QuicCryptoFrame& frame) override; bool OnAckFrameStart(QuicPacketNumber largest_acked, @@ -358,6 +363,7 @@ ~MockQuicConnectionVisitor() override; MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame& frame)); + MOCK_METHOD1(OnCryptoFrame, void(const QuicCryptoFrame& frame)); MOCK_METHOD1(OnWindowUpdateFrame, void(const QuicWindowUpdateFrame& frame)); MOCK_METHOD1(OnBlockedFrame, void(const QuicBlockedFrame& frame)); MOCK_METHOD1(OnRstStream, void(const QuicRstStreamFrame& frame)); @@ -511,7 +517,7 @@ MOCK_METHOD2(OnStreamReset, void(QuicStreamId, QuicRstStreamErrorCode)); MOCK_METHOD1(SendControlFrame, bool(const QuicFrame& frame)); - MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicStringPiece)); + MOCK_METHOD2(SendMessage, MessageStatus(QuicMessageId, QuicMemSliceSpan)); MOCK_METHOD3(OnConnectionClosed, void(QuicErrorCode error, const QuicString& error_details, @@ -555,6 +561,13 @@ } MOCK_METHOD1(OnPathResponseFrame, bool(const QuicPathResponseFrame&)); MOCK_METHOD1(OnStopSendingFrame, bool(const QuicStopSendingFrame& frame)); + MOCK_METHOD3(SendCryptoData, + size_t(EncryptionLevel, size_t, QuicStreamOffset)); + size_t QuicConnection_SendCryptoData(EncryptionLevel level, + size_t write_length, + QuicStreamOffset offset) { + return QuicConnection::SendCryptoData(level, write_length, offset); + } }; class PacketSavingConnection : public MockQuicConnection { @@ -575,6 +588,7 @@ void SendOrQueuePacket(SerializedPacket* packet) override; std::vector<std::unique_ptr<QuicEncryptedPacket>> encrypted_packets_; + MockClock clock_; }; class MockQuicSession : public QuicSession { @@ -668,7 +682,6 @@ QuicCryptoStream* GetMutableCryptoStream() override; const QuicCryptoStream* GetCryptoStream() const override; void SetCryptoStream(QuicCryptoStream* crypto_stream); - const spdy::SpdyHeaderBlock& GetWriteHeaders() { return write_headers_; } // From QuicSession. MOCK_METHOD3(OnConnectionClosed, @@ -720,22 +733,6 @@ MOCK_METHOD2(OnPriorityFrame, void(QuicStreamId id, spdy::SpdyPriority priority)); - // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be - // mocked directly. - size_t WriteHeaders(QuicStreamId id, - spdy::SpdyHeaderBlock headers, - bool fin, - spdy::SpdyPriority priority, - QuicReferenceCountedPointer<QuicAckListenerInterface> - ack_listener) override; - MOCK_METHOD5( - WriteHeadersMock, - size_t(QuicStreamId id, - const spdy::SpdyHeaderBlock& headers, - bool fin, - spdy::SpdyPriority priority, - const QuicReferenceCountedPointer<QuicAckListenerInterface>& - ack_listener)); MOCK_METHOD1(OnHeadersHeadOfLineBlocking, void(QuicTime::Delta delta)); MOCK_METHOD4( OnStreamFrameData, @@ -745,7 +742,6 @@ private: std::unique_ptr<QuicCryptoStream> crypto_stream_; - spdy::SpdyHeaderBlock write_headers_; }; class TestQuicSpdyServerSession : public QuicServerSessionBase { @@ -869,7 +865,6 @@ const QuicIpAddress& self_address, const QuicSocketAddress& peer_address, PerPacketOptions* options)); - MOCK_CONST_METHOD0(IsWriteBlockedDataBuffered, bool()); MOCK_CONST_METHOD0(IsWriteBlocked, bool()); MOCK_METHOD0(SetWritable, void()); MOCK_CONST_METHOD1(GetMaxPacketSize, @@ -1008,8 +1003,6 @@ MOCK_METHOD1(OnStreamFrame, void(const QuicStreamFrame&)); - MOCK_METHOD1(OnAckFrame, void(const QuicAckFrame& frame)); - MOCK_METHOD1(OnStopWaitingFrame, void(const QuicStopWaitingFrame&)); MOCK_METHOD1(OnRstStreamFrame, void(const QuicRstStreamFrame&)); @@ -1177,11 +1170,31 @@ iov->iov_len = static_cast<size_t>(str.size()); } +// Helper functions for stream ids, to allow test logic to abstract over the +// HTTP stream numbering scheme (i.e. whether one or two QUIC streams are used +// per HTTP transaction). +QuicStreamId GetNthClientInitiatedBidirectionalStreamId( + QuicTransportVersion version, + int n); +QuicStreamId GetNthServerInitiatedBidirectionalStreamId( + QuicTransportVersion version, + int n); +QuicStreamId GetNthServerInitiatedUnidirectionalStreamId( + QuicTransportVersion version, + int n); + StreamType DetermineStreamType(QuicStreamId id, QuicTransportVersion version, + Perspective perspective, bool is_incoming, StreamType default_type); +// Utility function that stores message_data in |storage| and returns a +// QuicMemSliceSpan. +QuicMemSliceSpan MakeSpan(QuicBufferAllocator* allocator, + QuicStringPiece message_data, + QuicMemSliceStorage* storage); + } // namespace test } // namespace quic
diff --git a/quic/test_tools/quic_unacked_packet_map_peer.cc b/quic/test_tools/quic_unacked_packet_map_peer.cc new file mode 100644 index 0000000..1ecc65f --- /dev/null +++ b/quic/test_tools/quic_unacked_packet_map_peer.cc
@@ -0,0 +1,24 @@ +// 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. + +#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h" + +namespace quic { +namespace test { + +// static +const QuicStreamFrame& QuicUnackedPacketMapPeer::GetAggregatedStreamFrame( + const QuicUnackedPacketMap& unacked_packets) { + return unacked_packets.aggregated_stream_frame_; +} + +// static +void QuicUnackedPacketMapPeer::SetPerspective( + QuicUnackedPacketMap* unacked_packets, + Perspective perspective) { + *const_cast<Perspective*>(&unacked_packets->perspective_) = perspective; +} + +} // namespace test +} // namespace quic
diff --git a/quic/test_tools/quic_unacked_packet_map_peer.h b/quic/test_tools/quic_unacked_packet_map_peer.h new file mode 100644 index 0000000..3bba0b6 --- /dev/null +++ b/quic/test_tools/quic_unacked_packet_map_peer.h
@@ -0,0 +1,25 @@ +// 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_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_ +#define QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_ + +#include "net/third_party/quiche/src/quic/core/quic_unacked_packet_map.h" + +namespace quic { +namespace test { + +class QuicUnackedPacketMapPeer { + public: + static const QuicStreamFrame& GetAggregatedStreamFrame( + const QuicUnackedPacketMap& unacked_packets); + + static void SetPerspective(QuicUnackedPacketMap* unacked_packets, + Perspective perspective); +}; + +} // namespace test +} // namespace quic + +#endif // QUICHE_QUIC_TEST_TOOLS_QUIC_UNACKED_PACKET_MAP_PEER_H_
diff --git a/quic/test_tools/simple_quic_framer.cc b/quic/test_tools/simple_quic_framer.cc index 6b0fb66..b5847ac 100644 --- a/quic/test_tools/simple_quic_framer.cc +++ b/quic/test_tools/simple_quic_framer.cc
@@ -55,6 +55,8 @@ return true; } + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override {} + bool OnStreamFrame(const QuicStreamFrame& frame) override { // Save a copy of the data so it is valid after the packet is processed. QuicString* string_data = @@ -68,8 +70,13 @@ } bool OnCryptoFrame(const QuicCryptoFrame& frame) override { - // TODO(nharper): Implement this. - return false; + // Save a copy of the data so it is valid after the packet is processed. + QuicString* string_data = + new QuicString(frame.data_buffer, frame.data_length); + crypto_data_.push_back(QuicWrapUnique(string_data)); + crypto_frames_.push_back(QuicMakeUnique<QuicCryptoFrame>( + frame.level, frame.offset, QuicStringPiece(*string_data))); + return true; } bool OnAckFrameStart(QuicPacketNumber largest_acked, @@ -181,7 +188,7 @@ } bool OnMessageFrame(const QuicMessageFrame& frame) override { - message_frames_.push_back(frame); + message_frames_.emplace_back(frame.data, frame.message_length); return true; } @@ -222,6 +229,9 @@ const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const { return stream_frames_; } + const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const { + return crypto_frames_; + } const std::vector<QuicStopWaitingFrame>& stop_waiting_frames() const { return stop_waiting_frames_; } @@ -258,6 +268,7 @@ std::vector<QuicPaddingFrame> padding_frames_; std::vector<QuicPingFrame> ping_frames_; std::vector<std::unique_ptr<QuicStreamFrame>> stream_frames_; + std::vector<std::unique_ptr<QuicCryptoFrame>> crypto_frames_; std::vector<QuicRstStreamFrame> rst_stream_frames_; std::vector<QuicGoAwayFrame> goaway_frames_; std::vector<QuicStreamIdBlockedFrame> stream_id_blocked_frames_; @@ -274,6 +285,7 @@ std::vector<QuicNewTokenFrame> new_token_frames_; std::vector<QuicMessageFrame> message_frames_; std::vector<std::unique_ptr<QuicString>> stream_data_; + std::vector<std::unique_ptr<QuicString>> crypto_data_; EncryptionLevel last_decrypted_level_; }; @@ -325,7 +337,8 @@ rst_stream_frames().size() + stop_waiting_frames().size() + path_challenge_frames().size() + path_response_frames().size() + stream_frames().size() + ping_frames().size() + - connection_close_frames().size() + padding_frames().size(); + connection_close_frames().size() + padding_frames().size() + + crypto_frames().size(); } const std::vector<QuicAckFrame>& SimpleQuicFramer::ack_frames() const { @@ -364,6 +377,11 @@ return visitor_->stream_frames(); } +const std::vector<std::unique_ptr<QuicCryptoFrame>>& +SimpleQuicFramer::crypto_frames() const { + return visitor_->crypto_frames(); +} + const std::vector<QuicRstStreamFrame>& SimpleQuicFramer::rst_stream_frames() const { return visitor_->rst_stream_frames();
diff --git a/quic/test_tools/simple_quic_framer.h b/quic/test_tools/simple_quic_framer.h index da2f4e5..2edf9d3 100644 --- a/quic/test_tools/simple_quic_framer.h +++ b/quic/test_tools/simple_quic_framer.h
@@ -47,6 +47,7 @@ const std::vector<QuicGoAwayFrame>& goaway_frames() const; const std::vector<QuicRstStreamFrame>& rst_stream_frames() const; const std::vector<std::unique_ptr<QuicStreamFrame>>& stream_frames() const; + const std::vector<std::unique_ptr<QuicCryptoFrame>>& crypto_frames() const; const std::vector<QuicPaddingFrame>& padding_frames() const; const QuicVersionNegotiationPacket* version_negotiation_packet() const; EncryptionLevel last_decrypted_level() const;
diff --git a/quic/test_tools/simple_session_notifier.cc b/quic/test_tools/simple_session_notifier.cc index 75c55f4..c56831e 100644 --- a/quic/test_tools/simple_session_notifier.cc +++ b/quic/test_tools/simple_session_notifier.cc
@@ -81,6 +81,17 @@ state.fin_outstanding = fin; } +size_t SimpleSessionNotifier::WriteCryptoData(EncryptionLevel level, + QuicByteCount data_length, + QuicStreamOffset offset) { + crypto_state_[level].bytes_total += data_length; + size_t bytes_written = + connection_->SendCryptoData(level, data_length, offset); + crypto_state_[level].bytes_sent += bytes_written; + crypto_bytes_transferred_[level].Add(offset, offset + bytes_written); + return bytes_written; +} + void SimpleSessionNotifier::WriteOrBufferRstStream( QuicStreamId id, QuicRstStreamErrorCode error, @@ -103,6 +114,7 @@ void SimpleSessionNotifier::NeuterUnencryptedData() { for (const auto& interval : crypto_bytes_transferred_[ENCRYPTION_NONE]) { + // TODO(nharper): Handle CRYPTO frame case. QuicStreamFrame stream_frame( QuicUtils::GetCryptoStreamId(connection_->transport_version()), false, interval.min(), interval.max() - interval.min()); @@ -120,6 +132,7 @@ return; } // Write new data. + // TODO(nharper): Write CRYPTO frames. for (const auto& pair : stream_map_) { const auto& state = pair.second; if (!StreamHasBufferedData(pair.first)) { @@ -175,6 +188,19 @@ bool SimpleSessionNotifier::OnFrameAcked(const QuicFrame& frame, QuicTime::Delta /*ack_delay_time*/) { QUIC_DVLOG(1) << "Acking " << frame; + if (frame.type == CRYPTO_FRAME) { + StreamState* state = &crypto_state_[frame.crypto_frame->level]; + QuicStreamOffset offset = frame.crypto_frame->offset; + QuicByteCount data_length = frame.crypto_frame->data_length; + QuicIntervalSet<QuicStreamOffset> newly_acked(offset, offset + data_length); + newly_acked.Difference(state->bytes_acked); + if (newly_acked.Empty()) { + return false; + } + state->bytes_acked.Add(offset, offset + data_length); + state->pending_retransmissions.Difference(offset, offset + data_length); + return true; + } if (frame.type != STREAM_FRAME) { return OnControlFrameAcked(frame); } @@ -201,6 +227,20 @@ void SimpleSessionNotifier::OnFrameLost(const QuicFrame& frame) { QUIC_DVLOG(1) << "Losting " << frame; + if (frame.type == CRYPTO_FRAME) { + StreamState* state = &crypto_state_[frame.crypto_frame->level]; + QuicStreamOffset offset = frame.crypto_frame->offset; + QuicByteCount data_length = frame.crypto_frame->data_length; + QuicIntervalSet<QuicStreamOffset> bytes_lost(offset, offset + data_length); + bytes_lost.Difference(state->bytes_acked); + if (bytes_lost.Empty()) { + return; + } + for (const auto& lost : bytes_lost) { + state->pending_retransmissions.Add(lost.min(), lost.max()); + } + return; + } if (frame.type != STREAM_FRAME) { OnControlFrameLost(frame); return; @@ -229,6 +269,21 @@ connection_, QuicConnection::SEND_ACK_IF_QUEUED); connection_->SetTransmissionType(type); for (const QuicFrame& frame : frames) { + if (frame.type == CRYPTO_FRAME) { + const StreamState& state = crypto_state_[frame.crypto_frame->level]; + QuicIntervalSet<QuicStreamOffset> retransmission( + frame.crypto_frame->offset, + frame.crypto_frame->offset + frame.crypto_frame->data_length); + retransmission.Difference(state.bytes_acked); + for (const auto& interval : retransmission) { + QuicStreamOffset offset = interval.min(); + QuicByteCount length = interval.max() - interval.min(); + size_t consumed = connection_->SendCryptoData(frame.crypto_frame->level, + length, offset); + // CRYPTO frames should never be write blocked. + DCHECK_EQ(consumed, length); + } + } if (frame.type != STREAM_FRAME) { if (GetControlFrameId(frame) == kInvalidControlFrameId) { continue; @@ -308,6 +363,14 @@ } bool SimpleSessionNotifier::IsFrameOutstanding(const QuicFrame& frame) const { + if (frame.type == CRYPTO_FRAME) { + QuicStreamOffset offset = frame.crypto_frame->offset; + QuicByteCount data_length = frame.crypto_frame->data_length; + bool ret = data_length > 0 && + !crypto_state_[frame.crypto_frame->level].bytes_acked.Contains( + offset, offset + data_length); + return ret; + } if (frame.type != STREAM_FRAME) { return IsControlFrameOutstanding(frame); } @@ -323,6 +386,20 @@ } bool SimpleSessionNotifier::HasUnackedCryptoData() const { + if (connection_->transport_version() >= QUIC_VERSION_47) { + for (size_t i = 0; i < NUM_ENCRYPTION_LEVELS; ++i) { + const StreamState& state = crypto_state_[i]; + if (state.bytes_total > state.bytes_sent) { + return true; + } + QuicIntervalSet<QuicStreamOffset> bytes_to_ack(0, state.bytes_total); + bytes_to_ack.Difference(state.bytes_acked); + if (!bytes_to_ack.Empty()) { + return true; + } + } + return false; + } if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId( connection_->transport_version()))) { return false; @@ -406,6 +483,7 @@ } bool SimpleSessionNotifier::RetransmitLostCryptoData() { + // TODO(nharper): Handle CRYPTO frame case. if (!QuicContainsKey(stream_map_, QuicUtils::GetCryptoStreamId( connection_->transport_version()))) { return true;
diff --git a/quic/test_tools/simple_session_notifier.h b/quic/test_tools/simple_session_notifier.h index 293937f..f7982d2 100644 --- a/quic/test_tools/simple_session_notifier.h +++ b/quic/test_tools/simple_session_notifier.h
@@ -6,6 +6,7 @@ #define QUICHE_QUIC_TEST_TOOLS_SIMPLE_SESSION_NOTIFIER_H_ #include "testing/gmock/include/gmock/gmock.h" +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" #include "net/third_party/quiche/src/quic/core/session_notifier_interface.h" namespace quic { @@ -31,6 +32,11 @@ QuicRstStreamErrorCode error, QuicStreamOffset bytes_written); + // Tries to write CRYPTO data and returns the number of bytes written. + size_t WriteCryptoData(EncryptionLevel level, + QuicByteCount data_length, + QuicStreamOffset offset); + // Neuters unencrypted data of crypto stream. void NeuterUnencryptedData(); @@ -133,6 +139,8 @@ QuicIntervalSet<QuicStreamOffset> crypto_bytes_transferred_[NUM_ENCRYPTION_LEVELS]; + StreamState crypto_state_[NUM_ENCRYPTION_LEVELS]; + QuicConnection* connection_; };
diff --git a/quic/test_tools/simple_session_notifier_test.cc b/quic/test_tools/simple_session_notifier_test.cc index 61bc95c..b20fee6 100644 --- a/quic/test_tools/simple_session_notifier_test.cc +++ b/quic/test_tools/simple_session_notifier_test.cc
@@ -111,8 +111,8 @@ notifier_.WriteOrBufferData( QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024, NO_FIN); - // Send crypto data [1024, 2048) in ENCRYPTION_INITIAL. - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId( connection_.transport_version()), 1024, 1024, NO_FIN)) @@ -144,8 +144,8 @@ notifier_.WriteOrBufferData( QuicUtils::GetCryptoStreamId(connection_.transport_version()), 1024, NO_FIN); - // Send crypto data [1024, 2048) in ENCRYPTION_INITIAL. - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); + // Send crypto data [1024, 2048) in ENCRYPTION_ZERO_RTT. + connection_.SetDefaultEncryptionLevel(ENCRYPTION_ZERO_RTT); EXPECT_CALL(connection_, SendStreamData(QuicUtils::GetCryptoStreamId( connection_.transport_version()), 1024, 1024, NO_FIN))
diff --git a/quic/test_tools/simulator/quic_endpoint.cc b/quic/test_tools/simulator/quic_endpoint.cc index 2867d82..5cd4de1 100644 --- a/quic/test_tools/simulator/quic_endpoint.cc +++ b/quic/test_tools/simulator/quic_endpoint.cc
@@ -223,6 +223,8 @@ DCHECK_LE(offsets_received_.Size(), 1000u); } +void QuicEndpoint::OnCryptoFrame(const QuicCryptoFrame& frame) {} + void QuicEndpoint::OnCanWrite() { if (notifier_ != nullptr) { notifier_->OnCanWrite(); @@ -311,10 +313,6 @@ return WriteResult(WRITE_STATUS_OK, buf_len); } -bool QuicEndpoint::Writer::IsWriteBlockedDataBuffered() const { - return false; -} - bool QuicEndpoint::Writer::IsWriteBlocked() const { return is_blocked_; }
diff --git a/quic/test_tools/simulator/quic_endpoint.h b/quic/test_tools/simulator/quic_endpoint.h index 600a1d1..e36f384 100644 --- a/quic/test_tools/simulator/quic_endpoint.h +++ b/quic/test_tools/simulator/quic_endpoint.h
@@ -80,6 +80,7 @@ // Begin QuicConnectionVisitorInterface implementation. void OnStreamFrame(const QuicStreamFrame& frame) override; + void OnCryptoFrame(const QuicCryptoFrame& frame) override; void OnCanWrite() override; bool WillingAndAbleToWrite() const override; bool HasPendingHandshake() const override; @@ -108,13 +109,13 @@ void OnForwardProgressConfirmed() override {} bool OnMaxStreamIdFrame(const QuicMaxStreamIdFrame& frame) override { return true; - }; + } bool OnStreamIdBlockedFrame(const QuicStreamIdBlockedFrame& frame) override { return true; - }; + } bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override { return true; - }; + } // End QuicConnectionVisitorInterface implementation. @@ -141,7 +142,6 @@ const QuicIpAddress& self_address, const QuicSocketAddress& peer_address, PerPacketOptions* options) override; - bool IsWriteBlockedDataBuffered() const override; bool IsWriteBlocked() const override; void SetWritable() override; QuicByteCount GetMaxPacketSize(
diff --git a/quic/test_tools/simulator/switch.cc b/quic/test_tools/simulator/switch.cc index d00daf7..638fa20 100644 --- a/quic/test_tools/simulator/switch.cc +++ b/quic/test_tools/simulator/switch.cc
@@ -4,7 +4,6 @@ #include <cinttypes> -#include "base/port.h" #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h" #include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h" @@ -17,10 +16,9 @@ SwitchPortNumber port_count, QuicByteCount queue_capacity) { for (size_t port_number = 1; port_number <= port_count; port_number++) { - ports_.emplace_back( - simulator, - QuicStringPrintf("%s (port %" PRIuS ")", name.c_str(), port_number), - this, port_number, queue_capacity); + ports_.emplace_back(simulator, + QuicStrCat(name, " (port ", port_number, ")"), this, + port_number, queue_capacity); } }
diff --git a/quic/tools/quic_client_base.cc b/quic/tools/quic_client_base.cc index f824811..2d8c307 100644 --- a/quic/tools/quic_client_base.cc +++ b/quic/tools/quic_client_base.cc
@@ -226,6 +226,11 @@ return true; } +bool QuicClientBase::ChangeEphemeralPort() { + auto current_host = network_helper_->GetLatestClientAddress().host(); + return MigrateSocketWithSpecifiedPort(current_host, 0 /*any ephemeral port*/); +} + QuicSession* QuicClientBase::session() { return session_.get(); } @@ -325,7 +330,7 @@ } QuicConnectionId QuicClientBase::GenerateNewConnectionId() { - return QuicUtils::CreateRandomConnectionId(Perspective::IS_CLIENT); + return QuicUtils::CreateRandomConnectionId(); } bool QuicClientBase::CanReconnectWithDifferentVersion(
diff --git a/quic/tools/quic_client_base.h b/quic/tools/quic_client_base.h index c751bfd..379f097 100644 --- a/quic/tools/quic_client_base.h +++ b/quic/tools/quic_client_base.h
@@ -10,12 +10,12 @@ #include <string> -#include "base/macros.h" #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h" #include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_macros.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_piece.h" @@ -102,7 +102,7 @@ // Wait for events until the handshake is confirmed. // Returns true if the crypto handshake succeeds, false otherwise. - bool WaitForCryptoHandshakeConfirmed() ABSL_MUST_USE_RESULT; + bool WaitForCryptoHandshakeConfirmed() QUIC_MUST_USE_RESULT; // Wait up to 50ms, and handle any events which occur. // Returns true if there are any outstanding requests. @@ -114,6 +114,9 @@ // Migrate to a new socket (new_host, port) during an active connection. bool MigrateSocketWithSpecifiedPort(const QuicIpAddress& new_host, int port); + // Open a new socket to change to a new ephemeral port. + bool ChangeEphemeralPort(); + QuicSession* session(); bool connected() const;
diff --git a/quic/tools/quic_client_bin.cc b/quic/tools/quic_client_bin.cc index 629b980..9504c74 100644 --- a/quic/tools/quic_client_bin.cc +++ b/quic/tools/quic_client_bin.cc
@@ -29,6 +29,9 @@ // IP=`dig www.google.com +short | head -1` // quic_client www.google.com --host=${IP} // +// Send repeated requests and change ephemeral port between requests +// quic_client www.google.com --num_requests=10 +// // Try to connect to a host which does not speak QUIC: // quic_client www.example.com // @@ -40,19 +43,21 @@ // --config=quic quic_client #include <iostream> +#include <vector> #include "base/commandlineflags.h" #include "base/init_google.h" #include "net/base/ipaddress.h" #include "net/dns/hostlookup.h" #include "third_party/absl/flags/flag.h" -#include "net/third_party/quiche/src/quic/core/crypto/proof_verifier_google3.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" #include "net/third_party/quiche/src/quic/core/quic_server_id.h" #include "net/third_party/quiche/src/quic/core/quic_utils.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_ptr_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_str_cat.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string.h" #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" #include "net/third_party/quiche/src/quic/tools/quic_client.h" @@ -90,49 +95,84 @@ } }; -DEFINE_string(host, - "", - "The IP or hostname to connect to. If not provided, the host " - "will be derived from the provided URL."); -DEFINE_int32(port, 0, "The port to connect to."); -DEFINE_string(body, "", "If set, send a POST with this body."); -DEFINE_string(body_hex, - "", - "If set, contents are converted from hex to ascii, before " - "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\""); -DEFINE_string(headers, - "", - "A semicolon separated list of key:value pairs to " - "add to request headers."); -DEFINE_bool(quiet, false, "Set to true for a quieter output experience."); -DEFINE_int32(quic_version, - -1, - "QUIC version to speak, e.g. 21. If not set, then all available " - "versions are offered in the handshake."); -DEFINE_bool(version_mismatch_ok, - false, - "If true, a version mismatch in the handshake is not considered a " - "failure. Useful for probing a server to determine if it speaks " - "any version of QUIC."); -DEFINE_bool(redirect_is_success, - true, - "If true, an HTTP response code of 3xx is considered to be a " - "successful response, otherwise a failure."); -DEFINE_int32(initial_mtu, 0, "Initial MTU of the connection."); -DEFINE_string(root_certificate_file, - "/google/src/head/depot/google3/security/cacerts/" - "for_connecting_to_google/roots.pem", - "Path to the root certificate which the server's certificate is " - "required to chain to."); -ABSL_FLAG(bool, - disable_certificate_verification, - false, - "If true, don't verify the server certificate."); -ABSL_FLAG(bool, - drop_response_body, - false, - "If true, drop response body immediately after it is received."); +DEFINE_QUIC_COMMAND_LINE_FLAG( + string, + host, + "", + "The IP or hostname to connect to. If not provided, the host " + "will be derived from the provided URL."); +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(string, + body, + "", + "If set, send a POST with this body."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + string, + body_hex, + "", + "If set, contents are converted from hex to ascii, before " + "sending as body of a POST. e.g. --body_hex=\"68656c6c6f\""); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + string, + headers, + "", + "A semicolon separated list of key:value pairs to " + "add to request headers."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(bool, + quiet, + false, + "Set to true for a quieter output experience."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + int32_t, + quic_version, + -1, + "QUIC version to speak, e.g. 21. If not set, then all available " + "versions are offered in the handshake."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, + version_mismatch_ok, + false, + "If true, a version mismatch in the handshake is not considered a " + "failure. Useful for probing a server to determine if it speaks " + "any version of QUIC."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, + redirect_is_success, + true, + "If true, an HTTP response code of 3xx is considered to be a " + "successful response, otherwise a failure."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, + initial_mtu, + 0, + "Initial MTU of the connection."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + int32_t, + num_requests, + 1, + "How many sequential requests to make on a single connection."); + +DEFINE_QUIC_COMMAND_LINE_FLAG(bool, + disable_certificate_verification, + false, + "If true, don't verify the server certificate."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + bool, + drop_response_body, + false, + "If true, drop response body immediately after it is received."); + +using quic::QuicString; using quic::QuicStringPiece; using quic::QuicTextUtils; using quic::QuicUrl; @@ -141,20 +181,22 @@ using std::endl; int main(int argc, char* argv[]) { - InitGoogle(argv[0], &argc, &argv, true); + const char* usage = "Usage: quic_client [options] <url>"; // All non-flag arguments should be interpreted as URLs to fetch. - if (argc != 2) { - cerr << "Usage: " << argv[0] << " [optional flags] url" << endl; - return 1; + std::vector<QuicString> urls = + quic::QuicParseCommandLineFlags(usage, argc, argv); + if (urls.size() != 1) { + quic::QuicPrintCommandLineFlagHelp(usage); + exit(0); } - QuicUrl url(argv[1], "https"); - string host = FLAGS_host; + QuicUrl url(urls[0], "https"); + string host = GetQuicFlag(FLAGS_host); if (host.empty()) { host = url.host(); } - int port = FLAGS_port; + int port = GetQuicFlag(FLAGS_port); if (port == 0) { port = url.port(); } @@ -176,23 +218,24 @@ quic::QuicEpollServer epoll_server; quic::QuicServerId server_id(url.host(), port, false); quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions(); - if (FLAGS_quic_version != -1) { + if (GetQuicFlag(FLAGS_quic_version) != -1) { versions.clear(); versions.push_back(quic::ParsedQuicVersion( - quic::PROTOCOL_QUIC_CRYPTO, - static_cast<quic::QuicTransportVersion>(FLAGS_quic_version))); + quic::PROTOCOL_QUIC_CRYPTO, static_cast<quic::QuicTransportVersion>( + GetQuicFlag(FLAGS_quic_version)))); } + const int32_t num_requests(GetQuicFlag(FLAGS_num_requests)); std::unique_ptr<quic::ProofVerifier> proof_verifier; if (GetQuicFlag(FLAGS_disable_certificate_verification)) { proof_verifier = quic::QuicMakeUnique<FakeProofVerifier>(); } else { - proof_verifier = quic::QuicMakeUnique<quic::ProofVerifierGoogle3>( - FLAGS_root_certificate_file); + proof_verifier = quic::CreateDefaultProofVerifier(); } quic::QuicClient client(quic::QuicSocketAddress(ip_addr, port), server_id, versions, &epoll_server, std::move(proof_verifier)); + int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu); client.set_initial_max_packet_length( - FLAGS_initial_mtu != 0 ? FLAGS_initial_mtu : quic::kDefaultMaxPacketSize); + initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize); client.set_drop_response_body(GetQuicFlag(FLAGS_drop_response_body)); if (!client.Initialize()) { cerr << "Failed to initialize client." << endl; @@ -206,7 +249,7 @@ << endl; // 0: No error. // 20: Failed to connect due to QUIC_INVALID_VERSION. - return FLAGS_version_mismatch_ok ? 0 : 20; + return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20; } cerr << "Failed to connect to " << host_port << ". Error: " << quic::QuicErrorCodeToString(error) << endl; @@ -215,10 +258,11 @@ cout << "Connected to " << host_port << endl; // Construct the string body from flags, if provided. - string body = FLAGS_body; - if (!FLAGS_body_hex.empty()) { - DCHECK(FLAGS_body.empty()) << "Only set one of --body and --body_hex."; - body = QuicTextUtils::HexDecode(FLAGS_body_hex); + string body = GetQuicFlag(FLAGS_body); + if (!GetQuicFlag(FLAGS_body_hex).empty()) { + DCHECK(GetQuicFlag(FLAGS_body).empty()) + << "Only set one of --body and --body_hex."; + body = QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex)); } // Construct a GET or POST request for supplied URL. @@ -229,7 +273,8 @@ header_block[":path"] = url.PathParamsQuery(); // Append any additional headers supplied on the command line. - for (QuicStringPiece sp : QuicTextUtils::Split(FLAGS_headers, ';')) { + for (QuicStringPiece sp : + QuicTextUtils::Split(GetQuicFlag(FLAGS_headers), ';')) { QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&sp); if (sp.empty()) { continue; @@ -243,55 +288,72 @@ // Make sure to store the response, for later output. client.set_store_response(true); - // Send the request. - client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true); + for (int i = 0; i < num_requests; ++i) { + // Send the request. + client.SendRequestAndWaitForResponse(header_block, body, /*fin=*/true); - // Print request and response details. - if (!FLAGS_quiet) { - cout << "Request:" << endl; - cout << "headers:" << header_block.DebugString(); - if (!FLAGS_body_hex.empty()) { - // Print the user provided hex, rather than binary body. - cout << "body:\n" - << QuicTextUtils::HexDump(QuicTextUtils::HexDecode(FLAGS_body_hex)) - << endl; - } else { - cout << "body: " << body << endl; - } - cout << endl; - - if (!client.preliminary_response_headers().empty()) { - cout << "Preliminary response headers: " - << client.preliminary_response_headers() << endl; + // Print request and response details. + if (!GetQuicFlag(FLAGS_quiet)) { + cout << "Request:" << endl; + cout << "headers:" << header_block.DebugString(); + if (!GetQuicFlag(FLAGS_body_hex).empty()) { + // Print the user provided hex, rather than binary body. + cout << "body:\n" + << QuicTextUtils::HexDump( + QuicTextUtils::HexDecode(GetQuicFlag(FLAGS_body_hex))) + << endl; + } else { + cout << "body: " << body << endl; + } cout << endl; + + if (!client.preliminary_response_headers().empty()) { + cout << "Preliminary response headers: " + << client.preliminary_response_headers() << endl; + cout << endl; + } + + cout << "Response:" << endl; + cout << "headers: " << client.latest_response_headers() << endl; + string response_body = client.latest_response_body(); + if (!GetQuicFlag(FLAGS_body_hex).empty()) { + // Assume response is binary data. + cout << "body:\n" << QuicTextUtils::HexDump(response_body) << endl; + } else { + cout << "body: " << response_body << endl; + } + cout << "trailers: " << client.latest_response_trailers() << endl; } - cout << "Response:" << endl; - cout << "headers: " << client.latest_response_headers() << endl; - string response_body = client.latest_response_body(); - if (!FLAGS_body_hex.empty()) { - // Assume response is binary data. - cout << "body:\n" << QuicTextUtils::HexDump(response_body) << endl; - } else { - cout << "body: " << response_body << endl; - } - cout << "trailers: " << client.latest_response_trailers() << endl; - } - - size_t response_code = client.latest_response_code(); - if (response_code >= 200 && response_code < 300) { - cout << "Request succeeded (" << response_code << ")." << endl; - return 0; - } else if (response_code >= 300 && response_code < 400) { - if (FLAGS_redirect_is_success) { - cout << "Request succeeded (redirect " << response_code << ")." << endl; - return 0; - } else { - cout << "Request failed (redirect " << response_code << ")." << endl; + if (!client.connected()) { + cerr << "Request caused connection failure. Error: " + << quic::QuicErrorCodeToString(client.session()->error()) << endl; return 1; } - } else { - cerr << "Request failed (" << response_code << ")." << endl; - return 1; + + size_t response_code = client.latest_response_code(); + if (response_code >= 200 && response_code < 300) { + cout << "Request succeeded (" << response_code << ")." << endl; + } else if (response_code >= 300 && response_code < 400) { + if (GetQuicFlag(FLAGS_redirect_is_success)) { + cout << "Request succeeded (redirect " << response_code << ")." << endl; + } else { + cout << "Request failed (redirect " << response_code << ")." << endl; + return 1; + } + } else { + cerr << "Request failed (" << response_code << ")." << endl; + return 1; + } + + // Change the ephemeral port if there are more requests to do. + if (i + 1 < num_requests) { + if (!client.ChangeEphemeralPort()) { + cout << "Failed to change ephemeral port." << endl; + return 1; + } + } } + + return 0; }
diff --git a/quic/tools/quic_client_epoll_network_helper.cc b/quic/tools/quic_client_epoll_network_helper.cc index 6a48ad3..f2d22a1 100644 --- a/quic/tools/quic_client_epoll_network_helper.cc +++ b/quic/tools/quic_client_epoll_network_helper.cc
@@ -78,6 +78,7 @@ } else { client_address = QuicSocketAddress(QuicIpAddress::Any6(), bind_to_port); } + sockaddr_storage addr = client_address.generic_address(); int rc = bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)); if (rc < 0) {
diff --git a/quic/tools/quic_client_epoll_network_helper.h b/quic/tools/quic_client_epoll_network_helper.h index 5871cd0..e0f8cf3 100644 --- a/quic/tools/quic_client_epoll_network_helper.h +++ b/quic/tools/quic_client_epoll_network_helper.h
@@ -13,16 +13,13 @@ #include <string> #include "base/macros.h" -#include "gfe/gfe2/base/epoll_server.h" #include "net/third_party/quiche/src/quic/core/http/quic_client_push_promise_index.h" -#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h" -#include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h" #include "net/third_party/quiche/src/quic/core/quic_config.h" #include "net/third_party/quiche/src/quic/core/quic_packet_reader.h" #include "net/third_party/quiche/src/quic/core/quic_process_packet_interface.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" #include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h" -#include "net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h" +#include "net/third_party/quiche/src/quic/tools/quic_client_base.h" namespace quic {
diff --git a/quic/tools/quic_client_test.cc b/quic/tools/quic_client_test.cc index 4f139b3..7977f05 100644 --- a/quic/tools/quic_client_test.cc +++ b/quic/tools/quic_client_test.cc
@@ -4,13 +4,14 @@ #include "net/third_party/quiche/src/quic/tools/quic_client.h" +#include <dirent.h> +#include <sys/types.h> + #include <memory> -#include "file/base/path.h" -#include "file/util/linux_fileops.h" -#include "gfe/gfe2/base/epoll_server.h" -#include "net/util/netutil.h" -#include "testing/base/public/test_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_epoll.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h" #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h" @@ -23,39 +24,44 @@ const char* kPathToFds = "/proc/self/fd"; +QuicString ReadLink(const QuicString& path) { + QuicString result(PATH_MAX, '\0'); + ssize_t result_size = readlink(path.c_str(), &result[0], result.size()); + CHECK(result_size > 0 && static_cast<size_t>(result_size) < result.size()); + result.resize(result_size); + return result; +} + // Counts the number of open sockets for the current process. size_t NumOpenSocketFDs() { - std::vector<QuicString> fd_entries; - QuicString error_message; - - CHECK(file_util::LinuxFileOps::ListDirectoryEntries(kPathToFds, &fd_entries, - &error_message)); - size_t socket_count = 0; - for (const QuicString& entry : fd_entries) { - if (entry == "." || entry == "..") { + dirent* file; + std::unique_ptr<DIR, int (*)(DIR*)> fd_directory(opendir(kPathToFds), + closedir); + while ((file = readdir(fd_directory.get())) != nullptr) { + QuicStringPiece name(file->d_name); + if (name == "." || name == "..") { continue; } - QuicString fd_path = - file_util::LinuxFileOps::ReadLink(file::JoinPath(kPathToFds, entry)); + QuicString fd_path = ReadLink(QuicStrCat(kPathToFds, "/", name)); if (QuicTextUtils::StartsWith(fd_path, "socket:")) { socket_count++; } } - return socket_count; } // Creates a new QuicClient and Initializes it. Caller is responsible for // deletion. -QuicClient* CreateAndInitializeQuicClient(QuicEpollServer* eps, uint16_t port) { +std::unique_ptr<QuicClient> CreateAndInitializeQuicClient(QuicEpollServer* eps, + uint16_t port) { QuicSocketAddress server_address(QuicSocketAddress(TestLoopback(), port)); QuicServerId server_id("hostname", server_address.port(), false); ParsedQuicVersionVector versions = AllSupportedVersions(); - QuicClient* client = - new QuicClient(server_address, server_id, versions, eps, - crypto_test_utils::ProofVerifierForTesting()); + auto client = + QuicMakeUnique<QuicClient>(server_address, server_id, versions, eps, + crypto_test_utils::ProofVerifierForTesting()); EXPECT_TRUE(client->Initialize()); return client; } @@ -66,8 +72,12 @@ // Make sure that the QuicClient doesn't leak socket FDs. Doing so could cause // port exhaustion in long running processes which repeatedly create clients. - // Record initial number of FDs, after creation of EpollServer. + // Record initial number of FDs, after creating EpollServer and creating and + // destroying a single client (the latter is needed since initializing + // platform dependencies like certificate verifier may open a persistent + // socket). QuicEpollServer eps; + CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie()); size_t number_of_open_fds = NumOpenSocketFDs(); // Create a number of clients, initialize them, and verify this has resulted @@ -75,7 +85,7 @@ const int kNumClients = 50; for (int i = 0; i < kNumClients; ++i) { std::unique_ptr<QuicClient> client( - CreateAndInitializeQuicClient(&eps, net_util::PickUnusedPortOrDie())); + CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie())); // Initializing the client will create a new FD. EXPECT_LT(number_of_open_fds, NumOpenSocketFDs()); @@ -90,7 +100,7 @@ size_t number_of_open_fds = NumOpenSocketFDs(); std::unique_ptr<QuicClient> client( - CreateAndInitializeQuicClient(&eps, net_util::PickUnusedPortOrDie())); + CreateAndInitializeQuicClient(&eps, QuicPickUnusedPortOrDie())); EXPECT_EQ(number_of_open_fds + 1, NumOpenSocketFDs()); // Create more UDP sockets. EXPECT_TRUE(QuicClientPeer::CreateUDPSocketAndBind(client.get()));
diff --git a/quic/tools/quic_memory_cache_backend.h b/quic/tools/quic_memory_cache_backend.h index 1bf9b7c..1417349 100644 --- a/quic/tools/quic_memory_cache_backend.h +++ b/quic/tools/quic_memory_cache_backend.h
@@ -68,7 +68,6 @@ private: QuicStringPiece host_; QuicStringPiece path_; - QuicMemoryCacheBackend* cache_; }; QuicMemoryCacheBackend();
diff --git a/quic/tools/quic_memory_cache_backend_test.cc b/quic/tools/quic_memory_cache_backend_test.cc index 8c621be..be5c374 100644 --- a/quic/tools/quic_memory_cache_backend_test.cc +++ b/quic/tools/quic_memory_cache_backend_test.cc
@@ -16,7 +16,7 @@ namespace { typedef QuicBackendResponse Response; typedef QuicBackendResponse::ServerPushInfo ServerPushInfo; -}; // namespace +} // namespace class QuicMemoryCacheBackendTest : public QuicTest { protected:
diff --git a/quic/tools/quic_packet_printer_bin.cc b/quic/tools/quic_packet_printer_bin.cc index 2900ce8..3dd7493 100644 --- a/quic/tools/quic_packet_printer_bin.cc +++ b/quic/tools/quic_packet_printer_bin.cc
@@ -80,6 +80,9 @@ std::cerr << "OnPacketHeader\n"; return true; } + void OnCoalescedPacket(const QuicEncryptedPacket& packet) override { + std::cerr << "OnCoalescedPacket\n"; + } bool OnStreamFrame(const QuicStreamFrame& frame) override { std::cerr << "OnStreamFrame: " << frame; std::cerr << " data: { "
diff --git a/quic/tools/quic_server.cc b/quic/tools/quic_server.cc index eaec5d4..006098c 100644 --- a/quic/tools/quic_server.cc +++ b/quic/tools/quic_server.cc
@@ -147,7 +147,7 @@ QuicDispatcher* QuicServer::CreateQuicDispatcher() { QuicEpollAlarmFactory alarm_factory(&epoll_server_); return new QuicSimpleDispatcher( - config_, &crypto_config_, &version_manager_, + &config_, &crypto_config_, &version_manager_, std::unique_ptr<QuicEpollConnectionHelper>(new QuicEpollConnectionHelper( &epoll_server_, QuicAllocator::BUFFER_POOL)), std::unique_ptr<QuicCryptoServerStream::Helper>(
diff --git a/quic/tools/quic_server_bin.cc b/quic/tools/quic_server_bin.cc index c4c85d3..446d55e 100644 --- a/quic/tools/quic_server_bin.cc +++ b/quic/tools/quic_server_bin.cc
@@ -5,6 +5,8 @@ // A binary wrapper for QuicServer. It listens forever on --port // (default 6121) until it's killed or ctrl-cd to death. +#include <vector> + #include "base/commandlineflags.h" #include "base/init_google.h" #include "net/httpsconnection/certificates.proto.h" @@ -15,17 +17,28 @@ #include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" #include "net/third_party/quiche/src/quic/tools/quic_server.h" -DEFINE_int32(port, 6121, "The port the quic server will listen on."); -DEFINE_string( +DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, + port, + 6121, + "The port the quic server will listen on."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + string, certificate_dir, "/google/src/head/depot/google3/net/third_party/quiche/src/quic/core/crypto/testdata", "The directory containing certificate files."); -DEFINE_string(intermediate_certificate_name, - "intermediate.crt", - "The name of the file containing the intermediate certificate."); -DEFINE_string(leaf_certificate_name, - "test.example.com", - "The name of the file containing the leaf certificate."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + string, + intermediate_certificate_name, + "intermediate.crt", + "The name of the file containing the intermediate certificate."); + +DEFINE_QUIC_COMMAND_LINE_FLAG( + string, + leaf_certificate_name, + "test.example.com", + "The name of the file containing the leaf certificate."); std::unique_ptr<quic::ProofSource> CreateProofSource( const string& base_directory, @@ -49,20 +62,28 @@ } int main(int argc, char* argv[]) { - InitGoogle(argv[0], &argc, &argv, true); - - quic::QuicMemoryCacheBackend memory_cache_backend; - if (!FLAGS_quic_response_cache_dir.empty()) { - memory_cache_backend.InitializeBackend(FLAGS_quic_response_cache_dir); + const char* usage = "Usage: quic_server [options]"; + std::vector<quic::QuicString> non_option_args = + quic::QuicParseCommandLineFlags(usage, argc, argv); + if (!non_option_args.empty()) { + quic::QuicPrintCommandLineFlagHelp(usage); + exit(0); } - quic::QuicServer server(CreateProofSource(FLAGS_certificate_dir, - FLAGS_intermediate_certificate_name, - FLAGS_leaf_certificate_name), - &memory_cache_backend); + quic::QuicMemoryCacheBackend memory_cache_backend; + if (!GetQuicFlag(FLAGS_quic_response_cache_dir).empty()) { + memory_cache_backend.InitializeBackend( + GetQuicFlag(FLAGS_quic_response_cache_dir)); + } - if (!server.CreateUDPSocketAndListen( - quic::QuicSocketAddress(quic::QuicIpAddress::Any6(), FLAGS_port))) { + quic::QuicServer server( + CreateProofSource(GetQuicFlag(FLAGS_certificate_dir), + GetQuicFlag(FLAGS_intermediate_certificate_name), + GetQuicFlag(FLAGS_leaf_certificate_name)), + &memory_cache_backend); + + if (!server.CreateUDPSocketAndListen(quic::QuicSocketAddress( + quic::QuicIpAddress::Any6(), GetQuicFlag(FLAGS_port)))) { return 1; }
diff --git a/quic/tools/quic_server_test.cc b/quic/tools/quic_server_test.cc index f549ad4..7b5cd58 100644 --- a/quic/tools/quic_server_test.cc +++ b/quic/tools/quic_server_test.cc
@@ -7,7 +7,6 @@ #include <string.h> #include <sys/socket.h> -#include "net/util/netutil.h" #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h" #include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" @@ -15,6 +14,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.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/platform/api/quic_port_utils.h" #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h" @@ -35,7 +35,7 @@ class QuicServerTest : public QuicTest {}; TEST_F(QuicServerTest, TestDroppedPackets) { - int port = net_util::PickUnusedPortOrDie(); + int port = QuicPickUnusedPortOrDie(); QuicSocketAddress server_address(TestLoopback(), port); QuicMemoryCacheBackend response_cache; @@ -78,7 +78,7 @@ class MockQuicSimpleDispatcher : public QuicSimpleDispatcher { public: MockQuicSimpleDispatcher( - const QuicConfig& config, + const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper, @@ -113,7 +113,7 @@ protected: QuicDispatcher* CreateQuicDispatcher() override { mock_dispatcher_ = new MockQuicSimpleDispatcher( - config(), &crypto_config(), version_manager(), + &config(), &crypto_config(), version_manager(), std::unique_ptr<QuicEpollConnectionHelper>( new QuicEpollConnectionHelper(epoll_server(), QuicAllocator::BUFFER_POOL)), @@ -132,7 +132,7 @@ class QuicServerEpollInTest : public QuicTest { public: QuicServerEpollInTest() - : port_(net_util::PickUnusedPortOrDie()), + : port_(QuicPickUnusedPortOrDie()), server_address_(TestLoopback(), port_) {} void StartListening() { @@ -203,7 +203,7 @@ TlsServerHandshaker::CreateSslCtx()), version_manager_(AllSupportedVersions()), dispatcher_( - config_, + &config_, &crypto_config_, &version_manager_, std::unique_ptr<QuicEpollConnectionHelper>(
diff --git a/quic/tools/quic_simple_crypto_server_stream_helper.cc b/quic/tools/quic_simple_crypto_server_stream_helper.cc index 567c670..bdd6731 100644 --- a/quic/tools/quic_simple_crypto_server_stream_helper.cc +++ b/quic/tools/quic_simple_crypto_server_stream_helper.cc
@@ -19,7 +19,7 @@ QuicSimpleCryptoServerStreamHelper::GenerateConnectionIdForReject( QuicTransportVersion /*version*/, QuicConnectionId /*connection_id*/) const { - return QuicUtils::CreateRandomConnectionId(random_, Perspective::IS_SERVER); + return QuicUtils::CreateRandomConnectionId(random_); } bool QuicSimpleCryptoServerStreamHelper::CanAcceptClientHello( @@ -27,7 +27,7 @@ const QuicSocketAddress& client_address, const QuicSocketAddress& peer_address, const QuicSocketAddress& self_address, - string* error_details) const { + QuicString* error_details) const { return true; }
diff --git a/quic/tools/quic_simple_crypto_server_stream_helper_test.cc b/quic/tools/quic_simple_crypto_server_stream_helper_test.cc index 652f282..4ede588 100644 --- a/quic/tools/quic_simple_crypto_server_stream_helper_test.cc +++ b/quic/tools/quic_simple_crypto_server_stream_helper_test.cc
@@ -1,3 +1,7 @@ +// 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. + #include "net/third_party/quiche/src/quic/tools/quic_simple_crypto_server_stream_helper.h" #include "net/third_party/quiche/src/quic/core/quic_utils.h" @@ -14,10 +18,6 @@ QuicSimpleCryptoServerStreamHelper helper(&random); EXPECT_EQ(QuicUtils::CreateRandomConnectionId(&random), - helper.GenerateConnectionIdForReject(QUIC_VERSION_35, - test::TestConnectionId())); - - EXPECT_EQ(QuicUtils::CreateRandomConnectionId(&random), helper.GenerateConnectionIdForReject(QUIC_VERSION_99, test::TestConnectionId())); }
diff --git a/quic/tools/quic_simple_dispatcher.cc b/quic/tools/quic_simple_dispatcher.cc index 166dd0b..942eb0a 100644 --- a/quic/tools/quic_simple_dispatcher.cc +++ b/quic/tools/quic_simple_dispatcher.cc
@@ -9,7 +9,7 @@ namespace quic { QuicSimpleDispatcher::QuicSimpleDispatcher( - const QuicConfig& config, + const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/tools/quic_simple_dispatcher.h b/quic/tools/quic_simple_dispatcher.h index 3ee8c0e..6f13d39 100644 --- a/quic/tools/quic_simple_dispatcher.h +++ b/quic/tools/quic_simple_dispatcher.h
@@ -14,7 +14,7 @@ class QuicSimpleDispatcher : public QuicDispatcher { public: QuicSimpleDispatcher( - const QuicConfig& config, + const QuicConfig* config, const QuicCryptoServerConfig* crypto_config, QuicVersionManager* version_manager, std::unique_ptr<QuicConnectionHelperInterface> helper,
diff --git a/quic/tools/quic_simple_server_session.h b/quic/tools/quic_simple_server_session.h index d459da6..45c97d0 100644 --- a/quic/tools/quic_simple_server_session.h +++ b/quic/tools/quic_simple_server_session.h
@@ -7,7 +7,10 @@ #ifndef QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_SESSION_H_ #define QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_SESSION_H_ +#include <stdint.h> + #include <list> +#include <memory> #include <set> #include <string> #include <utility>
diff --git a/quic/tools/quic_simple_server_session_test.cc b/quic/tools/quic_simple_server_session_test.cc index 1ba330d..832a611 100644 --- a/quic/tools/quic_simple_server_session_test.cc +++ b/quic/tools/quic_simple_server_session_test.cc
@@ -40,6 +40,7 @@ using testing::_; using testing::AtLeast; using testing::InSequence; +using testing::Invoke; using testing::Return; using testing::StrictMock; @@ -119,7 +120,15 @@ : MockQuicConnection(helper, alarm_factory, perspective, - supported_versions) {} + supported_versions) { + auto consume_all_data = [](QuicStreamId id, size_t write_length, + QuicStreamOffset offset, + StreamSendingState state) { + return QuicConsumedData(write_length, state != NO_FIN); + }; + ON_CALL(*this, SendStreamData(_, _, _, _)) + .WillByDefault(Invoke(consume_all_data)); + } MOCK_METHOD4(SendStreamData, QuicConsumedData(QuicStreamId id, @@ -159,22 +168,6 @@ QuicStreamId promised_stream_id, const spdy::SpdyHeaderBlock& headers)); - size_t WriteHeaders(QuicStreamId stream_id, - spdy::SpdyHeaderBlock headers, - bool fin, - spdy::SpdyPriority priority, - QuicReferenceCountedPointer<QuicAckListenerInterface> - ack_listener) override { - return WriteHeadersMock(stream_id, headers, fin, priority, ack_listener); - } - MOCK_METHOD5( - WriteHeadersMock, - size_t(QuicStreamId stream_id, - const spdy::SpdyHeaderBlock& headers, - bool fin, - spdy::SpdyPriority priority, - const QuicReferenceCountedPointer<QuicAckListenerInterface>& - ack_listener)); MOCK_METHOD1(SendBlocked, void(QuicStreamId)); }; @@ -232,7 +225,7 @@ ->OnSuccessfulVersionNegotiation(supported_versions.front()); visitor_ = QuicConnectionPeer::GetVisitor(connection_); - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly(Invoke( this, @@ -242,13 +235,17 @@ } QuicStreamId GetNthClientInitiatedBidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - *session_, n); + return GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), n); } QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) { - return QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId( - *session_, n); + return quic::test::GetNthServerInitiatedUnidirectionalStreamId( + connection_->transport_version(), n); + } + + bool IsVersion99() const { + return connection_->transport_version() == QUIC_VERSION_99; } void InjectStopSending(QuicStreamId stream_id, @@ -256,7 +253,7 @@ // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes // a one-way close. - if (connection_->transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { // Only needed for version 99/IETF QUIC. return; } @@ -284,9 +281,9 @@ QuicConnectionVisitorInterface* visitor_; }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSimpleServerSessionTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSimpleServerSessionTest, + ::testing::ValuesIn(AllSupportedVersions())); TEST_P(QuicSimpleServerSessionTest, CloseStreamDueToReset) { // Open a stream, then reset it. @@ -302,9 +299,12 @@ QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(GetNthClientInitiatedBidirectionalId(0), - QUIC_RST_ACKNOWLEDGEMENT)); + if (!IsVersion99()) { + // For version 99, this is covered in InjectStopSending() + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); + } visitor_->OnRstStream(rst1); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes @@ -327,12 +327,13 @@ GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - if (connection_->transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)); + // For version 99, this is covered in InjectStopSending() + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); } - EXPECT_CALL(*connection_, - OnStreamReset(GetNthClientInitiatedBidirectionalId(0), - QUIC_RST_ACKNOWLEDGEMENT)); visitor_->OnRstStream(rst1); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes @@ -367,12 +368,13 @@ GetNthClientInitiatedBidirectionalId(0), QUIC_ERROR_PROCESSING_STREAM, 0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); - if (connection_->transport_version() != QUIC_VERSION_99) { + if (!IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)); + // For version 99, this is covered in InjectStopSending() + EXPECT_CALL(*connection_, + OnStreamReset(GetNthClientInitiatedBidirectionalId(0), + QUIC_RST_ACKNOWLEDGEMENT)); } - EXPECT_CALL(*connection_, - OnStreamReset(GetNthClientInitiatedBidirectionalId(0), - QUIC_RST_ACKNOWLEDGEMENT)); visitor_->OnRstStream(rst); // Create and inject a STOP_SENDING frame. In GOOGLE QUIC, receiving a // RST_STREAM frame causes a two-way close. For IETF QUIC, RST_STREAM causes @@ -541,7 +543,7 @@ protected: const size_t kStreamFlowControlWindowSize = 32 * 1024; // 32KB. - QuicSimpleServerSessionServerPushTest() : QuicSimpleServerSessionTest() { + QuicSimpleServerSessionServerPushTest() { // Reset stream level flow control window to be 32KB. QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow( &config_, kStreamFlowControlWindowSize); @@ -550,10 +552,6 @@ // control blocks it. QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( &config_, kInitialSessionFlowControlWindowForTest); - // Enable server push. - QuicTagVector copt; - copt.push_back(kSPSH); - QuicConfigPeer::SetReceivedConnectionOptions(&config_, copt); ParsedQuicVersionVector supported_versions = SupportedVersions(GetParam()); connection_ = new StrictMock<MockQuicConnectionWithSendStreamData>( @@ -566,7 +564,7 @@ ->OnSuccessfulVersionNegotiation(supported_versions.front()); // Needed to make new session flow control window and server push work. - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { EXPECT_CALL(*connection_, SendControlFrame(_)) .WillRepeatedly(Invoke(this, &QuicSimpleServerSessionServerPushTest:: ClearMaxStreamIdControlFrame)); @@ -619,7 +617,7 @@ QuicString body(body_size, 'a'); QuicString data; header_length = 0; - if (connection_->transport_version() == QUIC_VERSION_99) { + if (VersionHasDataFrameHeader(connection_->transport_version())) { HttpEncoder encoder; std::unique_ptr<char[]> buffer; header_length = @@ -640,14 +638,11 @@ stream_id, _)); if (i <= kMaxStreamsForTest) { // |kMaxStreamsForTest| promised responses should be sent. - EXPECT_CALL(*session_, - WriteHeadersMock(stream_id, _, false, - QuicStream::kDefaultPriority, _)); // Since flow control window is smaller than response body, not the // whole body will be sent. - if (connection_->transport_version() == QUIC_VERSION_99) { - EXPECT_CALL(*connection_, SendStreamData(stream_id, _, 0, NO_FIN)) - .WillOnce(Return(QuicConsumedData(header_length, false))); + if (VersionHasDataFrameHeader(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_id, header_length, 0, NO_FIN)); } EXPECT_CALL(*connection_, SendStreamData(stream_id, _, header_length, NO_FIN)) @@ -661,26 +656,34 @@ request_headers); return header_length; } + + void ConsumeHeadersStreamData() { + QuicStreamId headers_stream_id = + QuicUtils::GetHeadersStreamId(connection_->transport_version()); + EXPECT_CALL(*connection_, SendStreamData(headers_stream_id, _, _, _)) + .Times(AtLeast(1)); + } }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSimpleServerSessionServerPushTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSimpleServerSessionServerPushTest, + ::testing::ValuesIn(AllSupportedVersions())); +// Tests that given more than kMaxStreamsForTest resources, all their +// PUSH_PROMISE's will be sent out and only kMaxStreamsForTest streams will be +// opened and send push response. TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) { - // Tests that given more than kMaxOpenStreamForTest resources, all their - // PUSH_PROMISE's will be sent out and only |kMaxOpenStreamForTest| streams - // will be opened and send push response. - + ConsumeHeadersStreamData(); size_t num_resources = kMaxStreamsForTest + 5; PromisePushResources(num_resources); EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); } +// Tests that after promised stream queued up, when an opened stream is marked +// draining, a queued promised stream will become open and send push response. TEST_P(QuicSimpleServerSessionServerPushTest, HandlePromisedPushRequestsAfterStreamDraining) { - // Tests that after promised stream queued up, when an opened stream is marked - // draining, a queued promised stream will become open and send push response. + ConsumeHeadersStreamData(); size_t num_resources = kMaxStreamsForTest + 1; QuicByteCount header_length = PromisePushResources(num_resources); QuicStreamId next_out_going_stream_id = @@ -688,12 +691,9 @@ // After an open stream is marked draining, a new stream is expected to be // created and a response sent on the stream. - EXPECT_CALL(*session_, WriteHeadersMock(next_out_going_stream_id, _, false, - QuicStream::kDefaultPriority, _)); - if (connection_->transport_version() == QUIC_VERSION_99) { - EXPECT_CALL(*connection_, - SendStreamData(next_out_going_stream_id, _, 0, NO_FIN)) - .WillOnce(Return(QuicConsumedData(header_length, false))); + if (VersionHasDataFrameHeader(connection_->transport_version())) { + EXPECT_CALL(*connection_, SendStreamData(next_out_going_stream_id, + header_length, 0, NO_FIN)); } EXPECT_CALL(*connection_, SendStreamData(next_out_going_stream_id, _, header_length, NO_FIN)) @@ -701,7 +701,7 @@ kStreamFlowControlWindowSize - header_length, false))); EXPECT_CALL(*session_, SendBlocked(next_out_going_stream_id)); - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // The PromisePushedResources call, above, will have used all available // stream ids. For version 99, stream ids are not made available until // a MAX_STREAM_ID frame is received. This emulates the reception of one. @@ -716,15 +716,16 @@ EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); } +// Tests that after all resources are promised, a RST frame from client can +// prevent a promised resource to be send out. TEST_P(QuicSimpleServerSessionServerPushTest, ResetPromisedStreamToCancelServerPush) { - // Tests that after all resources are promised, a RST frame from client can - // prevent a promised resource to be send out. + ConsumeHeadersStreamData(); // Having two extra resources to be send later. One of them will be reset, so // when opened stream become close, only one will become open. size_t num_resources = kMaxStreamsForTest + 2; - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // V99 will send out a stream-id-blocked frame when the we desired to exceed // the limit. This will clear the frames so that they do not block the later // rst-stream frame. @@ -753,22 +754,17 @@ QuicStreamId stream_not_reset = GetNthServerInitiatedUnidirectionalId(kMaxStreamsForTest); InSequence s; - EXPECT_CALL(*session_, WriteHeadersMock(stream_not_reset, _, false, - QuicStream::kDefaultPriority, _)); - if (connection_->transport_version() == QUIC_VERSION_99) { - EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, _, 0, NO_FIN)) - .WillOnce(Return(QuicConsumedData(header_length, false))); + if (VersionHasDataFrameHeader(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_not_reset, header_length, 0, NO_FIN)); } EXPECT_CALL(*connection_, SendStreamData(stream_not_reset, _, header_length, NO_FIN)) .WillOnce(Return(QuicConsumedData( kStreamFlowControlWindowSize - header_length, false))); EXPECT_CALL(*session_, SendBlocked(stream_not_reset)); - EXPECT_CALL(*session_, WriteHeadersMock(stream_got_reset, _, false, - QuicStream::kDefaultPriority, _)) - .Times(0); - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // The PromisePushedResources call, above, will have used all available // stream ids. For version 99, stream ids are not made available until // a MAX_STREAM_ID frame is received. This emulates the reception of one. @@ -781,12 +777,13 @@ session_->StreamDraining(GetNthServerInitiatedUnidirectionalId(1)); } +// Tests that closing a open outgoing stream can trigger a promised resource in +// the queue to be send out. TEST_P(QuicSimpleServerSessionServerPushTest, CloseStreamToHandleMorePromisedStream) { - // Tests that closing a open outgoing stream can trigger a promised resource - // in the queue to be send out. + ConsumeHeadersStreamData(); size_t num_resources = kMaxStreamsForTest + 1; - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // V99 will send out a stream-id-blocked frame when the we desired to exceed // the limit. This will clear the frames so that they do not block the later // rst-stream frame. @@ -803,13 +800,14 @@ QuicStreamId stream_got_reset = GetNthServerInitiatedUnidirectionalId(0); EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1); EXPECT_CALL(*connection_, SendControlFrame(_)); - EXPECT_CALL(*connection_, - OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT)); - EXPECT_CALL(*session_, WriteHeadersMock(stream_to_open, _, false, - QuicStream::kDefaultPriority, _)); - if (connection_->transport_version() == QUIC_VERSION_99) { - EXPECT_CALL(*connection_, SendStreamData(stream_to_open, _, 0, NO_FIN)) - .WillOnce(Return(QuicConsumedData(header_length, false))); + if (!IsVersion99()) { + // For version 99, this is covered in InjectStopSending() + EXPECT_CALL(*connection_, + OnStreamReset(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT)); + } + if (VersionHasDataFrameHeader(connection_->transport_version())) { + EXPECT_CALL(*connection_, + SendStreamData(stream_to_open, header_length, 0, NO_FIN)); } EXPECT_CALL(*connection_, SendStreamData(stream_to_open, _, header_length, NO_FIN)) @@ -819,7 +817,7 @@ EXPECT_CALL(*session_, SendBlocked(stream_to_open)); QuicRstStreamFrame rst(kInvalidControlFrameId, stream_got_reset, QUIC_STREAM_CANCELLED, 0); - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // The PromisePushedResources call, above, will have used all available // stream ids. For version 99, stream ids are not made available until // a MAX_STREAM_ID frame is received. This emulates the reception of one.
diff --git a/quic/tools/quic_simple_server_stream.cc b/quic/tools/quic_simple_server_stream.cc index 1f70a8a..2ae2dbf 100644 --- a/quic/tools/quic_simple_server_stream.cc +++ b/quic/tools/quic_simple_server_stream.cc
@@ -291,7 +291,7 @@ QUIC_DLOG(INFO) << "Stream " << id() << " writing body (fin = false) with size: " << body.size(); if (!body.empty()) { - WriteOrBufferBody(body, /*fin=*/false, nullptr); + WriteOrBufferBody(body, /*fin=*/false); } } @@ -321,7 +321,7 @@ QUIC_DLOG(INFO) << "Stream " << id() << " writing body (fin = " << send_fin << ") with size: " << body.size(); if (!body.empty() || send_fin) { - WriteOrBufferBody(body, send_fin, nullptr); + WriteOrBufferBody(body, send_fin); } if (send_fin) { // Nothing else to send.
diff --git a/quic/tools/quic_simple_server_stream.h b/quic/tools/quic_simple_server_stream.h index 8939a2c..2e6826f 100644 --- a/quic/tools/quic_simple_server_stream.h +++ b/quic/tools/quic_simple_server_stream.h
@@ -15,10 +15,6 @@ namespace quic { -namespace test { -class QuicSimpleServerStreamPeer; -} // namespace test - // All this does right now is aggregate data, and on fin, send an HTTP // response. class QuicSimpleServerStream : public QuicSpdyServerStreamBase, @@ -93,14 +89,12 @@ const QuicString& body() { return body_; } - private: - friend class test::QuicSimpleServerStreamPeer; - // The parsed headers received from the client. spdy::SpdyHeaderBlock request_headers_; int64_t content_length_; QuicString body_; + private: QuicSimpleServerBackend* quic_simple_server_backend_; // Not owned. };
diff --git a/quic/tools/quic_simple_server_stream_test.cc b/quic/tools/quic_simple_server_stream_test.cc index 4e9e68d..a13c9a2 100644 --- a/quic/tools/quic_simple_server_stream_test.cc +++ b/quic/tools/quic_simple_server_stream_test.cc
@@ -32,50 +32,51 @@ using testing::Invoke; using testing::Return; using testing::StrictMock; +using testing::ValuesIn; namespace quic { namespace test { -size_t kFakeFrameLen = 60; +const size_t kFakeFrameLen = 60; +const size_t kErrorLength = strlen(QuicSimpleServerStream::kErrorResponseBody); +const size_t kDataFrameHeaderLength = 2; -class QuicSimpleServerStreamPeer : public QuicSimpleServerStream { +class TestStream : public QuicSimpleServerStream { public: - QuicSimpleServerStreamPeer( - QuicStreamId stream_id, - QuicSpdySession* session, - StreamType type, - QuicSimpleServerBackend* quic_simple_server_backend) + TestStream(QuicStreamId stream_id, + QuicSpdySession* session, + StreamType type, + QuicSimpleServerBackend* quic_simple_server_backend) : QuicSimpleServerStream(stream_id, session, type, quic_simple_server_backend) {} - ~QuicSimpleServerStreamPeer() override = default; + ~TestStream() override = default; - using QuicSimpleServerStream::SendErrorResponse; - using QuicSimpleServerStream::SendResponse; + MOCK_METHOD1(WriteHeadersMock, void(bool fin)); + + size_t WriteHeaders(spdy::SpdyHeaderBlock header_block, + bool fin, + QuicReferenceCountedPointer<QuicAckListenerInterface> + ack_listener) override { + WriteHeadersMock(fin); + return 0; + } + + // Expose protected QuicSimpleServerStream methods. + void DoSendResponse() { SendResponse(); } + void DoSendErrorResponse() { SendErrorResponse(); } spdy::SpdyHeaderBlock* mutable_headers() { return &request_headers_; } void set_body(QuicString body) { body_ = std::move(body); } + const QuicString& body() const { return body_; } + int content_length() const { return content_length_; } - static void SendResponse(QuicSimpleServerStream* stream) { - stream->SendResponse(); - } - - static void SendErrorResponse(QuicSimpleServerStream* stream) { - stream->SendErrorResponse(); - } - - static const QuicString& body(QuicSimpleServerStream* stream) { - return stream->body_; - } - - static int content_length(QuicSimpleServerStream* stream) { - return stream->content_length_; - } - - static spdy::SpdyHeaderBlock& headers(QuicSimpleServerStream* stream) { - return stream->request_headers_; + QuicStringPiece GetHeader(QuicStringPiece key) const { + auto it = request_headers_.find(key); + DCHECK(it != request_headers_.end()); + return it->second; } }; @@ -85,7 +86,7 @@ public: const size_t kMaxStreamsForTest = 100; - explicit MockQuicSimpleServerSession( + MockQuicSimpleServerSession( QuicConnection* connection, MockQuicSessionVisitor* owner, MockQuicCryptoServerStreamHelper* helper, @@ -103,7 +104,7 @@ QuicSessionPeer::SetMaxOpenIncomingStreams(this, kMaxStreamsForTest); QuicSessionPeer::SetMaxOpenOutgoingStreams(this, kMaxStreamsForTest); ON_CALL(*this, WritevData(_, _, _, _, _)) - .WillByDefault(testing::Return(QuicConsumedData(0, false))); + .WillByDefault(Invoke(MockQuicSession::ConsumeData)); } MockQuicSimpleServerSession(const MockQuicSimpleServerSession&) = delete; @@ -129,24 +130,6 @@ const QuicHeaderList& header_list)); MOCK_METHOD2(OnStreamHeadersPriority, void(QuicStreamId stream_id, spdy::SpdyPriority priority)); - // Methods taking non-copyable types like SpdyHeaderBlock by value cannot be - // mocked directly. - size_t WriteHeaders(QuicStreamId id, - spdy::SpdyHeaderBlock headers, - bool fin, - spdy::SpdyPriority priority, - QuicReferenceCountedPointer<QuicAckListenerInterface> - ack_listener) override { - return WriteHeadersMock(id, headers, fin, priority, ack_listener); - } - MOCK_METHOD5( - WriteHeadersMock, - size_t(QuicStreamId id, - const spdy::SpdyHeaderBlock& headers, - bool fin, - spdy::SpdyPriority priority, - const QuicReferenceCountedPointer<QuicAckListenerInterface>& - ack_listener)); MOCK_METHOD3(SendRstStream, void(QuicStreamId stream_id, QuicRstStreamErrorCode error, @@ -198,8 +181,7 @@ &compressed_certs_cache_, &memory_cache_backend_), quic_response_(new QuicBackendResponse), - body_("hello world"), - is_version_99_(connection_->transport_version() == QUIC_VERSION_99) { + body_("hello world") { connection_->set_visitor(&session_); header_list_.OnHeaderBlockStart(); header_list_.OnHeader(":authority", "www.google.com"); @@ -216,23 +198,29 @@ kInitialStreamFlowControlWindowForTest); session_.config()->SetInitialSessionFlowControlWindowToSend( kInitialSessionFlowControlWindowForTest); - stream_ = new QuicSimpleServerStreamPeer( - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 0), + stream_ = new StrictMock<TestStream>( + GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 0), &session_, BIDIRECTIONAL, &memory_cache_backend_); // Register stream_ in dynamic_stream_map_ and pass ownership to session_. session_.ActivateStream(QuicWrapUnique(stream_)); connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); } - const QuicString& StreamBody() { - return QuicSimpleServerStreamPeer::body(stream_); - } + const QuicString& StreamBody() { return stream_->body(); } QuicString StreamHeadersValue(const QuicString& key) { return (*stream_->mutable_headers())[key].as_string(); } + bool IsVersion99() const { + return connection_->transport_version() == QUIC_VERSION_99; + } + + bool HasFrameHeader() const { + return VersionHasDataFrameHeader(connection_->transport_version()); + } + spdy::SpdyHeaderBlock response_headers_; MockQuicConnectionHelper helper_; MockAlarmFactory alarm_factory_; @@ -243,28 +231,26 @@ QuicCompressedCertsCache compressed_certs_cache_; QuicMemoryCacheBackend memory_cache_backend_; StrictMock<MockQuicSimpleServerSession> session_; - QuicSimpleServerStreamPeer* stream_; // Owned by session_. + StrictMock<TestStream>* stream_; // Owned by session_. std::unique_ptr<QuicBackendResponse> quic_response_; QuicString body_; QuicHeaderList header_list_; HttpEncoder encoder_; - bool is_version_99_; }; -INSTANTIATE_TEST_CASE_P(Tests, - QuicSimpleServerStreamTest, - ::testing::ValuesIn(AllSupportedVersions())); +INSTANTIATE_TEST_SUITE_P(Tests, + QuicSimpleServerStreamTest, + ValuesIn(AllSupportedVersions())); TEST_P(QuicSimpleServerStreamTest, TestFraming) { EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); std::unique_ptr<char[]> buffer; QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body_.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = is_version_99_ ? header + body_ : body_; + QuicString data = HasFrameHeader() ? header + body_ : body_; stream_->OnStreamFrame( QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data)); EXPECT_EQ("11", StreamHeadersValue("content-length")); @@ -275,7 +261,6 @@ TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) { EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); @@ -283,7 +268,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body_.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = is_version_99_ ? header + body_ : body_; + QuicString data = HasFrameHeader() ? header + body_ : body_; stream_->OnStreamFrame( QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data)); EXPECT_EQ("11", StreamHeadersValue("content-length")); @@ -294,7 +279,6 @@ TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) { EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); EXPECT_FALSE(stream_->fin_received()); @@ -308,18 +292,16 @@ } TEST_P(QuicSimpleServerStreamTest, TestFramingExtraData) { - testing::InSequence seq; + InSequence seq; QuicString large_body = "hello world!!!!!!"; // We'll automatically write out an error (headers + body) - EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _)); - if (is_version_99_) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .WillOnce(Invoke(MockQuicSession::ConsumeData)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); + if (HasFrameHeader()) { + EXPECT_CALL(session_, WritevData(_, _, kDataFrameHeaderLength, _, NO_FIN)); } + EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .WillOnce(Invoke(MockQuicSession::ConsumeData)); EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0); stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); @@ -327,7 +309,7 @@ QuicByteCount header_length = encoder_.SerializeDataFrameHeader(body_.length(), &buffer); QuicString header = QuicString(buffer.get(), header_length); - QuicString data = is_version_99_ ? header + body_ : body_; + QuicString data = HasFrameHeader() ? header + body_ : body_; stream_->OnStreamFrame( QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data)); @@ -336,7 +318,7 @@ header_length = encoder_.SerializeDataFrameHeader(large_body.length(), &buffer); header = QuicString(buffer.get(), header_length); - QuicString data2 = is_version_99_ ? header + large_body : large_body; + QuicString data2 = HasFrameHeader() ? header + large_body : large_body; stream_->OnStreamFrame( QuicStreamFrame(stream_->id(), /*fin=*/true, data.size(), data2)); EXPECT_EQ("11", StreamHeadersValue("content-length")); @@ -367,18 +349,13 @@ stream_->set_fin_received(true); InSequence s; - EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _)); - if (is_version_99_) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(header_length, false))); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); + if (HasFrameHeader()) { + EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN)); } - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData( - strlen(QuicSimpleServerStream::kErrorResponseBody), true))); + EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN)); - QuicSimpleServerStreamPeer::SendResponse(stream_); + stream_->DoSendResponse(); EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_TRUE(stream_->write_side_closed()); } @@ -407,27 +384,22 @@ stream_->set_fin_received(true); InSequence s; - EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _)); - if (is_version_99_) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(header_length, false))); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); + if (HasFrameHeader()) { + EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN)); } - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData( - strlen(QuicSimpleServerStream::kErrorResponseBody), true))); + EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN)); - QuicSimpleServerStreamPeer::SendResponse(stream_); + stream_->DoSendResponse(); EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_TRUE(stream_->write_side_closed()); } TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response) { // Create a new promised stream with even id(). - QuicSimpleServerStreamPeer* promised_stream = new QuicSimpleServerStreamPeer( - QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(session_, - 0), + auto promised_stream = new StrictMock<TestStream>( + GetNthServerInitiatedUnidirectionalStreamId( + connection_->transport_version(), 0), &session_, WRITE_UNIDIRECTIONAL, &memory_cache_backend_); session_.ActivateStream(QuicWrapUnique(promised_stream)); @@ -451,7 +423,7 @@ EXPECT_CALL(session_, SendRstStream(promised_stream->id(), QUIC_STREAM_CANCELLED, 0)); - QuicSimpleServerStreamPeer::SendResponse(promised_stream); + promised_stream->DoSendResponse(); } TEST_P(QuicSimpleServerStreamTest, SendResponseWithValidHeaders) { @@ -476,17 +448,13 @@ stream_->set_fin_received(true); InSequence s; - EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _)); - if (is_version_99_) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(header_length, false))); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); + if (HasFrameHeader()) { + EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN)); } - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(body.length(), true))); + EXPECT_CALL(session_, WritevData(_, _, body.length(), _, FIN)); - QuicSimpleServerStreamPeer::SendResponse(stream_); + stream_->DoSendResponse(); EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_TRUE(stream_->write_side_closed()); } @@ -518,23 +486,17 @@ stream_->set_fin_received(true); InSequence s; - EXPECT_CALL( - session_, - PromisePushResourcesMock( - host + request_path, _, - QuicSpdySessionPeer::GetNthClientInitiatedBidirectionalStreamId( - session_, 0), - _)); - EXPECT_CALL(session_, WriteHeadersMock(stream_->id(), _, false, _, _)); - if (is_version_99_) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(header_length, false))); + EXPECT_CALL(session_, PromisePushResourcesMock( + host + request_path, _, + GetNthClientInitiatedBidirectionalStreamId( + connection_->transport_version(), 0), + _)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); + if (HasFrameHeader()) { + EXPECT_CALL(session_, WritevData(_, _, header_length, _, NO_FIN)); } - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(body.length(), true))); - QuicSimpleServerStreamPeer::SendResponse(stream_); + EXPECT_CALL(session_, WritevData(_, _, body.length(), _, FIN)); + stream_->DoSendResponse(); EXPECT_EQ(*request_headers, session_.original_request_headers_); } @@ -557,13 +519,12 @@ // Create a stream with even stream id and test against this stream. const QuicStreamId kServerInitiatedStreamId = - QuicSpdySessionPeer::GetNthServerInitiatedUnidirectionalStreamId(session_, - 0); + GetNthServerInitiatedUnidirectionalStreamId( + connection_->transport_version(), 0); // Create a server initiated stream and pass it to session_. - QuicSimpleServerStreamPeer* server_initiated_stream = - new QuicSimpleServerStreamPeer(kServerInitiatedStreamId, &session_, - WRITE_UNIDIRECTIONAL, - &memory_cache_backend_); + auto server_initiated_stream = + new StrictMock<TestStream>(kServerInitiatedStreamId, &session_, + WRITE_UNIDIRECTIONAL, &memory_cache_backend_); session_.ActivateStream(QuicWrapUnique(server_initiated_stream)); const QuicString kHost = "www.foo.com"; @@ -586,26 +547,18 @@ // Call PushResponse() should trigger stream to fetch response from cache // and send it back. - EXPECT_CALL(session_, - WriteHeadersMock(kServerInitiatedStreamId, _, false, - server_initiated_stream->priority(), _)); - InSequence s; - if (is_version_99_) { - EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(header_length, false))); + EXPECT_CALL(*server_initiated_stream, WriteHeadersMock(false)); + + if (HasFrameHeader()) { + EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, header_length, + _, NO_FIN)); } - EXPECT_CALL(session_, WritevData(_, kServerInitiatedStreamId, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(kBody.size(), true))); + EXPECT_CALL(session_, + WritevData(_, kServerInitiatedStreamId, kBody.size(), _, FIN)); server_initiated_stream->PushResponse(std::move(headers)); - EXPECT_EQ(kPath, QuicSimpleServerStreamPeer::headers( - server_initiated_stream)[":path"] - .as_string()); - EXPECT_EQ("GET", QuicSimpleServerStreamPeer::headers( - server_initiated_stream)[":method"] - .as_string()); + EXPECT_EQ(kPath, server_initiated_stream->GetHeader(":path")); + EXPECT_EQ("GET", server_initiated_stream->GetHeader(":method")); } TEST_P(QuicSimpleServerStreamTest, TestSendErrorResponse) { @@ -614,17 +567,13 @@ stream_->set_fin_received(true); InSequence s; - EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _)); - if (is_version_99_) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(2, false))); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); + if (HasFrameHeader()) { + EXPECT_CALL(session_, WritevData(_, _, kDataFrameHeaderLength, _, NO_FIN)); } - EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(1) - .WillOnce(Return(QuicConsumedData(3, true))); + EXPECT_CALL(session_, WritevData(_, _, kErrorLength, _, FIN)); - QuicSimpleServerStreamPeer::SendErrorResponse(stream_); + stream_->DoSendErrorResponse(); EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_TRUE(stream_->write_side_closed()); } @@ -636,9 +585,8 @@ // \000 is a way to write the null byte when followed by a literal digit. header_list_.OnHeader("content-length", QuicStringPiece("11\00012", 5)); - EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_); @@ -654,9 +602,8 @@ // \000 is a way to write the null byte when followed by a literal digit. header_list_.OnHeader("content-length", QuicStringPiece("\00012", 3)); - EXPECT_CALL(session_, WriteHeadersMock(_, _, _, _, _)); + EXPECT_CALL(*stream_, WriteHeadersMock(false)); EXPECT_CALL(session_, WritevData(_, _, _, _, _)) - .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSession::ConsumeData)); stream_->OnStreamHeaderList(true, kFakeFrameLen, header_list_); @@ -672,7 +619,7 @@ stream_->OnStreamHeaderList(false, kFakeFrameLen, header_list_); - EXPECT_EQ(11, QuicSimpleServerStreamPeer::content_length(stream_)); + EXPECT_EQ(11, stream_->content_length()); EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_)); EXPECT_FALSE(stream_->reading_stopped()); EXPECT_FALSE(stream_->write_side_closed()); @@ -688,7 +635,7 @@ QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(), QUIC_STREAM_CANCELLED, 1234); stream_->OnStreamReset(rst_frame); - if (connection_->transport_version() == QUIC_VERSION_99) { + if (IsVersion99()) { // For V99 receiving a RST_STREAM causes a 1-way close; the test requires // a full close. A CloseWriteSide closes the other half of the stream. // Everything should then work properly.
diff --git a/quic/tools/quic_tcp_like_trace_converter.h b/quic/tools/quic_tcp_like_trace_converter.h index 6c9a241..4329805 100644 --- a/quic/tools/quic_tcp_like_trace_converter.h +++ b/quic/tools/quic_tcp_like_trace_converter.h
@@ -8,9 +8,10 @@ #include <vector> #include "net/third_party/quiche/src/quic/core/frames/quic_stream_frame.h" +#include "net/third_party/quiche/src/quic/core/quic_interval.h" +#include "net/third_party/quiche/src/quic/core/quic_interval_set.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" -#include "net/third_party/quiche/src/quic/platform/api/quic_interval.h" namespace quic {
diff --git a/spdy/core/hpack/hpack_constants.h b/spdy/core/hpack/hpack_constants.h index 3f4026b..d3f9d8d 100644 --- a/spdy/core/hpack/hpack_constants.h +++ b/spdy/core/hpack/hpack_constants.h
@@ -12,7 +12,8 @@ #include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h" // All section references below are to -// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08 +// https://httpwg.org/specs/rfc7540.html and +// https://httpwg.org/specs/rfc7541.html. namespace spdy { @@ -42,7 +43,7 @@ class HpackHuffmanTable; class HpackStaticTable; -// Defined in RFC 7540, 6.5.2. +// RFC 7540, 6.5.2: Initial value for SETTINGS_HEADER_TABLE_SIZE. const uint32_t kDefaultHeaderTableSizeSetting = 4096; // RFC 7541, 5.2: Flag for a string literal that is stored unmodified (i.e., @@ -69,11 +70,11 @@ // varint-encoded table size with a 5-bit prefix. const HpackPrefix kHeaderTableSizeUpdateOpcode = {0b001, 3}; -// Symbol code table from RFC 7541, "Appendix C. Huffman Code". +// RFC 7541, Appendix B: Huffman Code. SPDY_EXPORT_PRIVATE const std::vector<HpackHuffmanSymbol>& HpackHuffmanCodeVector(); -// Static table from RFC 7541, "Appendix B. Static Table Definition". +// RFC 7541, Appendix A: Static Table Definition. SPDY_EXPORT_PRIVATE const std::vector<HpackStaticEntry>& HpackStaticTableVector(); @@ -87,7 +88,7 @@ // threads. This function is thread-safe. SPDY_EXPORT_PRIVATE const HpackStaticTable& ObtainHpackStaticTable(); -// Pseudo-headers start with a colon. (HTTP2 8.1.2.1., HPACK 3.1.) +// RFC 7541, 8.1.2.1: Pseudo-headers start with a colon. const char kPseudoHeaderPrefix = ':'; } // namespace spdy
diff --git a/spdy/core/hpack/hpack_decoder_adapter_test.cc b/spdy/core/hpack/hpack_decoder_adapter_test.cc index 765c2ea..9c94126 100644 --- a/spdy/core/hpack/hpack_decoder_adapter_test.cc +++ b/spdy/core/hpack/hpack_decoder_adapter_test.cc
@@ -259,15 +259,13 @@ size_t bytes_passed_in_; }; -INSTANTIATE_TEST_CASE_P( - NoHandler, - HpackDecoderAdapterTest, +INSTANTIATE_TEST_SUITE_P( + NoHandler, HpackDecoderAdapterTest, ::testing::Combine(::testing::Values(START_WITHOUT_HANDLER, NO_START), ::testing::Bool())); -INSTANTIATE_TEST_CASE_P( - WithHandler, - HpackDecoderAdapterTest, +INSTANTIATE_TEST_SUITE_P( + WithHandler, HpackDecoderAdapterTest, ::testing::Combine(::testing::Values(START_WITH_HANDLER), ::testing::Bool()));
diff --git a/spdy/core/hpack/hpack_encoder_test.cc b/spdy/core/hpack/hpack_encoder_test.cc index 8ead1c2..7d7d37d 100644 --- a/spdy/core/hpack/hpack_encoder_test.cc +++ b/spdy/core/hpack/hpack_encoder_test.cc
@@ -207,7 +207,8 @@ bool use_incremental_; }; -INSTANTIATE_TEST_CASE_P(HpackEncoderTests, HpackEncoderTest, ::testing::Bool()); +INSTANTIATE_TEST_SUITE_P(HpackEncoderTests, HpackEncoderTest, + ::testing::Bool()); TEST_P(HpackEncoderTest, SingleDynamicIndex) { encoder_.SetHeaderListener(
diff --git a/spdy/core/hpack/hpack_round_trip_test.cc b/spdy/core/hpack/hpack_round_trip_test.cc index 4b3a848..bd4d6ee 100644 --- a/spdy/core/hpack/hpack_round_trip_test.cc +++ b/spdy/core/hpack/hpack_round_trip_test.cc
@@ -78,11 +78,9 @@ HpackDecoderAdapter decoder_; }; -INSTANTIATE_TEST_CASE_P(Tests, - HpackRoundTripTest, - ::testing::Values(ALL_INPUT, - ONE_BYTE, - ZERO_THEN_ONE_BYTE)); +INSTANTIATE_TEST_SUITE_P(Tests, HpackRoundTripTest, + ::testing::Values(ALL_INPUT, ONE_BYTE, + ZERO_THEN_ONE_BYTE)); TEST_P(HpackRoundTripTest, ResponseFixtures) { {
diff --git a/spdy/core/spdy_framer_test.cc b/spdy/core/spdy_framer_test.cc index a08d7d7..3841172 100644 --- a/spdy/core/spdy_framer_test.cc +++ b/spdy/core/spdy_framer_test.cc
@@ -615,9 +615,8 @@ Http2DecoderAdapter deframer_; }; -INSTANTIATE_TEST_CASE_P(SpdyFramerTests, - SpdyFramerTest, - ::testing::Values(USE, NOT_USE)); +INSTANTIATE_TEST_SUITE_P(SpdyFramerTests, SpdyFramerTest, + ::testing::Values(USE, NOT_USE)); // Test that we can encode and decode a SpdyHeaderBlock in serialized form. TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {