| // Copyright (c) 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. | |
| // gunit tests for the IETF-format framer --- generally does a simple test | |
| // for each framer; we generate the template object (eg | |
| // QuicIetfStreamFrame) with the correct stuff in it, ask that a frame | |
| // be serialized (call AppendIetf<mumble>) then deserialized (call | |
| // ProcessIetf<mumble>) and then check that the gazintas and gazoutas | |
| // are the same. | |
| // | |
| // We do minimal checking of the serialized frame | |
| // | |
| // We do look at various different values (resulting in different | |
| // length varints, etc) | |
| #include "net/third_party/quiche/src/quic/core/quic_framer.h" | |
| #include <algorithm> | |
| #include <cstdint> | |
| #include <map> | |
| #include <memory> | |
| #include <string> | |
| #include <vector> | |
| #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h" | |
| #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h" | |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_decrypter.h" | |
| #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_data_writer.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_packets.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_utils.h" | |
| #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_ptr_util.h" | |
| #include "net/third_party/quiche/src/quic/platform/api/quic_test.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" | |
| namespace quic { | |
| namespace test { | |
| namespace { | |
| const size_t kNormalPacketBufferSize = 1400; | |
| // 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); | |
| const QuicIetfStreamId kStreamId1 = UINT64_C(0x10); | |
| const QuicIetfStreamId kStreamId0 = UINT64_C(0x00); | |
| // Ditto for the offsets. | |
| const QuicIetfStreamOffset kOffset8 = UINT64_C(0x3210BA9876543210); | |
| const QuicIetfStreamOffset kOffset4 = UINT64_C(0x32109876); | |
| const QuicIetfStreamOffset kOffset2 = UINT64_C(0x3456); | |
| const QuicIetfStreamOffset kOffset1 = UINT64_C(0x3f); | |
| const QuicIetfStreamOffset kOffset0 = UINT64_C(0x00); | |
| // Structures used to create various ack frames. | |
| // Defines an ack frame to feed through the framer/deframer. | |
| struct ack_frame { | |
| uint64_t delay_time; | |
| bool is_ack_ecn; | |
| QuicPacketCount ect_0_count; | |
| QuicPacketCount ect_1_count; | |
| QuicPacketCount ecn_ce_count; | |
| const std::vector<QuicAckBlock>& ranges; | |
| uint64_t expected_frame_type; | |
| }; | |
| class TestQuicVisitor : public QuicFramerVisitorInterface { | |
| public: | |
| TestQuicVisitor() {} | |
| ~TestQuicVisitor() override {} | |
| void OnError(QuicFramer* f) override { | |
| QUIC_DLOG(INFO) << "QuicIetfFramer Error: " | |
| << QuicErrorCodeToString(f->error()) << " (" << f->error() | |
| << ")"; | |
| } | |
| void OnPacket() override {} | |
| void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} | |
| void OnVersionNegotiationPacket( | |
| const QuicVersionNegotiationPacket& packet) override {} | |
| void OnRetryPacket(QuicConnectionId original_connection_id, | |
| QuicConnectionId new_connection_id, | |
| QuicStringPiece retry_token) override {} | |
| bool OnProtocolVersionMismatch(ParsedQuicVersion received_version, | |
| PacketHeaderFormat form) override { | |
| return true; | |
| } | |
| bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override { | |
| return true; | |
| } | |
| bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override { | |
| return true; | |
| } | |
| void OnDecryptedPacket(EncryptionLevel level) override {} | |
| 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; } | |
| bool OnAckFrameStart(QuicPacketNumber largest_acked, | |
| QuicTime::Delta ack_delay_time) override { | |
| return true; | |
| } | |
| bool OnAckRange(QuicPacketNumber start, QuicPacketNumber end) override { | |
| return true; | |
| } | |
| bool OnAckTimestamp(QuicPacketNumber packet_number, | |
| QuicTime timestamp) override { | |
| return true; | |
| } | |
| bool OnAckFrameEnd(QuicPacketNumber start) override { return true; } | |
| bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override { | |
| return true; | |
| } | |
| bool OnPaddingFrame(const QuicPaddingFrame& frame) override { return true; } | |
| bool OnPingFrame(const QuicPingFrame& frame) override { return true; } | |
| bool OnMessageFrame(const QuicMessageFrame& frame) override { return true; } | |
| void OnPacketComplete() override {} | |
| bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { | |
| return true; | |
| } | |
| bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override { | |
| return true; | |
| } | |
| bool OnStopSendingFrame(const QuicStopSendingFrame& frame) override { | |
| return true; | |
| } | |
| bool OnPathChallengeFrame(const QuicPathChallengeFrame& frame) override { | |
| return true; | |
| } | |
| bool OnPathResponseFrame(const QuicPathResponseFrame& frame) override { | |
| return true; | |
| } | |
| bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override { return true; } | |
| bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override { | |
| return true; | |
| } | |
| bool OnBlockedFrame(const QuicBlockedFrame& frame) override { return true; } | |
| bool OnNewConnectionIdFrame(const QuicNewConnectionIdFrame& frame) override { | |
| return true; | |
| } | |
| bool OnRetireConnectionIdFrame( | |
| const QuicRetireConnectionIdFrame& frame) override { | |
| return true; | |
| } | |
| bool OnNewTokenFrame(const QuicNewTokenFrame& frame) override { return true; } | |
| bool IsValidStatelessResetToken(QuicUint128 token) const override { | |
| return true; | |
| } | |
| void OnAuthenticatedIetfStatelessResetPacket( | |
| const QuicIetfStatelessResetPacket& packet) override {} | |
| bool OnMaxStreamsFrame(const QuicMaxStreamsFrame& frame) override { | |
| return true; | |
| } | |
| bool OnStreamsBlockedFrame(const QuicStreamsBlockedFrame& frame) override { | |
| return true; | |
| } | |
| }; | |
| class QuicIetfFramerTest : public QuicTestWithParam<ParsedQuicVersion> { | |
| public: | |
| QuicIetfFramerTest() | |
| : start_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(0x10)), | |
| framer_(AllSupportedVersions(), | |
| start_, | |
| Perspective::IS_SERVER, | |
| kQuicDefaultConnectionIdLength) { | |
| framer_.set_visitor(&visitor_); | |
| } | |
| // Utility functions to do actual framing/deframing. | |
| void TryStreamFrame(char* packet_buffer, | |
| size_t packet_buffer_size, | |
| const char* xmit_packet_data, | |
| size_t xmit_packet_data_size, | |
| QuicIetfStreamId stream_id, | |
| QuicIetfStreamOffset offset, | |
| bool fin_bit, | |
| bool last_frame_bit, | |
| QuicIetfFrameType frame_type) { | |
| // initialize a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(packet_buffer_size, packet_buffer, | |
| NETWORK_BYTE_ORDER); // do not really care | |
| // about endianness. | |
| // set up to define the source frame we wish to send. | |
| QuicStreamFrame source_stream_frame( | |
| stream_id, fin_bit, offset, xmit_packet_data, xmit_packet_data_size); | |
| // Write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendIetfStreamFrame( | |
| &framer_, source_stream_frame, last_frame_bit, &writer)); | |
| // Better have something in the packet buffer. | |
| EXPECT_NE(0u, writer.length()); | |
| // Now set up a reader to read in the frame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| // A StreamFrame to hold the results... we know the frame type, | |
| // put it into the QuicIetfStreamFrame | |
| QuicStreamFrame sink_stream_frame; | |
| if (xmit_packet_data_size) { | |
| EXPECT_EQ(sink_stream_frame.data_buffer, nullptr); | |
| EXPECT_EQ(sink_stream_frame.data_length, 0u); | |
| } | |
| EXPECT_TRUE(QuicFramerPeer::ProcessIetfStreamFrame( | |
| &framer_, &reader, frame_type, &sink_stream_frame)); | |
| // Now check that the streamid, fin-bit, offset, and | |
| // data len all match the input. | |
| EXPECT_EQ(sink_stream_frame.stream_id, source_stream_frame.stream_id); | |
| EXPECT_EQ(sink_stream_frame.fin, source_stream_frame.fin); | |
| EXPECT_EQ(sink_stream_frame.data_length, source_stream_frame.data_length); | |
| if (frame_type & IETF_STREAM_FRAME_OFF_BIT) { | |
| // There was an offset in the frame, see if xmit and rcv vales equal. | |
| EXPECT_EQ(sink_stream_frame.offset, source_stream_frame.offset); | |
| } else { | |
| // Offset not in frame, so it better come out 0. | |
| EXPECT_EQ(sink_stream_frame.offset, 0u); | |
| } | |
| if (xmit_packet_data_size) { | |
| ASSERT_NE(sink_stream_frame.data_buffer, nullptr); | |
| ASSERT_NE(source_stream_frame.data_buffer, nullptr); | |
| EXPECT_EQ(strcmp(sink_stream_frame.data_buffer, | |
| source_stream_frame.data_buffer), | |
| 0); | |
| } else { | |
| // No data in the frame. | |
| EXPECT_EQ(source_stream_frame.data_length, 0u); | |
| EXPECT_EQ(sink_stream_frame.data_length, 0u); | |
| } | |
| } | |
| // Overall ack frame encode/decode/compare function | |
| // Encodes an ack frame as specified at |*frame| | |
| // Then decodes the frame, | |
| // Then compares the two | |
| // Does some basic checking: | |
| // - did the writer write something? | |
| // - did the reader read the entire packet? | |
| // - did the things the reader read match what the writer wrote? | |
| // Returns true if it all worked false if not. | |
| bool TryAckFrame(char* packet_buffer, | |
| size_t packet_buffer_size, | |
| struct ack_frame* frame) { | |
| QuicAckFrame transmit_frame = InitAckFrame(frame->ranges); | |
| if (frame->is_ack_ecn) { | |
| transmit_frame.ecn_counters_populated = true; | |
| transmit_frame.ect_0_count = frame->ect_0_count; | |
| transmit_frame.ect_1_count = frame->ect_1_count; | |
| transmit_frame.ecn_ce_count = frame->ecn_ce_count; | |
| } | |
| transmit_frame.ack_delay_time = | |
| QuicTime::Delta::FromMicroseconds(frame->delay_time); | |
| size_t expected_size = | |
| QuicFramerPeer::GetIetfAckFrameSize(&framer_, transmit_frame); | |
| // Make a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(expected_size, packet_buffer, NETWORK_BYTE_ORDER); | |
| // Write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendIetfAckFrameAndTypeByte( | |
| &framer_, transmit_frame, &writer)); | |
| size_t expected_frame_length = QuicFramerPeer::ComputeFrameLength( | |
| &framer_, QuicFrame(&transmit_frame), false, | |
| static_cast<QuicPacketNumberLength>(123456u)); | |
| // Encoded length should match what ComputeFrameLength returns | |
| EXPECT_EQ(expected_frame_length, writer.length()); | |
| // and what is in the buffer should be the expected size. | |
| EXPECT_EQ(expected_size, writer.length()) << "Frame is " << transmit_frame; | |
| // Now set up a reader to read in the frame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| // read in the frame type | |
| uint8_t received_frame_type; | |
| EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); | |
| EXPECT_EQ(frame->expected_frame_type, received_frame_type); | |
| // an AckFrame to hold the results | |
| QuicAckFrame receive_frame; | |
| EXPECT_TRUE(QuicFramerPeer::ProcessIetfAckFrame( | |
| &framer_, &reader, received_frame_type, &receive_frame)); | |
| if (frame->is_ack_ecn && | |
| (frame->ect_0_count || frame->ect_1_count || frame->ecn_ce_count)) { | |
| EXPECT_TRUE(receive_frame.ecn_counters_populated); | |
| EXPECT_EQ(receive_frame.ect_0_count, frame->ect_0_count); | |
| EXPECT_EQ(receive_frame.ect_1_count, frame->ect_1_count); | |
| EXPECT_EQ(receive_frame.ecn_ce_count, frame->ecn_ce_count); | |
| } else { | |
| EXPECT_FALSE(receive_frame.ecn_counters_populated); | |
| EXPECT_EQ(receive_frame.ect_0_count, 0u); | |
| EXPECT_EQ(receive_frame.ect_1_count, 0u); | |
| EXPECT_EQ(receive_frame.ecn_ce_count, 0u); | |
| } | |
| // Now check that the received frame matches the sent frame. | |
| EXPECT_EQ(transmit_frame.largest_acked, receive_frame.largest_acked); | |
| // The ~0x7 needs some explaining. The ack frame format down shifts the | |
| // delay time by 3 (divide by 8) to allow for greater ranges in delay time. | |
| // Therefore, if we give the framer a delay time that is not an | |
| // even multiple of 8, the value that the deframer produces will | |
| // not be the same as what the framer got. The downshift on | |
| // framing and upshift on deframing results in clearing the 3 | |
| // low-order bits ... The masking basically does the same thing, | |
| // so the compare works properly. | |
| return true; | |
| } | |
| // encode, decode, and check a Path Challenge frame. | |
| bool TryPathChallengeFrame(char* packet_buffer, | |
| size_t packet_buffer_size, | |
| const QuicPathFrameBuffer& data) { | |
| // Make a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(packet_buffer_size, packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicPathChallengeFrame transmit_frame(0, data); | |
| // write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendPathChallengeFrame( | |
| &framer_, transmit_frame, &writer)); | |
| // Check for correct length in the packet buffer. | |
| EXPECT_EQ(kQuicPathChallengeFrameSize, writer.length()); | |
| // now set up a reader to read in the frame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicPathChallengeFrame receive_frame; | |
| EXPECT_TRUE(QuicFramerPeer::ProcessPathChallengeFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Now check that the received frame matches the sent frame. | |
| EXPECT_EQ( | |
| 0, memcmp(transmit_frame.data_buffer.data(), | |
| receive_frame.data_buffer.data(), kQuicPathFrameBufferSize)); | |
| return true; | |
| } | |
| // encode, decode, and check a Path Response frame. | |
| bool TryPathResponseFrame(char* packet_buffer, | |
| size_t packet_buffer_size, | |
| const QuicPathFrameBuffer& data) { | |
| // Make a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(packet_buffer_size, packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicPathResponseFrame transmit_frame(0, data); | |
| // Write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendPathResponseFrame( | |
| &framer_, transmit_frame, &writer)); | |
| // Check for correct length in the packet buffer. | |
| EXPECT_EQ(kQuicPathResponseFrameSize, writer.length()); | |
| // Set up a reader to read in the frame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicPathResponseFrame receive_frame; | |
| EXPECT_TRUE(QuicFramerPeer::ProcessPathResponseFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Now check that the received frame matches the sent frame. | |
| EXPECT_EQ( | |
| 0, memcmp(transmit_frame.data_buffer.data(), | |
| receive_frame.data_buffer.data(), kQuicPathFrameBufferSize)); | |
| return true; | |
| } | |
| // Test the Serialization/deserialization of a Reset Stream Frame. | |
| void TryResetFrame(char* packet_buffer, | |
| size_t packet_buffer_size, | |
| QuicStreamId stream_id, | |
| uint16_t error_code, | |
| QuicStreamOffset final_offset) { | |
| // Initialize a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(packet_buffer_size, packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicRstStreamFrame transmit_frame(static_cast<QuicControlFrameId>(1), | |
| stream_id, error_code, final_offset); | |
| // Write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendIetfResetStreamFrame( | |
| &framer_, transmit_frame, &writer)); | |
| // Check that the size of the serialzed frame is in the allowed range. | |
| EXPECT_LT(3u, writer.length()); | |
| EXPECT_GT(19u, writer.length()); | |
| // Now set up a reader to read in the thing in. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| // A QuicRstStreamFrame to hold the results | |
| QuicRstStreamFrame receive_frame; | |
| EXPECT_TRUE(QuicFramerPeer::ProcessIetfResetStreamFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Now check that the received values match the input. | |
| EXPECT_EQ(receive_frame.stream_id, transmit_frame.stream_id); | |
| EXPECT_EQ(receive_frame.ietf_error_code, transmit_frame.ietf_error_code); | |
| EXPECT_EQ(receive_frame.byte_offset, transmit_frame.byte_offset); | |
| } | |
| void TryMaxStreamsFrame(QuicStreamCount stream_count, | |
| bool unidirectional, | |
| bool stream_id_server_initiated) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| Perspective old_perspective = framer_.perspective(); | |
| // Set up the writer and transmit QuicMaxStreamsFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| // 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); | |
| QuicMaxStreamsFrame transmit_frame(0, stream_count, unidirectional); | |
| // 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); | |
| QuicMaxStreamsFrame 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_count, receive_frame.stream_count); | |
| EXPECT_EQ(transmit_frame.stream_count, receive_frame.stream_count); | |
| QuicFramerPeer::SetPerspective(&framer_, old_perspective); | |
| } | |
| void TryStreamsBlockedFrame(QuicStreamCount stream_count, | |
| bool unidirectional, | |
| bool stream_id_server_initiated) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| Perspective old_perspective = framer_.perspective(); | |
| // Set up the writer and transmit QuicStreamsBlockedFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| // Set the perspective of the sender. If the stream id is supposed to | |
| // be server-initiated, then the sender of the STREAMS_BLOCKED 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); | |
| QuicStreamsBlockedFrame transmit_frame(0, stream_count, unidirectional); | |
| // 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); | |
| QuicStreamsBlockedFrame 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_count, receive_frame.stream_count); | |
| EXPECT_EQ(transmit_frame.stream_count, receive_frame.stream_count); | |
| QuicFramerPeer::SetPerspective(&framer_, old_perspective); | |
| } | |
| QuicTime start_; | |
| QuicFramer framer_; | |
| test::TestQuicVisitor visitor_; | |
| }; | |
| struct stream_frame_variant { | |
| QuicIetfStreamId stream_id; | |
| QuicIetfStreamOffset offset; | |
| bool fin_bit; | |
| bool last_frame_bit; | |
| uint8_t frame_type; | |
| } stream_frame_to_test[] = { | |
| #define IETF_STREAM0 (((uint8_t)IETF_STREAM)) | |
| #define IETF_STREAM1 (((uint8_t)IETF_STREAM) | IETF_STREAM_FRAME_FIN_BIT) | |
| #define IETF_STREAM2 (((uint8_t)IETF_STREAM) | IETF_STREAM_FRAME_LEN_BIT) | |
| #define IETF_STREAM3 \ | |
| (((uint8_t)IETF_STREAM) | IETF_STREAM_FRAME_LEN_BIT | \ | |
| IETF_STREAM_FRAME_FIN_BIT) | |
| #define IETF_STREAM4 (((uint8_t)IETF_STREAM) | IETF_STREAM_FRAME_OFF_BIT) | |
| #define IETF_STREAM5 \ | |
| (((uint8_t)IETF_STREAM) | IETF_STREAM_FRAME_OFF_BIT | \ | |
| IETF_STREAM_FRAME_FIN_BIT) | |
| #define IETF_STREAM6 \ | |
| (((uint8_t)IETF_STREAM) | IETF_STREAM_FRAME_OFF_BIT | \ | |
| IETF_STREAM_FRAME_LEN_BIT) | |
| #define IETF_STREAM7 \ | |
| (((uint8_t)IETF_STREAM) | IETF_STREAM_FRAME_OFF_BIT | \ | |
| IETF_STREAM_FRAME_LEN_BIT | IETF_STREAM_FRAME_FIN_BIT) | |
| {kStreamId8, kOffset8, true, false, IETF_STREAM7}, | |
| {kStreamId8, kOffset8, false, false, IETF_STREAM6}, | |
| {kStreamId8, kOffset4, true, false, IETF_STREAM7}, | |
| {kStreamId8, kOffset4, false, false, IETF_STREAM6}, | |
| {kStreamId8, kOffset2, true, false, IETF_STREAM7}, | |
| {kStreamId8, kOffset2, false, false, IETF_STREAM6}, | |
| {kStreamId8, kOffset1, true, false, IETF_STREAM7}, | |
| {kStreamId8, kOffset1, false, false, IETF_STREAM6}, | |
| {kStreamId8, kOffset0, true, false, IETF_STREAM3}, | |
| {kStreamId8, kOffset0, false, false, IETF_STREAM2}, | |
| {kStreamId4, kOffset8, true, false, IETF_STREAM7}, | |
| {kStreamId4, kOffset8, false, false, IETF_STREAM6}, | |
| {kStreamId4, kOffset4, true, false, IETF_STREAM7}, | |
| {kStreamId4, kOffset4, false, false, IETF_STREAM6}, | |
| {kStreamId4, kOffset2, true, false, IETF_STREAM7}, | |
| {kStreamId4, kOffset2, false, false, IETF_STREAM6}, | |
| {kStreamId4, kOffset1, true, false, IETF_STREAM7}, | |
| {kStreamId4, kOffset1, false, false, IETF_STREAM6}, | |
| {kStreamId4, kOffset0, true, false, IETF_STREAM3}, | |
| {kStreamId4, kOffset0, false, false, IETF_STREAM2}, | |
| {kStreamId2, kOffset8, true, false, IETF_STREAM7}, | |
| {kStreamId2, kOffset8, false, false, IETF_STREAM6}, | |
| {kStreamId2, kOffset4, true, false, IETF_STREAM7}, | |
| {kStreamId2, kOffset4, false, false, IETF_STREAM6}, | |
| {kStreamId2, kOffset2, true, false, IETF_STREAM7}, | |
| {kStreamId2, kOffset2, false, false, IETF_STREAM6}, | |
| {kStreamId2, kOffset1, true, false, IETF_STREAM7}, | |
| {kStreamId2, kOffset1, false, false, IETF_STREAM6}, | |
| {kStreamId2, kOffset0, true, false, IETF_STREAM3}, | |
| {kStreamId2, kOffset0, false, false, IETF_STREAM2}, | |
| {kStreamId1, kOffset8, true, false, IETF_STREAM7}, | |
| {kStreamId1, kOffset8, false, false, IETF_STREAM6}, | |
| {kStreamId1, kOffset4, true, false, IETF_STREAM7}, | |
| {kStreamId1, kOffset4, false, false, IETF_STREAM6}, | |
| {kStreamId1, kOffset2, true, false, IETF_STREAM7}, | |
| {kStreamId1, kOffset2, false, false, IETF_STREAM6}, | |
| {kStreamId1, kOffset1, true, false, IETF_STREAM7}, | |
| {kStreamId1, kOffset1, false, false, IETF_STREAM6}, | |
| {kStreamId1, kOffset0, true, false, IETF_STREAM3}, | |
| {kStreamId1, kOffset0, false, false, IETF_STREAM2}, | |
| {kStreamId0, kOffset8, true, false, IETF_STREAM7}, | |
| {kStreamId0, kOffset8, false, false, IETF_STREAM6}, | |
| {kStreamId0, kOffset4, true, false, IETF_STREAM7}, | |
| {kStreamId0, kOffset4, false, false, IETF_STREAM6}, | |
| {kStreamId0, kOffset2, true, false, IETF_STREAM7}, | |
| {kStreamId0, kOffset2, false, false, IETF_STREAM6}, | |
| {kStreamId0, kOffset1, true, false, IETF_STREAM7}, | |
| {kStreamId0, kOffset1, false, false, IETF_STREAM6}, | |
| {kStreamId0, kOffset0, true, false, IETF_STREAM3}, | |
| {kStreamId0, kOffset0, false, false, IETF_STREAM2}, | |
| {kStreamId8, kOffset8, true, true, IETF_STREAM5}, | |
| {kStreamId8, kOffset8, false, true, IETF_STREAM4}, | |
| {kStreamId8, kOffset4, true, true, IETF_STREAM5}, | |
| {kStreamId8, kOffset4, false, true, IETF_STREAM4}, | |
| {kStreamId8, kOffset2, true, true, IETF_STREAM5}, | |
| {kStreamId8, kOffset2, false, true, IETF_STREAM4}, | |
| {kStreamId8, kOffset1, true, true, IETF_STREAM5}, | |
| {kStreamId8, kOffset1, false, true, IETF_STREAM4}, | |
| {kStreamId8, kOffset0, true, true, IETF_STREAM1}, | |
| {kStreamId8, kOffset0, false, true, IETF_STREAM0}, | |
| {kStreamId4, kOffset8, true, true, IETF_STREAM5}, | |
| {kStreamId4, kOffset8, false, true, IETF_STREAM4}, | |
| {kStreamId4, kOffset4, true, true, IETF_STREAM5}, | |
| {kStreamId4, kOffset4, false, true, IETF_STREAM4}, | |
| {kStreamId4, kOffset2, true, true, IETF_STREAM5}, | |
| {kStreamId4, kOffset2, false, true, IETF_STREAM4}, | |
| {kStreamId4, kOffset1, true, true, IETF_STREAM5}, | |
| {kStreamId4, kOffset1, false, true, IETF_STREAM4}, | |
| {kStreamId4, kOffset0, true, true, IETF_STREAM1}, | |
| {kStreamId4, kOffset0, false, true, IETF_STREAM0}, | |
| {kStreamId2, kOffset8, true, true, IETF_STREAM5}, | |
| {kStreamId2, kOffset8, false, true, IETF_STREAM4}, | |
| {kStreamId2, kOffset4, true, true, IETF_STREAM5}, | |
| {kStreamId2, kOffset4, false, true, IETF_STREAM4}, | |
| {kStreamId2, kOffset2, true, true, IETF_STREAM5}, | |
| {kStreamId2, kOffset2, false, true, IETF_STREAM4}, | |
| {kStreamId2, kOffset1, true, true, IETF_STREAM5}, | |
| {kStreamId2, kOffset1, false, true, IETF_STREAM4}, | |
| {kStreamId2, kOffset0, true, true, IETF_STREAM1}, | |
| {kStreamId2, kOffset0, false, true, IETF_STREAM0}, | |
| {kStreamId1, kOffset8, true, true, IETF_STREAM5}, | |
| {kStreamId1, kOffset8, false, true, IETF_STREAM4}, | |
| {kStreamId1, kOffset4, true, true, IETF_STREAM5}, | |
| {kStreamId1, kOffset4, false, true, IETF_STREAM4}, | |
| {kStreamId1, kOffset2, true, true, IETF_STREAM5}, | |
| {kStreamId1, kOffset2, false, true, IETF_STREAM4}, | |
| {kStreamId1, kOffset1, true, true, IETF_STREAM5}, | |
| {kStreamId1, kOffset1, false, true, IETF_STREAM4}, | |
| {kStreamId1, kOffset0, true, true, IETF_STREAM1}, | |
| {kStreamId1, kOffset0, false, true, IETF_STREAM0}, | |
| {kStreamId0, kOffset8, true, true, IETF_STREAM5}, | |
| {kStreamId0, kOffset8, false, true, IETF_STREAM4}, | |
| {kStreamId0, kOffset4, true, true, IETF_STREAM5}, | |
| {kStreamId0, kOffset4, false, true, IETF_STREAM4}, | |
| {kStreamId0, kOffset2, true, true, IETF_STREAM5}, | |
| {kStreamId0, kOffset2, false, true, IETF_STREAM4}, | |
| {kStreamId0, kOffset1, true, true, IETF_STREAM5}, | |
| {kStreamId0, kOffset1, false, true, IETF_STREAM4}, | |
| {kStreamId0, kOffset0, true, true, IETF_STREAM1}, | |
| {kStreamId0, kOffset0, false, true, IETF_STREAM0}, | |
| }; | |
| TEST_F(QuicIetfFramerTest, StreamFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| const char* transmit_packet_data = | |
| "this is a test of some packet data, " | |
| "can do a simple strcmp to see if the " | |
| "input and output are the same!"; | |
| size_t transmit_packet_data_len = strlen(transmit_packet_data) + 1; | |
| for (size_t i = 0; i < QUIC_ARRAYSIZE(stream_frame_to_test); ++i) { | |
| SCOPED_TRACE(i); | |
| struct stream_frame_variant* variant = &stream_frame_to_test[i]; | |
| TryStreamFrame(packet_buffer, sizeof(packet_buffer), transmit_packet_data, | |
| transmit_packet_data_len, variant->stream_id, | |
| variant->offset, variant->fin_bit, variant->last_frame_bit, | |
| static_cast<QuicIetfFrameType>(variant->frame_type)); | |
| } | |
| } | |
| // As the previous test, but with no data. | |
| TEST_F(QuicIetfFramerTest, ZeroLengthStreamFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| for (size_t i = 0; i < QUIC_ARRAYSIZE(stream_frame_to_test); ++i) { | |
| SCOPED_TRACE(i); | |
| struct stream_frame_variant* variant = &stream_frame_to_test[i]; | |
| TryStreamFrame(packet_buffer, sizeof(packet_buffer), | |
| /* xmit_packet_data = */ NULL, | |
| /* xmit_packet_data_size = */ 0, variant->stream_id, | |
| variant->offset, variant->fin_bit, variant->last_frame_bit, | |
| static_cast<QuicIetfFrameType>(variant->frame_type)); | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, CryptoFrame) { | |
| SimpleDataProducer data_producer; | |
| framer_.set_data_producer(&data_producer); | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| QuicStringPiece frame_data("This is a CRYPTO frame."); | |
| QuicStreamOffset offsets[] = {kOffset8, kOffset4, kOffset2, kOffset1, | |
| kOffset0}; | |
| for (QuicStreamOffset offset : offsets) { | |
| QuicCryptoFrame frame(ENCRYPTION_INITIAL, offset, frame_data.length()); | |
| data_producer.SaveCryptoData(ENCRYPTION_INITIAL, offset, frame_data); | |
| QuicDataWriter writer(QUIC_ARRAYSIZE(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| // Write the frame. | |
| EXPECT_TRUE(QuicFramerPeer::AppendCryptoFrame(&framer_, frame, &writer)); | |
| EXPECT_NE(0u, writer.length()); | |
| // Read it back. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicCryptoFrame read_frame; | |
| EXPECT_TRUE( | |
| QuicFramerPeer::ProcessCryptoFrame(&framer_, &reader, &read_frame)); | |
| // Check that the frames match: | |
| QuicStringPiece read_data(read_frame.data_buffer, read_frame.data_length); | |
| EXPECT_EQ(read_frame.data_length, frame.data_length); | |
| EXPECT_EQ(read_frame.offset, frame.offset); | |
| EXPECT_EQ(read_data, frame_data); | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, ConnectionCloseEmptyString) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| // initialize a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| // empty string, | |
| std::string test_string = "Ich Bin Ein Jelly Donut?"; | |
| QuicConnectionCloseFrame sent_frame; | |
| sent_frame.quic_error_code = static_cast<QuicErrorCode>(0); | |
| sent_frame.error_details = test_string; | |
| sent_frame.transport_close_frame_type = 123; | |
| sent_frame.close_type = IETF_QUIC_TRANSPORT_CONNECTION_CLOSE; | |
| // write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendIetfConnectionCloseFrame( | |
| &framer_, sent_frame, &writer)); | |
| // better have something in the packet buffer. | |
| EXPECT_NE(0u, writer.length()); | |
| // now set up a reader to read in the frame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| // a QuicConnectionCloseFrame to hold the results. | |
| QuicConnectionCloseFrame sink_frame; | |
| EXPECT_TRUE(QuicFramerPeer::ProcessIetfConnectionCloseFrame( | |
| &framer_, &reader, IETF_QUIC_TRANSPORT_CONNECTION_CLOSE, &sink_frame)); | |
| // Now check that received == sent | |
| EXPECT_EQ(sent_frame.quic_error_code, sink_frame.quic_error_code); | |
| EXPECT_EQ(sink_frame.quic_error_code, static_cast<QuicErrorCode>(0)); | |
| EXPECT_EQ(sink_frame.error_details, test_string); | |
| EXPECT_EQ(sink_frame.close_type, sent_frame.close_type); | |
| EXPECT_EQ(sent_frame.close_type, IETF_QUIC_TRANSPORT_CONNECTION_CLOSE); | |
| } | |
| TEST_F(QuicIetfFramerTest, ApplicationCloseEmptyString) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| // initialize a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| // empty string, | |
| std::string test_string = "Ich Bin Ein Jelly Donut?"; | |
| QuicConnectionCloseFrame sent_frame; | |
| sent_frame.quic_error_code = static_cast<QuicErrorCode>(0); | |
| sent_frame.error_details = test_string; | |
| sent_frame.close_type = IETF_QUIC_APPLICATION_CONNECTION_CLOSE; | |
| // write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendIetfConnectionCloseFrame( | |
| &framer_, sent_frame, &writer)); | |
| // better have something in the packet buffer. | |
| EXPECT_NE(0u, writer.length()); | |
| // now set up a reader to read in the frame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| // a QuicConnectionCloseFrame to hold the results. | |
| QuicConnectionCloseFrame sink_frame; | |
| EXPECT_TRUE(QuicFramerPeer::ProcessIetfConnectionCloseFrame( | |
| &framer_, &reader, IETF_QUIC_APPLICATION_CONNECTION_CLOSE, &sink_frame)); | |
| // Now check that received == sent | |
| EXPECT_EQ(sink_frame.quic_error_code, static_cast<QuicErrorCode>(0)); | |
| EXPECT_EQ(sent_frame.quic_error_code, sink_frame.quic_error_code); | |
| EXPECT_EQ(sink_frame.error_details, test_string); | |
| EXPECT_EQ(sent_frame.close_type, IETF_QUIC_APPLICATION_CONNECTION_CLOSE); | |
| EXPECT_EQ(sent_frame.close_type, sink_frame.close_type); | |
| } | |
| // Testing for the IETF ACK framer. | |
| // clang-format off | |
| struct ack_frame ack_frame_variants[] = { | |
| {90000, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1000), QuicPacketNumber(2001)}}, | |
| IETF_ACK}, | |
| {0, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1000), QuicPacketNumber(2001)}}, | |
| IETF_ACK}, | |
| {1, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(2)}, | |
| {QuicPacketNumber(5), QuicPacketNumber(6)}}, | |
| IETF_ACK}, | |
| {63, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(2)}, | |
| {QuicPacketNumber(5), QuicPacketNumber(6)}}, | |
| IETF_ACK}, | |
| {64, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(2)}, | |
| {QuicPacketNumber(3), QuicPacketNumber(4)}, | |
| {QuicPacketNumber(5), QuicPacketNumber(6)}, | |
| {QuicPacketNumber(7), QuicPacketNumber(8)}, | |
| {QuicPacketNumber(9), QuicPacketNumber(10)}, | |
| {QuicPacketNumber(11), QuicPacketNumber(12)}}, | |
| IETF_ACK}, | |
| {10000, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(2)}, | |
| {QuicPacketNumber(3), QuicPacketNumber(4)}, | |
| {QuicPacketNumber(5), QuicPacketNumber(6)}, | |
| {QuicPacketNumber(7), QuicPacketNumber(8)}, | |
| {QuicPacketNumber(9), QuicPacketNumber(10)}, | |
| {QuicPacketNumber(11), QuicPacketNumber(12)}}, | |
| IETF_ACK}, | |
| {100000000, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(2)}, | |
| {QuicPacketNumber(3), QuicPacketNumber(4)}, | |
| {QuicPacketNumber(5), QuicPacketNumber(6)}, | |
| {QuicPacketNumber(7), QuicPacketNumber(8)}, | |
| {QuicPacketNumber(9), QuicPacketNumber(10)}, | |
| {QuicPacketNumber(11), QuicPacketNumber(12)}}, | |
| IETF_ACK}, | |
| {0, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}}, | |
| IETF_ACK}, | |
| {9223372036854775807, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(11)}, | |
| {QuicPacketNumber(74), QuicPacketNumber(138)}}, | |
| IETF_ACK}, | |
| // This ack is for packets 60 & 125. There are 64 packets in the gap. | |
| // The encoded value is gap_size - 1, or 63. Crosses a VarInt62 encoding | |
| // boundary... | |
| {1, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(60), QuicPacketNumber(61)}, | |
| {QuicPacketNumber(125), QuicPacketNumber(126)}}, | |
| IETF_ACK}, | |
| {2, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(130)}}, | |
| IETF_ACK}, | |
| {3, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(195)}}, | |
| IETF_ACK}, | |
| {4, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(194)}}, | |
| IETF_ACK}, | |
| {5, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(193)}}, | |
| IETF_ACK}, | |
| {6, | |
| false, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(192)}}, | |
| IETF_ACK}, | |
| // declare some ack_ecn frames to try. | |
| {6, | |
| false, | |
| 100, | |
| 200, | |
| 300, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(192)}}, | |
| IETF_ACK}, | |
| {6, | |
| true, | |
| 100, | |
| 200, | |
| 300, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(192)}}, | |
| IETF_ACK_ECN}, | |
| {6, | |
| true, | |
| 100, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(192)}}, | |
| IETF_ACK_ECN}, | |
| {6, | |
| true, | |
| 0, | |
| 200, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(192)}}, | |
| IETF_ACK_ECN}, | |
| {6, | |
| true, | |
| 0, | |
| 0, | |
| 300, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(192)}}, | |
| IETF_ACK_ECN}, | |
| {6, | |
| true, | |
| 0, | |
| 0, | |
| 0, | |
| {{QuicPacketNumber(1), QuicPacketNumber(65)}, | |
| {QuicPacketNumber(129), QuicPacketNumber(192)}}, | |
| IETF_ACK}, | |
| }; | |
| // clang-format on | |
| TEST_F(QuicIetfFramerTest, AckFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| for (auto ack_frame_variant : ack_frame_variants) { | |
| EXPECT_TRUE( | |
| TryAckFrame(packet_buffer, sizeof(packet_buffer), &ack_frame_variant)); | |
| } | |
| } | |
| // Test the case of having a QuicAckFrame with no ranges in it. By | |
| // examination of the Google Quic Ack code and tests, this case should | |
| // be handled as an ack with no "ranges after the first"; the | |
| // AckBlockCount should be 0 and the FirstAckBlock should be | |
| // |LargestAcked| - 1 (number of packets preceding the LargestAcked. | |
| TEST_F(QuicIetfFramerTest, AckFrameNoRanges) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| // Make a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicAckFrame transmit_frame; | |
| transmit_frame.largest_acked = QuicPacketNumber(1); | |
| transmit_frame.ack_delay_time = QuicTime::Delta::FromMicroseconds(0); | |
| size_t expected_size = | |
| QuicFramerPeer::GetIetfAckFrameSize(&framer_, transmit_frame); | |
| // Write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendIetfAckFrameAndTypeByte( | |
| &framer_, transmit_frame, &writer)); | |
| uint8_t packet[] = { | |
| 0x02, // type, IETF_ACK | |
| 0x01, // largest_acked, | |
| 0x00, // delay | |
| 0x00, // count of additional ack blocks | |
| 0x00, // size of first ack block (packets preceding largest_acked) | |
| }; | |
| EXPECT_EQ(expected_size, sizeof(packet)); | |
| EXPECT_EQ(sizeof(packet), writer.length()); | |
| EXPECT_EQ(0, memcmp(packet, packet_buffer, writer.length())); | |
| // Now set up a reader to read in the frame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| // an AckFrame to hold the results | |
| QuicAckFrame receive_frame; | |
| // read in the frame type | |
| uint8_t received_frame_type; | |
| EXPECT_TRUE(reader.ReadUInt8(&received_frame_type)); | |
| EXPECT_EQ(received_frame_type, IETF_ACK); | |
| EXPECT_TRUE(QuicFramerPeer::ProcessIetfAckFrame(&framer_, &reader, IETF_ACK, | |
| &receive_frame)); | |
| // Now check that the received frame matches the sent frame. | |
| EXPECT_EQ(transmit_frame.largest_acked, receive_frame.largest_acked); | |
| } | |
| TEST_F(QuicIetfFramerTest, PathChallengeFrame) { | |
| // Double-braces needed on some platforms due to | |
| // https://bugs.llvm.org/show_bug.cgi?id=21629 | |
| QuicPathFrameBuffer buffer0 = {{0, 0, 0, 0, 0, 0, 0, 0}}; | |
| QuicPathFrameBuffer buffer1 = { | |
| {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| EXPECT_TRUE( | |
| TryPathChallengeFrame(packet_buffer, sizeof(packet_buffer), buffer0)); | |
| EXPECT_TRUE( | |
| TryPathChallengeFrame(packet_buffer, sizeof(packet_buffer), buffer1)); | |
| } | |
| TEST_F(QuicIetfFramerTest, PathResponseFrame) { | |
| // Double-braces needed on some platforms due to | |
| // https://bugs.llvm.org/show_bug.cgi?id=21629 | |
| QuicPathFrameBuffer buffer0 = {{0, 0, 0, 0, 0, 0, 0, 0}}; | |
| QuicPathFrameBuffer buffer1 = { | |
| {0x80, 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe5, 0xf7}}; | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| EXPECT_TRUE( | |
| TryPathResponseFrame(packet_buffer, sizeof(packet_buffer), buffer0)); | |
| EXPECT_TRUE( | |
| TryPathResponseFrame(packet_buffer, sizeof(packet_buffer), buffer1)); | |
| } | |
| TEST_F(QuicIetfFramerTest, ResetStreamFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| struct resets { | |
| QuicStreamId stream_id; | |
| uint16_t error_code; | |
| QuicStreamOffset final_offset; | |
| } reset_frames[] = { | |
| {0, 55, 0}, | |
| {0x10, 73, 0x300}, | |
| }; | |
| for (auto reset : reset_frames) { | |
| TryResetFrame(packet_buffer, sizeof(packet_buffer), reset.stream_id, | |
| reset.error_code, reset.final_offset); | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, StopSendingFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| // Make a writer so that the serialized packet is placed in | |
| // packet_buffer. | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicStopSendingFrame transmit_frame; | |
| transmit_frame.stream_id = 12345; | |
| transmit_frame.application_error_code = 543; | |
| // Write the frame to the packet buffer. | |
| EXPECT_TRUE(QuicFramerPeer::AppendStopSendingFrame(&framer_, transmit_frame, | |
| &writer)); | |
| // Check that the number of bytes in the buffer is in the | |
| // allowed range. | |
| EXPECT_LE(3u, writer.length()); | |
| EXPECT_GE(10u, writer.length()); | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| // A frame to hold the results | |
| QuicStopSendingFrame receive_frame; | |
| EXPECT_TRUE(QuicFramerPeer::ProcessStopSendingFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Verify that the transmitted and received values are the same. | |
| EXPECT_EQ(receive_frame.stream_id, 12345u); | |
| EXPECT_EQ(receive_frame.application_error_code, 543u); | |
| EXPECT_EQ(receive_frame.stream_id, transmit_frame.stream_id); | |
| EXPECT_EQ(receive_frame.application_error_code, | |
| transmit_frame.application_error_code); | |
| } | |
| TEST_F(QuicIetfFramerTest, MaxDataFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| QuicStreamOffset window_sizes[] = {0, 1, 2, 5, 10, | |
| 20, 50, 100, 200, 500, | |
| 1000000, kOffset8, kOffset4, kOffset2}; | |
| for (QuicStreamOffset window_size : window_sizes) { | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| // Set up the writer and transmit QuicWindowUpdateFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicWindowUpdateFrame transmit_frame(0, 99, window_size); | |
| // Add the frame. | |
| EXPECT_TRUE( | |
| QuicFramerPeer::AppendMaxDataFrame(&framer_, transmit_frame, &writer)); | |
| // Check that the number of bytes in the buffer is in the expected range. | |
| EXPECT_LE(1u, writer.length()); | |
| EXPECT_GE(8u, writer.length()); | |
| // Set up reader and an empty QuicWindowUpdateFrame | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicWindowUpdateFrame receive_frame; | |
| // Deframe it | |
| EXPECT_TRUE( | |
| QuicFramerPeer::ProcessMaxDataFrame(&framer_, &reader, &receive_frame)); | |
| // 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(QuicUtils::GetInvalidStreamId(framer_.transport_version()), | |
| receive_frame.stream_id); | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, MaxStreamDataFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| QuicStreamOffset window_sizes[] = {0, 1, 2, 5, 10, | |
| 20, 50, 100, 200, 500, | |
| 1000000, kOffset8, kOffset4, kOffset2}; | |
| QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, | |
| kStreamId0}; | |
| for (QuicIetfStreamId stream_id : stream_ids) { | |
| for (QuicStreamOffset window_size : window_sizes) { | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| // Set up the writer and transmit QuicWindowUpdateFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicWindowUpdateFrame transmit_frame(0, stream_id, window_size); | |
| // Add the frame. | |
| EXPECT_TRUE(QuicFramerPeer::AppendMaxStreamDataFrame( | |
| &framer_, transmit_frame, &writer)); | |
| // Check that number of bytes in the buffer is in the expected range. | |
| EXPECT_LE(2u, writer.length()); | |
| EXPECT_GE(16u, writer.length()); | |
| // Set up reader and empty receive QuicPaddingFrame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicWindowUpdateFrame receive_frame; | |
| // Deframe it | |
| EXPECT_TRUE(QuicFramerPeer::ProcessMaxStreamDataFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Now check that received data and sent data are equal. | |
| EXPECT_EQ(transmit_frame.byte_offset, window_size); | |
| EXPECT_EQ(transmit_frame.byte_offset, receive_frame.byte_offset); | |
| EXPECT_EQ(stream_id, receive_frame.stream_id); | |
| EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); | |
| } | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, MaxStreamsFrame) { | |
| QuicStreamCount stream_counts[] = {0x3fffffff, 0x3fff, 0x3f, 0x1}; | |
| for (QuicStreamCount stream_count : stream_counts) { | |
| // Cover all four combinations of uni/bi-directional and | |
| // server-/client- initiation. | |
| TryMaxStreamsFrame(stream_count, /*unidirectional=*/true, | |
| /*stream_id_server_initiated=*/true); | |
| TryMaxStreamsFrame(stream_count, /*unidirectional=*/true, | |
| /*stream_id_server_initiated=*/false); | |
| TryMaxStreamsFrame(stream_count, /*unidirectional=*/false, | |
| /*stream_id_server_initiated=*/true); | |
| TryMaxStreamsFrame(stream_count, /*unidirectional=*/false, | |
| /*stream_id_server_initiated=*/false); | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, BlockedFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| QuicStreamOffset offsets[] = {kOffset8, kOffset4, kOffset2, kOffset1, | |
| kOffset0}; | |
| for (QuicStreamOffset offset : offsets) { | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| // Set up the writer and transmit QuicBlockedFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicBlockedFrame transmit_frame( | |
| 0, QuicUtils::GetInvalidStreamId(framer_.transport_version()), offset); | |
| // Add the frame. | |
| EXPECT_TRUE(QuicFramerPeer::AppendIetfBlockedFrame(&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 QuicFrame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicBlockedFrame receive_frame; | |
| // Deframe it | |
| EXPECT_TRUE(QuicFramerPeer::ProcessIetfBlockedFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Check that received and sent data are equivalent | |
| 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); | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, StreamBlockedFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| QuicStreamOffset offsets[] = {0, 1, 2, 5, 10, | |
| 20, 50, 100, 200, 500, | |
| 1000000, kOffset8, kOffset4, kOffset2}; | |
| QuicIetfStreamId stream_ids[] = {kStreamId4, kStreamId2, kStreamId1, | |
| kStreamId0}; | |
| for (QuicIetfStreamId stream_id : stream_ids) { | |
| for (QuicStreamOffset offset : offsets) { | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| // Set up the writer and transmit QuicWindowUpdateFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| QuicBlockedFrame transmit_frame(0, stream_id, offset); | |
| // Add the frame. | |
| EXPECT_TRUE(QuicFramerPeer::AppendStreamBlockedFrame( | |
| &framer_, transmit_frame, &writer)); | |
| // Check that number of bytes in the buffer is in the expected range. | |
| EXPECT_LE(2u, writer.length()); | |
| EXPECT_GE(16u, writer.length()); | |
| // Set up reader and empty receive QuicPaddingFrame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicBlockedFrame receive_frame; | |
| // Deframe it | |
| EXPECT_TRUE(QuicFramerPeer::ProcessStreamBlockedFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Now check that received == sent | |
| EXPECT_EQ(transmit_frame.offset, offset); | |
| EXPECT_EQ(transmit_frame.offset, receive_frame.offset); | |
| EXPECT_EQ(stream_id, receive_frame.stream_id); | |
| EXPECT_EQ(transmit_frame.stream_id, receive_frame.stream_id); | |
| } | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, StreamsBlockedFrame) { | |
| QuicStreamCount stream_counts[] = {0x3fffffff, 0x3fff, 0x3f, 0x1}; | |
| for (QuicStreamCount stream_count : stream_counts) { | |
| TryStreamsBlockedFrame(stream_count, | |
| /*unidirectional=*/false, | |
| /*stream_id_server_initiated=*/false); | |
| TryStreamsBlockedFrame(stream_count, | |
| /*unidirectional=*/false, | |
| /*stream_id_server_initiated=*/true); | |
| TryStreamsBlockedFrame(stream_count, | |
| /*unidirectional=*/true, | |
| /*stream_id_server_initiated=*/false); | |
| TryStreamsBlockedFrame(stream_count, | |
| /*unidirectional=*/true, | |
| /*stream_id_server_initiated=*/true); | |
| } | |
| } | |
| TEST_F(QuicIetfFramerTest, NewConnectionIdFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| QuicNewConnectionIdFrame transmit_frame; | |
| transmit_frame.connection_id = TestConnectionId(UINT64_C(0x0edcba9876543201)); | |
| transmit_frame.sequence_number = 0x01020304; | |
| // The token is defined as a uint128 -- a 16-byte integer. | |
| // The value is set in this manner because we want each | |
| // byte to have a specific value so that the binary | |
| // packet check (below) is good. If we used integer | |
| // operations (eg. "token = 0x12345...") then the bytes | |
| // would be set in host order. | |
| unsigned char token_bytes[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, | |
| 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, | |
| 0x0c, 0x0d, 0x0e, 0x0f}; | |
| memcpy(&transmit_frame.stateless_reset_token, token_bytes, | |
| sizeof(transmit_frame.stateless_reset_token)); | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| // Set up the writer and transmit a QuicNewConnectionIdFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| // Add the frame. | |
| EXPECT_TRUE(QuicFramerPeer::AppendNewConnectionIdFrame( | |
| &framer_, transmit_frame, &writer)); | |
| // Check that buffer length is correct | |
| EXPECT_EQ(29u, writer.length()); | |
| // clang-format off | |
| uint8_t packet[] = { | |
| // sequence number, 0x80 for varint62 encoding | |
| 0x80 + 0x01, 0x02, 0x03, 0x04, | |
| // new connection id length, is not varint62 encoded. | |
| 0x08, | |
| // new connection id, is not varint62 encoded. | |
| 0x0E, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x01, | |
| // the reset token: | |
| 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | |
| 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f | |
| }; | |
| // clang-format on | |
| EXPECT_EQ(0, memcmp(packet_buffer, packet, sizeof(packet))); | |
| // Set up reader and empty receive QuicPaddingFrame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicNewConnectionIdFrame receive_frame; | |
| // Deframe it | |
| EXPECT_TRUE(QuicFramerPeer::ProcessNewConnectionIdFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Now check that received == sent | |
| EXPECT_EQ(transmit_frame.connection_id, receive_frame.connection_id); | |
| EXPECT_EQ(transmit_frame.sequence_number, receive_frame.sequence_number); | |
| EXPECT_EQ(transmit_frame.stateless_reset_token, | |
| receive_frame.stateless_reset_token); | |
| } | |
| TEST_F(QuicIetfFramerTest, RetireConnectionIdFrame) { | |
| char packet_buffer[kNormalPacketBufferSize]; | |
| QuicRetireConnectionIdFrame transmit_frame; | |
| transmit_frame.sequence_number = 0x01020304; | |
| memset(packet_buffer, 0, sizeof(packet_buffer)); | |
| // Set up the writer and transmit QuicRetireConnectionIdFrame | |
| QuicDataWriter writer(sizeof(packet_buffer), packet_buffer, | |
| NETWORK_BYTE_ORDER); | |
| // Add the frame. | |
| EXPECT_TRUE(QuicFramerPeer::AppendRetireConnectionIdFrame( | |
| &framer_, transmit_frame, &writer)); | |
| // Check that buffer length is correct | |
| EXPECT_EQ(4u, writer.length()); | |
| // clang-format off | |
| uint8_t packet[] = { | |
| // sequence number, 0x80 for varint62 encoding | |
| 0x80 + 0x01, 0x02, 0x03, 0x04, | |
| }; | |
| // clang-format on | |
| EXPECT_EQ(0, memcmp(packet_buffer, packet, sizeof(packet))); | |
| // Set up reader and empty receive QuicPaddingFrame. | |
| QuicDataReader reader(packet_buffer, writer.length(), NETWORK_BYTE_ORDER); | |
| QuicRetireConnectionIdFrame receive_frame; | |
| // Deframe it | |
| EXPECT_TRUE(QuicFramerPeer::ProcessRetireConnectionIdFrame(&framer_, &reader, | |
| &receive_frame)); | |
| // Now check that received == sent | |
| EXPECT_EQ(transmit_frame.sequence_number, receive_frame.sequence_number); | |
| } | |
| } // namespace | |
| } // namespace test | |
| } // namespace quic |