Move RFC 9000 variable length integer encoding from QUIC to QUICHE Since BHTTP uses these, and we're starting BHTTP in QUICHE, we need to move the read/write functions for varints to QUICHE. While I was in there, I improved some comments to refer to the published RFC, and removed a few ODR violations. This CL is a no-op, it does not modify any existing functionality. PiperOrigin-RevId: 467990159
diff --git a/quiche/common/quiche_data_reader.cc b/quiche/common/quiche_data_reader.cc index 52b4af4..080431c 100644 --- a/quiche/common/quiche_data_reader.cc +++ b/quiche/common/quiche_data_reader.cc
@@ -143,6 +143,94 @@ return absl::SimpleAtoi(digits, result); } +QuicheVariableLengthIntegerLength QuicheDataReader::PeekVarInt62Length() { + QUICHE_DCHECK_EQ(endianness(), NETWORK_BYTE_ORDER); + const unsigned char* next = + reinterpret_cast<const unsigned char*>(data() + pos()); + if (BytesRemaining() == 0) { + return VARIABLE_LENGTH_INTEGER_LENGTH_0; + } + return static_cast<QuicheVariableLengthIntegerLength>( + 1 << ((*next & 0b11000000) >> 6)); +} + +// Read an RFC 9000 62-bit Variable Length Integer. +// +// Performance notes +// +// Measurements and experiments showed that unrolling the four cases +// like this and dereferencing next_ as we do (*(next_+n) --- and then +// doing a single pos_+=x at the end) gains about 10% over making a +// loop and dereferencing next_ such as *(next_++) +// +// Using a register for pos_ was not helpful. +// +// Branches are ordered to increase the likelihood of the first being +// taken. +// +// Low-level optimization is useful here because this function will be +// called frequently, leading to outsize benefits. +bool QuicheDataReader::ReadVarInt62(uint64_t* result) { + QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); + + size_t remaining = BytesRemaining(); + const unsigned char* next = + reinterpret_cast<const unsigned char*>(data() + pos()); + if (remaining != 0) { + switch (*next & 0xc0) { + case 0xc0: + // Leading 0b11...... is 8 byte encoding + if (remaining >= 8) { + *result = (static_cast<uint64_t>((*(next)) & 0x3f) << 56) + + (static_cast<uint64_t>(*(next + 1)) << 48) + + (static_cast<uint64_t>(*(next + 2)) << 40) + + (static_cast<uint64_t>(*(next + 3)) << 32) + + (static_cast<uint64_t>(*(next + 4)) << 24) + + (static_cast<uint64_t>(*(next + 5)) << 16) + + (static_cast<uint64_t>(*(next + 6)) << 8) + + (static_cast<uint64_t>(*(next + 7)) << 0); + AdvancePos(8); + return true; + } + return false; + + case 0x80: + // Leading 0b10...... is 4 byte encoding + if (remaining >= 4) { + *result = (((*(next)) & 0x3f) << 24) + (((*(next + 1)) << 16)) + + (((*(next + 2)) << 8)) + (((*(next + 3)) << 0)); + AdvancePos(4); + return true; + } + return false; + + case 0x40: + // Leading 0b01...... is 2 byte encoding + if (remaining >= 2) { + *result = (((*(next)) & 0x3f) << 8) + (*(next + 1)); + AdvancePos(2); + return true; + } + return false; + + case 0x00: + // Leading 0b00...... is 1 byte encoding + *result = (*next) & 0x3f; + AdvancePos(1); + return true; + } + } + return false; +} + +bool QuicheDataReader::ReadStringPieceVarInt62(absl::string_view* result) { + uint64_t result_length; + if (!ReadVarInt62(&result_length)) { + return false; + } + return ReadStringPiece(result, result_length); +} + absl::string_view QuicheDataReader::ReadRemainingPayload() { absl::string_view payload = PeekRemainingPayload(); pos_ = len_;
diff --git a/quiche/common/quiche_data_reader.h b/quiche/common/quiche_data_reader.h index bf336f9..ed05b69 100644 --- a/quiche/common/quiche_data_reader.h +++ b/quiche/common/quiche_data_reader.h
@@ -92,6 +92,25 @@ // iterator on success, may forward it even in case of failure. bool ReadDecimal64(size_t num_digits, uint64_t* result); + // 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. + QuicheVariableLengthIntegerLength PeekVarInt62Length(); + + // Read an RFC 9000 62-bit Variable Length Integer and place the result in + // |*result|. Returns false if there is not enough space in the buffer to read + // the number, true otherwise. If false is returned, |*result| is not altered. + bool ReadVarInt62(uint64_t* result); + + // Reads a string prefixed with a RFC 9000 62-bit variable Length integer + // length into the given output parameter. + // + // NOTE: Does not copy but rather references strings in the underlying buffer. + // This should be kept in mind when handling memory management! + // + // Returns false if there is not enough space in the buffer to read + // the number and subsequent string, true otherwise. + bool ReadStringPieceVarInt62(absl::string_view* result); + // Returns the remaining payload as a absl::string_view. // // NOTE: Does not copy but rather references strings in the underlying buffer.
diff --git a/quiche/common/quiche_data_writer.cc b/quiche/common/quiche_data_writer.cc index 5f83e1f..5e79439 100644 --- a/quiche/common/quiche_data_writer.cc +++ b/quiche/common/quiche_data_writer.cc
@@ -9,6 +9,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "quiche/common/platform/api/quiche_bug_tracker.h" #include "quiche/common/quiche_endian.h" namespace quiche { @@ -133,6 +134,158 @@ return WriteBytes(&tag, sizeof(tag)); } +// Converts a uint64_t into a 62-bit RFC 9000 Variable Length Integer. +// +// Performance notes +// +// Measurements and experiments showed that unrolling the four cases +// like this and dereferencing next_ as we do (*(next_+n)) gains about +// 10% over making a loop and dereferencing it as *(next_++) +// +// Using a register for next didn't help. +// +// Branches are ordered to increase the likelihood of the first being +// taken. +// +// Low-level optimization is useful here because this function will be +// called frequently, leading to outsize benefits. +bool QuicheDataWriter::WriteVarInt62(uint64_t value) { + QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); + + size_t remaining_bytes = remaining(); + char* next = buffer() + length(); + + if ((value & kVarInt62ErrorMask) == 0) { + // We know the high 2 bits are 0 so |value| is legal. + // We can do the encoding. + if ((value & kVarInt62Mask8Bytes) != 0) { + // Someplace in the high-4 bytes is a 1-bit. Do an 8-byte + // encoding. + if (remaining_bytes >= 8) { + *(next + 0) = ((value >> 56) & 0x3f) + 0xc0; + *(next + 1) = (value >> 48) & 0xff; + *(next + 2) = (value >> 40) & 0xff; + *(next + 3) = (value >> 32) & 0xff; + *(next + 4) = (value >> 24) & 0xff; + *(next + 5) = (value >> 16) & 0xff; + *(next + 6) = (value >> 8) & 0xff; + *(next + 7) = value & 0xff; + IncreaseLength(8); + return true; + } + return false; + } + // The high-order-4 bytes are all 0, check for a 1, 2, or 4-byte + // encoding + if ((value & kVarInt62Mask4Bytes) != 0) { + // The encoding will not fit into 2 bytes, Do a 4-byte + // encoding. + if (remaining_bytes >= 4) { + *(next + 0) = ((value >> 24) & 0x3f) + 0x80; + *(next + 1) = (value >> 16) & 0xff; + *(next + 2) = (value >> 8) & 0xff; + *(next + 3) = value & 0xff; + IncreaseLength(4); + return true; + } + return false; + } + // The high-order bits are all 0. Check to see if the number + // can be encoded as one or two bytes. One byte encoding has + // only 6 significant bits (bits 0xffffffff ffffffc0 are all 0). + // Two byte encoding has more than 6, but 14 or less significant + // bits (bits 0xffffffff ffffc000 are 0 and 0x00000000 00003fc0 + // are not 0) + if ((value & kVarInt62Mask2Bytes) != 0) { + // Do 2-byte encoding + if (remaining_bytes >= 2) { + *(next + 0) = ((value >> 8) & 0x3f) + 0x40; + *(next + 1) = (value)&0xff; + IncreaseLength(2); + return true; + } + return false; + } + if (remaining_bytes >= 1) { + // Do 1-byte encoding + *next = (value & 0x3f); + IncreaseLength(1); + return true; + } + return false; + } + // Can not encode, high 2 bits not 0 + return false; +} + +bool QuicheDataWriter::WriteStringPieceVarInt62( + const absl::string_view& string_piece) { + if (!WriteVarInt62(string_piece.size())) { + return false; + } + if (!string_piece.empty()) { + if (!WriteBytes(string_piece.data(), string_piece.size())) { + return false; + } + } + return true; +} + +// static +QuicheVariableLengthIntegerLength QuicheDataWriter::GetVarInt62Len( + uint64_t value) { + if ((value & kVarInt62ErrorMask) != 0) { + QUICHE_BUG(invalid_varint) << "Attempted to encode a value, " << value + << ", that is too big for VarInt62"; + return VARIABLE_LENGTH_INTEGER_LENGTH_0; + } + if ((value & kVarInt62Mask8Bytes) != 0) { + return VARIABLE_LENGTH_INTEGER_LENGTH_8; + } + if ((value & kVarInt62Mask4Bytes) != 0) { + return VARIABLE_LENGTH_INTEGER_LENGTH_4; + } + if ((value & kVarInt62Mask2Bytes) != 0) { + return VARIABLE_LENGTH_INTEGER_LENGTH_2; + } + return VARIABLE_LENGTH_INTEGER_LENGTH_1; +} + +bool QuicheDataWriter::WriteVarInt62WithForcedLength( + uint64_t value, QuicheVariableLengthIntegerLength write_length) { + QUICHE_DCHECK_EQ(endianness(), NETWORK_BYTE_ORDER); + + size_t remaining_bytes = remaining(); + if (remaining_bytes < write_length) { + return false; + } + + const QuicheVariableLengthIntegerLength min_length = GetVarInt62Len(value); + if (write_length < min_length) { + QUICHE_BUG(invalid_varint_forced) << "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); + } + + QUICHE_BUG(invalid_write_length) + << "Invalid write_length " << static_cast<int>(write_length); + return false; +} + bool QuicheDataWriter::Seek(size_t length) { if (!BeginWrite(length)) { return false;
diff --git a/quiche/common/quiche_data_writer.h b/quiche/common/quiche_data_writer.h index 5f027a9..8035bb2 100644 --- a/quiche/common/quiche_data_writer.h +++ b/quiche/common/quiche_data_writer.h
@@ -17,6 +17,24 @@ namespace quiche { +// Maximum value that can be properly encoded using RFC 9000 62-bit Variable +// Length Integer encoding. +enum : uint64_t { + kVarInt62MaxValue = UINT64_C(0x3fffffffffffffff), +}; + +// RFC 9000 62-bit Variable Length Integer encoding masks +// If a uint64_t anded with a mask is not 0 then the value is encoded +// using that length (or is too big, in the case of kVarInt62ErrorMask). +// Values must be checked in order (error, 8-, 4-, and then 2- bytes) +// and if none are non-0, the value is encoded in 1 byte. +enum : uint64_t { + kVarInt62ErrorMask = UINT64_C(0xc000000000000000), + kVarInt62Mask8Bytes = UINT64_C(0x3fffffffc0000000), + kVarInt62Mask4Bytes = UINT64_C(0x000000003fffc000), + kVarInt62Mask2Bytes = UINT64_C(0x0000000000003fc0), +}; + // This class provides facilities for packing binary data. // // The QuicheDataWriter supports appending primitive values (int, string, etc) @@ -69,6 +87,28 @@ // in big endian. bool WriteTag(uint32_t tag); + // Write a 62-bit unsigned integer using RFC 9000 Variable Length Integer + // encoding. Returns false if the value is out of range or if there is no room + // in the 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 WriteVarInt62WithForcedLength( + uint64_t value, QuicheVariableLengthIntegerLength write_length); + + // Writes a string piece as a consecutive length/content pair. The + // length uses RFC 9000 Variable Length Integer encoding. + bool WriteStringPieceVarInt62(const absl::string_view& string_piece); + + // Utility function to return the number of bytes needed to encode + // 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 QuicheVariableLengthIntegerLength GetVarInt62Len(uint64_t value); + // Advance the writer's position for writing by |length| bytes without writing // anything. This method only makes sense to be used on a buffer that has // already been written to (and is having certain parts rewritten).
diff --git a/quiche/common/quiche_data_writer_test.cc b/quiche/common/quiche_data_writer_test.cc index 7ae15d2..eb14350 100644 --- a/quiche/common/quiche_data_writer_test.cc +++ b/quiche/common/quiche_data_writer_test.cc
@@ -337,6 +337,416 @@ } } +const int kVarIntBufferLength = 1024; + +// Encodes and then decodes a specified value, checks that the +// value that was encoded is the same as the decoded value, the length +// is correct, and that after decoding, all data in the buffer has +// been consumed.. +// Returns true if everything works, false if not. +bool EncodeDecodeValue(uint64_t value_in, char* buffer, size_t size_of_buffer) { + // Init the buffer to all 0, just for cleanliness. Makes for better + // output if, in debugging, we need to dump out the buffer. + memset(buffer, 0, size_of_buffer); + // make a writer. Note that for IETF encoding + // we do not care about endianness... It's always big-endian, + // but the c'tor expects to be told what endianness is in force... + QuicheDataWriter writer(size_of_buffer, buffer, + quiche::Endianness::NETWORK_BYTE_ORDER); + + // Try to write the value. + if (writer.WriteVarInt62(value_in) != true) { + return false; + } + // Look at the value we encoded. Determine how much should have been + // used based on the value, and then check the state of the writer + // to see that it matches. + size_t expected_length = 0; + if (value_in <= 0x3f) { + expected_length = 1; + } else if (value_in <= 0x3fff) { + expected_length = 2; + } else if (value_in <= 0x3fffffff) { + expected_length = 4; + } else { + expected_length = 8; + } + if (writer.length() != expected_length) { + return false; + } + + // set up a reader, just the length we've used, no more, no less. + QuicheDataReader reader(buffer, expected_length, + quiche::Endianness::NETWORK_BYTE_ORDER); + uint64_t value_out; + + if (reader.ReadVarInt62(&value_out) == false) { + return false; + } + if (value_in != value_out) { + return false; + } + // We only write one value so there had better be nothing left to read + return reader.IsDoneReading(); +} + +// Test that 8-byte-encoded Variable Length Integers are properly laid +// out in the buffer. +TEST_P(QuicheDataWriterTest, VarInt8Layout) { + char buffer[1024]; + + // Check that the layout of bytes in the buffer is correct. Bytes + // are always encoded big endian... + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8))); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), + (0x31 + 0xc0)); // 0xc0 for encoding + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x42); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 2)), 0xf3); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 3)), 0xe4); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 4)), 0xd5); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 5)), 0xc6); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 6)), 0xb7); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 7)), 0xa8); +} + +// Test that 4-byte-encoded Variable Length Integers are properly laid +// out in the buffer. +TEST_P(QuicheDataWriterTest, VarInt4Layout) { + char buffer[1024]; + + // Check that the layout of bytes in the buffer is correct. Bytes + // are always encoded big endian... + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + EXPECT_TRUE(writer.WriteVarInt62(0x3243f4e5)); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), + (0x32 + 0x80)); // 0x80 for encoding + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x43); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 2)), 0xf4); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 3)), 0xe5); +} + +// Test that 2-byte-encoded Variable Length Integers are properly laid +// out in the buffer. +TEST_P(QuicheDataWriterTest, VarInt2Layout) { + char buffer[1024]; + + // Check that the layout of bytes in the buffer is correct. Bytes + // are always encoded big endian... + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + EXPECT_TRUE(writer.WriteVarInt62(0x3647)); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), + (0x36 + 0x40)); // 0x40 for encoding + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x47); +} + +// Test that 1-byte-encoded Variable Length Integers are properly laid +// out in the buffer. +TEST_P(QuicheDataWriterTest, VarInt1Layout) { + char buffer[1024]; + + // Check that the layout of bytes in the buffer + // is correct. Bytes are always encoded big endian... + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + EXPECT_TRUE(writer.WriteVarInt62(0x3f)); + EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), 0x3f); +} + +// Test certain, targeted, values that are expected to succeed: +// 0, 1, +// 0x3e, 0x3f, 0x40, 0x41 (around the 1-2 byte transitions) +// 0x3ffe, 0x3fff, 0x4000, 0x4001 (the 2-4 byte transition) +// 0x3ffffffe, 0x3fffffff, 0x40000000, 0x40000001 (the 4-8 byte +// transition) +// 0x3ffffffffffffffe, 0x3fffffffffffffff, (the highest valid values) +// 0xfe, 0xff, 0x100, 0x101, +// 0xfffe, 0xffff, 0x10000, 0x10001, +// 0xfffffe, 0xffffff, 0x1000000, 0x1000001, +// 0xfffffffe, 0xffffffff, 0x100000000, 0x100000001, +// 0xfffffffffe, 0xffffffffff, 0x10000000000, 0x10000000001, +// 0xfffffffffffe, 0xffffffffffff, 0x1000000000000, 0x1000000000001, +// 0xfffffffffffffe, 0xffffffffffffff, 0x100000000000000, 0x100000000000001, +TEST_P(QuicheDataWriterTest, VarIntGoodTargetedValues) { + char buffer[kVarIntBufferLength]; + uint64_t passing_values[] = { + 0, + 1, + 0x3e, + 0x3f, + 0x40, + 0x41, + 0x3ffe, + 0x3fff, + 0x4000, + 0x4001, + 0x3ffffffe, + 0x3fffffff, + 0x40000000, + 0x40000001, + 0x3ffffffffffffffe, + 0x3fffffffffffffff, + 0xfe, + 0xff, + 0x100, + 0x101, + 0xfffe, + 0xffff, + 0x10000, + 0x10001, + 0xfffffe, + 0xffffff, + 0x1000000, + 0x1000001, + 0xfffffffe, + 0xffffffff, + 0x100000000, + 0x100000001, + 0xfffffffffe, + 0xffffffffff, + 0x10000000000, + 0x10000000001, + 0xfffffffffffe, + 0xffffffffffff, + 0x1000000000000, + 0x1000000000001, + 0xfffffffffffffe, + 0xffffffffffffff, + 0x100000000000000, + 0x100000000000001, + }; + for (uint64_t test_val : passing_values) { + EXPECT_TRUE( + EncodeDecodeValue(test_val, static_cast<char*>(buffer), sizeof(buffer))) + << " encode/decode of " << test_val << " failed"; + } +} +// +// Test certain, targeted, values where failure is expected (the +// values are invalid w.r.t. IETF VarInt encoding): +// 0x4000000000000000, 0x4000000000000001, ( Just above max allowed value) +// 0xfffffffffffffffe, 0xffffffffffffffff, (should fail) +TEST_P(QuicheDataWriterTest, VarIntBadTargetedValues) { + char buffer[kVarIntBufferLength]; + uint64_t failing_values[] = { + 0x4000000000000000, + 0x4000000000000001, + 0xfffffffffffffffe, + 0xffffffffffffffff, + }; + for (uint64_t test_val : failing_values) { + EXPECT_FALSE( + EncodeDecodeValue(test_val, static_cast<char*>(buffer), sizeof(buffer))) + << " encode/decode of " << test_val << " succeeded, but was an " + << "invalid value"; + } +} +// Test writing varints with a forced length. +TEST_P(QuicheDataWriterTest, WriteVarInt62WithForcedLength) { + char buffer[90]; + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer)); + + writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_1); + writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62WithForcedLength(1, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_1); + writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62WithForcedLength(63, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62WithForcedLength(64, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62WithForcedLength(64, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62WithForcedLength(64, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62WithForcedLength(16383, VARIABLE_LENGTH_INTEGER_LENGTH_2); + writer.WriteVarInt62WithForcedLength(16383, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62WithForcedLength(16383, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62WithForcedLength(16384, VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62WithForcedLength(16384, VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62WithForcedLength(1073741823, + VARIABLE_LENGTH_INTEGER_LENGTH_4); + writer.WriteVarInt62WithForcedLength(1073741823, + VARIABLE_LENGTH_INTEGER_LENGTH_8); + + writer.WriteVarInt62WithForcedLength(1073741824, + VARIABLE_LENGTH_INTEGER_LENGTH_8); + + QuicheDataReader reader(buffer, sizeof(buffer)); + + uint64_t test_val = 0; + for (int i = 0; i < 4; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 1u); + } + for (int i = 0; i < 4; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 63u); + } + + for (int i = 0; i < 3; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 64u); + } + for (int i = 0; i < 3; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 16383u); + } + + for (int i = 0; i < 2; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 16384u); + } + for (int i = 0; i < 2; ++i) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 1073741823u); + } + + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, 1073741824u); + + // We are at the end of the buffer so this should fail. + EXPECT_FALSE(reader.ReadVarInt62(&test_val)); +} + +// Following tests all try to fill the buffer with multiple values, +// go one value more than the buffer can accommodate, then read +// the successfully encoded values, and try to read the unsuccessfully +// encoded value. The following is the number of values to encode. +const int kMultiVarCount = 1000; + +// Test writing & reading multiple 8-byte-encoded varints +TEST_P(QuicheDataWriterTest, MultiVarInt8) { + uint64_t test_val; + char buffer[8 * kMultiVarCount]; + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + // Put N values into the buffer. Adding i to the value ensures that + // each value is different so we can detect if we overwrite values, + // or read the same value over and over. + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8) + i)); + } + EXPECT_EQ(writer.length(), 8u * kMultiVarCount); + + // N+1st should fail, the buffer is full. + EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8))); + + // Now we should be able to read out the N values that were + // successfully encoded. + QuicheDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4d5c6b7a8) + i)); + } + // And the N+1st should fail. + EXPECT_FALSE(reader.ReadVarInt62(&test_val)); +} + +// Test writing & reading multiple 4-byte-encoded varints +TEST_P(QuicheDataWriterTest, MultiVarInt4) { + uint64_t test_val; + char buffer[4 * kMultiVarCount]; + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + // Put N values into the buffer. Adding i to the value ensures that + // each value is different so we can detect if we overwrite values, + // or read the same value over and over. + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4) + i)); + } + EXPECT_EQ(writer.length(), 4u * kMultiVarCount); + + // N+1st should fail, the buffer is full. + EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142f3e4))); + + // Now we should be able to read out the N values that were + // successfully encoded. + QuicheDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4) + i)); + } + // And the N+1st should fail. + EXPECT_FALSE(reader.ReadVarInt62(&test_val)); +} + +// Test writing & reading multiple 2-byte-encoded varints +TEST_P(QuicheDataWriterTest, MultiVarInt2) { + uint64_t test_val; + char buffer[2 * kMultiVarCount]; + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + // Put N values into the buffer. Adding i to the value ensures that + // each value is different so we can detect if we overwrite values, + // or read the same value over and over. + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142) + i)); + } + EXPECT_EQ(writer.length(), 2u * kMultiVarCount); + + // N+1st should fail, the buffer is full. + EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142))); + + // Now we should be able to read out the N values that were + // successfully encoded. + QuicheDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, (UINT64_C(0x3142) + i)); + } + // And the N+1st should fail. + EXPECT_FALSE(reader.ReadVarInt62(&test_val)); +} + +// Test writing & reading multiple 1-byte-encoded varints +TEST_P(QuicheDataWriterTest, MultiVarInt1) { + uint64_t test_val; + char buffer[1 * kMultiVarCount]; + memset(buffer, 0, sizeof(buffer)); + QuicheDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + // Put N values into the buffer. Adding i to the value ensures that + // each value is different so we can detect if we overwrite values, + // or read the same value over and over. &0xf ensures we do not + // overflow the max value for single-byte encoding. + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x30) + (i & 0xf))); + } + EXPECT_EQ(writer.length(), 1u * kMultiVarCount); + + // N+1st should fail, the buffer is full. + EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x31))); + + // Now we should be able to read out the N values that were + // successfully encoded. + QuicheDataReader reader(buffer, sizeof(buffer), + quiche::Endianness::NETWORK_BYTE_ORDER); + for (int i = 0; i < kMultiVarCount; i++) { + EXPECT_TRUE(reader.ReadVarInt62(&test_val)); + EXPECT_EQ(test_val, (UINT64_C(0x30) + (i & 0xf))); + } + // And the N+1st should fail. + EXPECT_FALSE(reader.ReadVarInt62(&test_val)); +} + TEST_P(QuicheDataWriterTest, Seek) { char buffer[3] = {}; QuicheDataWriter writer(ABSL_ARRAYSIZE(buffer), buffer,
diff --git a/quiche/common/quiche_endian.h b/quiche/common/quiche_endian.h index 30639cc..834f743 100644 --- a/quiche/common/quiche_endian.h +++ b/quiche/common/quiche_endian.h
@@ -54,6 +54,20 @@ } }; +enum QuicheVariableLengthIntegerLength : 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. + kQuicheDefaultLongHeaderLengthLength = VARIABLE_LENGTH_INTEGER_LENGTH_2, +}; + } // namespace quiche #endif // QUICHE_COMMON_QUICHE_ENDIAN_H_
diff --git a/quiche/quic/core/chlo_extractor_test.cc b/quiche/quic/core/chlo_extractor_test.cc index 3852469..6b49fdc 100644 --- a/quiche/quic/core/chlo_extractor_test.cc +++ b/quiche/quic/core/chlo_extractor_test.cc
@@ -65,8 +65,9 @@ header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; header.packet_number = QuicPacketNumber(1); if (version_.HasLongHeaderLengths()) { - header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.retry_token_length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicFrames frames; size_t offset = 0;
diff --git a/quiche/quic/core/crypto/transport_parameters.cc b/quiche/quic/core/crypto/transport_parameters.cc index 635d159..140c16a 100644 --- a/quiche/quic/core/crypto/transport_parameters.cc +++ b/quiche/quic/core/crypto/transport_parameters.cc
@@ -177,13 +177,13 @@ has_been_read_(false) { QUICHE_DCHECK_LE(min_value, default_value); QUICHE_DCHECK_LE(default_value, max_value); - QUICHE_DCHECK_LE(max_value, kVarInt62MaxValue); + QUICHE_DCHECK_LE(max_value, quiche::kVarInt62MaxValue); } TransportParameters::IntegerParameter::IntegerParameter( TransportParameters::TransportParameterId param_id) : TransportParameters::IntegerParameter::IntegerParameter( - param_id, 0, 0, kVarInt62MaxValue) {} + param_id, 0, 0, quiche::kVarInt62MaxValue) {} void TransportParameters::IntegerParameter::set_value(uint64_t value) { value_ = value; @@ -206,13 +206,13 @@ QUIC_BUG(quic_bug_10743_1) << "Failed to write param_id for " << *this; return false; } - const QuicVariableLengthIntegerLength value_length = + const quiche::QuicheVariableLengthIntegerLength value_length = QuicDataWriter::GetVarInt62Len(value_); if (!writer->WriteVarInt62(value_length)) { QUIC_BUG(quic_bug_10743_2) << "Failed to write value_length for " << *this; return false; } - if (!writer->WriteVarInt62(value_, value_length)) { + if (!writer->WriteVarInt62WithForcedLength(value_, value_length)) { QUIC_BUG(quic_bug_10743_3) << "Failed to write value for " << *this; return false; } @@ -451,7 +451,8 @@ TransportParameters::TransportParameters() : max_idle_timeout_ms(kMaxIdleTimeout), max_udp_payload_size(kMaxPacketSize, kDefaultMaxPacketSizeTransportParam, - kMinMaxPacketSizeTransportParam, kVarInt62MaxValue), + kMinMaxPacketSizeTransportParam, + quiche::kVarInt62MaxValue), initial_max_data(kInitialMaxData), initial_max_stream_data_bidi_local(kInitialMaxStreamDataBidiLocal), initial_max_stream_data_bidi_remote(kInitialMaxStreamDataBidiRemote), @@ -469,7 +470,7 @@ active_connection_id_limit(kActiveConnectionIdLimit, kDefaultActiveConnectionIdLimitTransportParam, kMinActiveConnectionIdLimitTransportParam, - kVarInt62MaxValue), + quiche::kVarInt62MaxValue), max_datagram_frame_size(kMaxDatagramFrameSize), initial_round_trip_time_us(kInitialRoundTripTime) // Important note: any new transport parameters must be added
diff --git a/quiche/quic/core/crypto/transport_parameters.h b/quiche/quic/core/crypto/transport_parameters.h index e1f349b..14ae6e9 100644 --- a/quiche/quic/core/crypto/transport_parameters.h +++ b/quiche/quic/core/crypto/transport_parameters.h
@@ -61,7 +61,7 @@ friend struct TransportParameters; // Constructors for initial setup used by TransportParameters only. // This constructor sets |default_value| and |min_value| to 0, and - // |max_value| to kVarInt62MaxValue. + // |max_value| to quiche::kVarInt62MaxValue. explicit IntegerParameter(TransportParameterId param_id); IntegerParameter(TransportParameterId param_id, uint64_t default_value, uint64_t min_value, uint64_t max_value);
diff --git a/quiche/quic/core/http/http_decoder.cc b/quiche/quic/core/http/http_decoder.cc index 5845a37..2bdce8e 100644 --- a/quiche/quic/core/http/http_decoder.cc +++ b/quiche/quic/core/http/http_decoder.cc
@@ -657,9 +657,9 @@ case static_cast<uint64_t>(HttpFrameType::SETTINGS): return kPayloadLengthLimit; case static_cast<uint64_t>(HttpFrameType::GOAWAY): - return VARIABLE_LENGTH_INTEGER_LENGTH_8; + return quiche::VARIABLE_LENGTH_INTEGER_LENGTH_8; case static_cast<uint64_t>(HttpFrameType::MAX_PUSH_ID): - return VARIABLE_LENGTH_INTEGER_LENGTH_8; + return quiche::VARIABLE_LENGTH_INTEGER_LENGTH_8; case static_cast<uint64_t>(HttpFrameType::PRIORITY_UPDATE_REQUEST_STREAM): return kPayloadLengthLimit; case static_cast<uint64_t>(HttpFrameType::ACCEPT_CH):
diff --git a/quiche/quic/core/http/http_decoder_test.cc b/quiche/quic/core/http/http_decoder_test.cc index 3ea97ca..c0a18ee 100644 --- a/quiche/quic/core/http/http_decoder_test.cc +++ b/quiche/quic/core/http/http_decoder_test.cc
@@ -569,7 +569,8 @@ HttpDecoder decoder(&visitor); QuicDataWriter writer(max_input_length, input); ASSERT_TRUE(writer.WriteVarInt62(frame_type)); // frame type. - ASSERT_TRUE(writer.WriteVarInt62(kVarInt62MaxValue)); // frame length. + ASSERT_TRUE( + writer.WriteVarInt62(quiche::kVarInt62MaxValue)); // frame length. ASSERT_TRUE(writer.WriteUInt8(0x00)); // one byte of payload. EXPECT_NE(decoder.ProcessInput(input, writer.length()), 0u) << frame_type; }
diff --git a/quiche/quic/core/quic_chaos_protector_test.cc b/quiche/quic/core/quic_chaos_protector_test.cc index 95c073a..92d3af9 100644 --- a/quiche/quic/core/quic_chaos_protector_test.cc +++ b/quiche/quic/core/quic_chaos_protector_test.cc
@@ -87,8 +87,9 @@ header_.packet_number = QuicPacketNumber(1); header_.form = IETF_QUIC_LONG_HEADER_PACKET; header_.long_packet_type = INITIAL; - header_.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - header_.length_length = kQuicDefaultLongHeaderLengthLength; + header_.retry_token_length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + header_.length_length = quiche::kQuicheDefaultLongHeaderLengthLength; // Setup validation framer. validation_framer_.framer()->SetInitialObfuscators( header_.destination_connection_id);
diff --git a/quiche/quic/core/quic_config.cc b/quiche/quic/core/quic_config.cc index c48001a..04aa196 100644 --- a/quiche/quic/core/quic_config.cc +++ b/quiche/quic/core/quic_config.cc
@@ -147,9 +147,9 @@ } void QuicFixedUint62::SetSendValue(uint64_t value) { - if (value > kVarInt62MaxValue) { + if (value > quiche::kVarInt62MaxValue) { QUIC_BUG(quic_bug_10575_3) << "QuicFixedUint62 invalid value " << value; - value = kVarInt62MaxValue; + value = quiche::kVarInt62MaxValue; } has_send_value_ = true; send_value_ = value;
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc index 21a4bbf..dca0520 100644 --- a/quiche/quic/core/quic_connection_test.cc +++ b/quiche/quic/core/quic_connection_test.cc
@@ -1119,9 +1119,10 @@ header.long_packet_type = EncryptionlevelToLongHeaderType(level); if (QuicVersionHasLongHeaderLengths( peer_framer_.version().transport_version)) { - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; if (header.long_packet_type == INITIAL) { - header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.retry_token_length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; } } } @@ -2893,8 +2894,8 @@ 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; + header.retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicFrames frames; @@ -2941,8 +2942,8 @@ 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; + header.retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicFrames frames;
diff --git a/quiche/quic/core/quic_crypto_stream.cc b/quiche/quic/core/quic_crypto_stream.cc index 904557b..45f5351 100644 --- a/quiche/quic/core/quic_crypto_stream.cc +++ b/quiche/quic/core/quic_crypto_stream.cc
@@ -49,13 +49,13 @@ QuicTransportVersion version, QuicConnectionId connection_id) { QUICHE_DCHECK( QuicUtils::IsConnectionIdValidForVersion(connection_id, version)); - QuicVariableLengthIntegerLength retry_token_length_length = - VARIABLE_LENGTH_INTEGER_LENGTH_1; - QuicVariableLengthIntegerLength length_length = - VARIABLE_LENGTH_INTEGER_LENGTH_2; + quiche::QuicheVariableLengthIntegerLength retry_token_length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + quiche::QuicheVariableLengthIntegerLength length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; if (!QuicVersionHasLongHeaderLengths(version)) { - retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; - length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; + length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; } return QuicPacketCreator::StreamFramePacketOverhead( version, static_cast<QuicConnectionIdLength>(connection_id.length()),
diff --git a/quiche/quic/core/quic_data_reader.cc b/quiche/quic/core/quic_data_reader.cc index 1a06057..aa8b278 100644 --- a/quiche/quic/core/quic_data_reader.cc +++ b/quiche/quic/core/quic_data_reader.cc
@@ -83,93 +83,5 @@ return ReadConnectionId(connection_id, connection_id_length); } -QuicVariableLengthIntegerLength QuicDataReader::PeekVarInt62Length() { - QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); - const unsigned char* next = - reinterpret_cast<const unsigned char*>(data() + pos()); - if (BytesRemaining() == 0) { - return VARIABLE_LENGTH_INTEGER_LENGTH_0; - } - return static_cast<QuicVariableLengthIntegerLength>( - 1 << ((*next & 0b11000000) >> 6)); -} - -// Read an IETF/QUIC formatted 62-bit Variable Length Integer. -// -// Performance notes -// -// Measurements and experiments showed that unrolling the four cases -// like this and dereferencing next_ as we do (*(next_+n) --- and then -// doing a single pos_+=x at the end) gains about 10% over making a -// loop and dereferencing next_ such as *(next_++) -// -// Using a register for pos_ was not helpful. -// -// Branches are ordered to increase the likelihood of the first being -// taken. -// -// Low-level optimization is useful here because this function will be -// called frequently, leading to outsize benefits. -bool QuicDataReader::ReadVarInt62(uint64_t* result) { - QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); - - size_t remaining = BytesRemaining(); - const unsigned char* next = - reinterpret_cast<const unsigned char*>(data() + pos()); - if (remaining != 0) { - switch (*next & 0xc0) { - case 0xc0: - // Leading 0b11...... is 8 byte encoding - if (remaining >= 8) { - *result = (static_cast<uint64_t>((*(next)) & 0x3f) << 56) + - (static_cast<uint64_t>(*(next + 1)) << 48) + - (static_cast<uint64_t>(*(next + 2)) << 40) + - (static_cast<uint64_t>(*(next + 3)) << 32) + - (static_cast<uint64_t>(*(next + 4)) << 24) + - (static_cast<uint64_t>(*(next + 5)) << 16) + - (static_cast<uint64_t>(*(next + 6)) << 8) + - (static_cast<uint64_t>(*(next + 7)) << 0); - AdvancePos(8); - return true; - } - return false; - - case 0x80: - // Leading 0b10...... is 4 byte encoding - if (remaining >= 4) { - *result = (((*(next)) & 0x3f) << 24) + (((*(next + 1)) << 16)) + - (((*(next + 2)) << 8)) + (((*(next + 3)) << 0)); - AdvancePos(4); - return true; - } - return false; - - case 0x40: - // Leading 0b01...... is 2 byte encoding - if (remaining >= 2) { - *result = (((*(next)) & 0x3f) << 8) + (*(next + 1)); - AdvancePos(2); - return true; - } - return false; - - case 0x00: - // Leading 0b00...... is 1 byte encoding - *result = (*next) & 0x3f; - AdvancePos(1); - return true; - } - } - return false; -} - -bool QuicDataReader::ReadStringPieceVarInt62(absl::string_view* result) { - uint64_t result_length; - if (!ReadVarInt62(&result_length)) { - return false; - } - return ReadStringPiece(result, result_length); -} - #undef ENDPOINT // undef for jumbo builds } // namespace quic
diff --git a/quiche/quic/core/quic_data_reader.h b/quiche/quic/core/quic_data_reader.h index 0a67df8..0a907e0 100644 --- a/quiche/quic/core/quic_data_reader.h +++ b/quiche/quic/core/quic_data_reader.h
@@ -62,29 +62,6 @@ // Forwards the internal iterator on success. // Returns true on success, false otherwise. bool ReadLengthPrefixedConnectionId(QuicConnectionId* connection_id); - - // 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. - QuicVariableLengthIntegerLength PeekVarInt62Length(); - - // Read an IETF-encoded Variable Length Integer and place the result - // in |*result|. - // Returns true if it works, false if not. The only error is that - // there is not enough in the buffer to read the number. - // If there is an error, |*result| is not altered. - // Numbers are encoded per the rules in draft-ietf-quic-transport-10.txt - // and that the integers in the range 0 ... (2^62)-1. - bool ReadVarInt62(uint64_t* result); - - // Reads a string prefixed with a Variable Length integer length into the - // given output parameter. - // - // NOTE: Does not copy but rather references strings in the underlying buffer. - // This should be kept in mind when handling memory management! - // - // Forwards the internal iterator on success. - // Returns true on success, false otherwise. - bool ReadStringPieceVarInt62(absl::string_view* result); }; } // namespace quic
diff --git a/quiche/quic/core/quic_data_writer.cc b/quiche/quic/core/quic_data_writer.cc index 4fbd3b6..09f1923 100644 --- a/quiche/quic/core/quic_data_writer.cc +++ b/quiche/quic/core/quic_data_writer.cc
@@ -102,157 +102,4 @@ return true; } -// Converts a uint64_t into an IETF/Quic formatted Variable Length -// Integer. IETF Variable Length Integers have 62 significant bits, so -// the value to write must be in the range of 0..(2^62)-1. -// -// Performance notes -// -// Measurements and experiments showed that unrolling the four cases -// like this and dereferencing next_ as we do (*(next_+n)) gains about -// 10% over making a loop and dereferencing it as *(next_++) -// -// Using a register for next didn't help. -// -// Branches are ordered to increase the likelihood of the first being -// taken. -// -// Low-level optimization is useful here because this function will be -// called frequently, leading to outsize benefits. -bool QuicDataWriter::WriteVarInt62(uint64_t value) { - QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); - - size_t remaining_bytes = remaining(); - char* next = buffer() + length(); - - if ((value & kVarInt62ErrorMask) == 0) { - // We know the high 2 bits are 0 so |value| is legal. - // We can do the encoding. - if ((value & kVarInt62Mask8Bytes) != 0) { - // Someplace in the high-4 bytes is a 1-bit. Do an 8-byte - // encoding. - if (remaining_bytes >= 8) { - *(next + 0) = ((value >> 56) & 0x3f) + 0xc0; - *(next + 1) = (value >> 48) & 0xff; - *(next + 2) = (value >> 40) & 0xff; - *(next + 3) = (value >> 32) & 0xff; - *(next + 4) = (value >> 24) & 0xff; - *(next + 5) = (value >> 16) & 0xff; - *(next + 6) = (value >> 8) & 0xff; - *(next + 7) = value & 0xff; - IncreaseLength(8); - return true; - } - return false; - } - // The high-order-4 bytes are all 0, check for a 1, 2, or 4-byte - // encoding - if ((value & kVarInt62Mask4Bytes) != 0) { - // The encoding will not fit into 2 bytes, Do a 4-byte - // encoding. - if (remaining_bytes >= 4) { - *(next + 0) = ((value >> 24) & 0x3f) + 0x80; - *(next + 1) = (value >> 16) & 0xff; - *(next + 2) = (value >> 8) & 0xff; - *(next + 3) = value & 0xff; - IncreaseLength(4); - return true; - } - return false; - } - // The high-order bits are all 0. Check to see if the number - // can be encoded as one or two bytes. One byte encoding has - // only 6 significant bits (bits 0xffffffff ffffffc0 are all 0). - // Two byte encoding has more than 6, but 14 or less significant - // bits (bits 0xffffffff ffffc000 are 0 and 0x00000000 00003fc0 - // are not 0) - if ((value & kVarInt62Mask2Bytes) != 0) { - // Do 2-byte encoding - if (remaining_bytes >= 2) { - *(next + 0) = ((value >> 8) & 0x3f) + 0x40; - *(next + 1) = (value)&0xff; - IncreaseLength(2); - return true; - } - return false; - } - if (remaining_bytes >= 1) { - // Do 1-byte encoding - *next = (value & 0x3f); - IncreaseLength(1); - return true; - } - return false; - } - // Can not encode, high 2 bits not 0 - return false; -} - -bool QuicDataWriter::WriteVarInt62( - uint64_t value, QuicVariableLengthIntegerLength write_length) { - QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); - - size_t remaining_bytes = remaining(); - if (remaining_bytes < write_length) { - return false; - } - - const QuicVariableLengthIntegerLength min_length = GetVarInt62Len(value); - if (write_length < min_length) { - QUIC_BUG(quic_bug_10347_1) << "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(quic_bug_10347_2) - << "Invalid write_length " << static_cast<int>(write_length); - return false; -} - -// static -QuicVariableLengthIntegerLength QuicDataWriter::GetVarInt62Len(uint64_t value) { - if ((value & kVarInt62ErrorMask) != 0) { - QUIC_BUG(quic_bug_10347_3) << "Attempted to encode a value, " << value - << ", that is too big for VarInt62"; - return VARIABLE_LENGTH_INTEGER_LENGTH_0; - } - if ((value & kVarInt62Mask8Bytes) != 0) { - return VARIABLE_LENGTH_INTEGER_LENGTH_8; - } - if ((value & kVarInt62Mask4Bytes) != 0) { - return VARIABLE_LENGTH_INTEGER_LENGTH_4; - } - if ((value & kVarInt62Mask2Bytes) != 0) { - return VARIABLE_LENGTH_INTEGER_LENGTH_2; - } - return VARIABLE_LENGTH_INTEGER_LENGTH_1; -} - -bool QuicDataWriter::WriteStringPieceVarInt62( - const absl::string_view& string_piece) { - if (!WriteVarInt62(string_piece.size())) { - return false; - } - if (!string_piece.empty()) { - if (!WriteBytes(string_piece.data(), string_piece.size())) { - return false; - } - } - return true; -} - } // namespace quic
diff --git a/quiche/quic/core/quic_data_writer.h b/quiche/quic/core/quic_data_writer.h index b1cd198..c96b3b7 100644 --- a/quiche/quic/core/quic_data_writer.h +++ b/quiche/quic/core/quic_data_writer.h
@@ -18,19 +18,6 @@ class QuicRandom; -// Maximum value that can be properly encoded using VarInt62 coding. -const uint64_t kVarInt62MaxValue = UINT64_C(0x3fffffffffffffff); - -// VarInt62 encoding masks -// If a uint64_t anded with a mask is not 0 then the value is encoded -// using that length (or is too big, in the case of kVarInt62ErrorMask). -// Values must be checked in order (error, 8-, 4-, and then 2- bytes) -// and if none are non-0, the value is encoded in 1 byte. -const uint64_t kVarInt62ErrorMask = UINT64_C(0xc000000000000000); -const uint64_t kVarInt62Mask8Bytes = UINT64_C(0x3fffffffc0000000); -const uint64_t kVarInt62Mask4Bytes = UINT64_C(0x000000003fffc000); -const uint64_t kVarInt62Mask2Bytes = UINT64_C(0x0000000000003fc0); - // This class provides facilities for packing QUIC data. // // The QuicDataWriter supports appending primitive values (int, string, etc) @@ -52,31 +39,6 @@ // Methods for adding to the payload. These values are appended to the end // of the QuicDataWriter payload. - // Write an unsigned-integer value per the IETF QUIC/Variable Length - // Integer encoding rules (see draft-ietf-quic-transport-08.txt). - // IETF Variable Length Integers have 62 significant bits, so the - // value to write must be in the range of 0...(2^62)-1. Returns - // false if the value is out of range or if there is no room in the - // 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 absl::string_view& string_piece); - - // Utility function to return the number of bytes needed to encode - // 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 QuicVariableLengthIntegerLength GetVarInt62Len(uint64_t value); - // Write unsigned floating point corresponding to the value. Large values are // clamped to the maximum representable (kUFloat16MaxValue). Values that can // not be represented directly are rounded down.
diff --git a/quiche/quic/core/quic_data_writer_test.cc b/quiche/quic/core/quic_data_writer_test.cc index 5d20c84..9d454e9 100644 --- a/quiche/quic/core/quic_data_writer_test.cc +++ b/quiche/quic/core/quic_data_writer_test.cc
@@ -666,416 +666,12 @@ } } -const int kVarIntBufferLength = 1024; - -// Encodes and then decodes a specified value, checks that the -// value that was encoded is the same as the decoded value, the length -// is correct, and that after decoding, all data in the buffer has -// been consumed.. -// Returns true if everything works, false if not. -bool EncodeDecodeValue(uint64_t value_in, char* buffer, size_t size_of_buffer) { - // Init the buffer to all 0, just for cleanliness. Makes for better - // output if, in debugging, we need to dump out the buffer. - memset(buffer, 0, size_of_buffer); - // make a writer. Note that for IETF encoding - // we do not care about endianness... It's always big-endian, - // but the c'tor expects to be told what endianness is in force... - QuicDataWriter writer(size_of_buffer, buffer, - quiche::Endianness::NETWORK_BYTE_ORDER); - - // Try to write the value. - if (writer.WriteVarInt62(value_in) != true) { - return false; - } - // Look at the value we encoded. Determine how much should have been - // used based on the value, and then check the state of the writer - // to see that it matches. - size_t expected_length = 0; - if (value_in <= 0x3f) { - expected_length = 1; - } else if (value_in <= 0x3fff) { - expected_length = 2; - } else if (value_in <= 0x3fffffff) { - expected_length = 4; - } else { - expected_length = 8; - } - if (writer.length() != expected_length) { - return false; - } - - // set up a reader, just the length we've used, no more, no less. - QuicDataReader reader(buffer, expected_length, - quiche::Endianness::NETWORK_BYTE_ORDER); - uint64_t value_out; - - if (reader.ReadVarInt62(&value_out) == false) { - return false; - } - if (value_in != value_out) { - return false; - } - // We only write one value so there had better be nothing left to read - return reader.IsDoneReading(); -} - -// Test that 8-byte-encoded Variable Length Integers are properly laid -// out in the buffer. -TEST_P(QuicDataWriterTest, VarInt8Layout) { - char buffer[1024]; - - // Check that the layout of bytes in the buffer is correct. Bytes - // are always encoded big endian... - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8))); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), - (0x31 + 0xc0)); // 0xc0 for encoding - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x42); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 2)), 0xf3); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 3)), 0xe4); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 4)), 0xd5); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 5)), 0xc6); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 6)), 0xb7); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 7)), 0xa8); -} - -// Test that 4-byte-encoded Variable Length Integers are properly laid -// out in the buffer. -TEST_P(QuicDataWriterTest, VarInt4Layout) { - char buffer[1024]; - - // Check that the layout of bytes in the buffer is correct. Bytes - // are always encoded big endian... - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - EXPECT_TRUE(writer.WriteVarInt62(0x3243f4e5)); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), - (0x32 + 0x80)); // 0x80 for encoding - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x43); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 2)), 0xf4); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 3)), 0xe5); -} - -// Test that 2-byte-encoded Variable Length Integers are properly laid -// out in the buffer. -TEST_P(QuicDataWriterTest, VarInt2Layout) { - char buffer[1024]; - - // Check that the layout of bytes in the buffer is correct. Bytes - // are always encoded big endian... - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - EXPECT_TRUE(writer.WriteVarInt62(0x3647)); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), - (0x36 + 0x40)); // 0x40 for encoding - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 1)), 0x47); -} - -// Test that 1-byte-encoded Variable Length Integers are properly laid -// out in the buffer. -TEST_P(QuicDataWriterTest, VarInt1Layout) { - char buffer[1024]; - - // Check that the layout of bytes in the buffer - // is correct. Bytes are always encoded big endian... - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - EXPECT_TRUE(writer.WriteVarInt62(0x3f)); - EXPECT_EQ(static_cast<unsigned char>(*(writer.data() + 0)), 0x3f); -} - -// Test certain, targeted, values that are expected to succeed: -// 0, 1, -// 0x3e, 0x3f, 0x40, 0x41 (around the 1-2 byte transitions) -// 0x3ffe, 0x3fff, 0x4000, 0x4001 (the 2-4 byte transition) -// 0x3ffffffe, 0x3fffffff, 0x40000000, 0x40000001 (the 4-8 byte -// transition) -// 0x3ffffffffffffffe, 0x3fffffffffffffff, (the highest valid values) -// 0xfe, 0xff, 0x100, 0x101, -// 0xfffe, 0xffff, 0x10000, 0x10001, -// 0xfffffe, 0xffffff, 0x1000000, 0x1000001, -// 0xfffffffe, 0xffffffff, 0x100000000, 0x100000001, -// 0xfffffffffe, 0xffffffffff, 0x10000000000, 0x10000000001, -// 0xfffffffffffe, 0xffffffffffff, 0x1000000000000, 0x1000000000001, -// 0xfffffffffffffe, 0xffffffffffffff, 0x100000000000000, 0x100000000000001, -TEST_P(QuicDataWriterTest, VarIntGoodTargetedValues) { - char buffer[kVarIntBufferLength]; - uint64_t passing_values[] = { - 0, - 1, - 0x3e, - 0x3f, - 0x40, - 0x41, - 0x3ffe, - 0x3fff, - 0x4000, - 0x4001, - 0x3ffffffe, - 0x3fffffff, - 0x40000000, - 0x40000001, - 0x3ffffffffffffffe, - 0x3fffffffffffffff, - 0xfe, - 0xff, - 0x100, - 0x101, - 0xfffe, - 0xffff, - 0x10000, - 0x10001, - 0xfffffe, - 0xffffff, - 0x1000000, - 0x1000001, - 0xfffffffe, - 0xffffffff, - 0x100000000, - 0x100000001, - 0xfffffffffe, - 0xffffffffff, - 0x10000000000, - 0x10000000001, - 0xfffffffffffe, - 0xffffffffffff, - 0x1000000000000, - 0x1000000000001, - 0xfffffffffffffe, - 0xffffffffffffff, - 0x100000000000000, - 0x100000000000001, - }; - for (uint64_t test_val : passing_values) { - EXPECT_TRUE( - EncodeDecodeValue(test_val, static_cast<char*>(buffer), sizeof(buffer))) - << " encode/decode of " << test_val << " failed"; - } -} -// -// Test certain, targeted, values where failure is expected (the -// values are invalid w.r.t. IETF VarInt encoding): -// 0x4000000000000000, 0x4000000000000001, ( Just above max allowed value) -// 0xfffffffffffffffe, 0xffffffffffffffff, (should fail) -TEST_P(QuicDataWriterTest, VarIntBadTargetedValues) { - char buffer[kVarIntBufferLength]; - uint64_t failing_values[] = { - 0x4000000000000000, - 0x4000000000000001, - 0xfffffffffffffffe, - 0xffffffffffffffff, - }; - for (uint64_t test_val : failing_values) { - EXPECT_FALSE( - EncodeDecodeValue(test_val, static_cast<char*>(buffer), sizeof(buffer))) - << " encode/decode of " << test_val << " succeeded, but was an " - << "invalid value"; - } -} - // Following tests all try to fill the buffer with multiple values, // go one value more than the buffer can accommodate, then read // the successfully encoded values, and try to read the unsuccessfully // encoded value. The following is the number of values to encode. const int kMultiVarCount = 1000; -// Test writing & reading multiple 8-byte-encoded varints -TEST_P(QuicDataWriterTest, MultiVarInt8) { - uint64_t test_val; - char buffer[8 * kMultiVarCount]; - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - // Put N values into the buffer. Adding i to the value ensures that - // each value is different so we can detect if we overwrite values, - // or read the same value over and over. - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8) + i)); - } - EXPECT_EQ(writer.length(), 8u * kMultiVarCount); - - // N+1st should fail, the buffer is full. - EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142f3e4d5c6b7a8))); - - // Now we should be able to read out the N values that were - // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4d5c6b7a8) + i)); - } - // And the N+1st should fail. - EXPECT_FALSE(reader.ReadVarInt62(&test_val)); -} - -// Test writing & reading multiple 4-byte-encoded varints -TEST_P(QuicDataWriterTest, MultiVarInt4) { - uint64_t test_val; - char buffer[4 * kMultiVarCount]; - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - // Put N values into the buffer. Adding i to the value ensures that - // each value is different so we can detect if we overwrite values, - // or read the same value over and over. - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142f3e4) + i)); - } - EXPECT_EQ(writer.length(), 4u * kMultiVarCount); - - // N+1st should fail, the buffer is full. - EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142f3e4))); - - // Now we should be able to read out the N values that were - // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, (UINT64_C(0x3142f3e4) + i)); - } - // And the N+1st should fail. - EXPECT_FALSE(reader.ReadVarInt62(&test_val)); -} - -// Test writing & reading multiple 2-byte-encoded varints -TEST_P(QuicDataWriterTest, MultiVarInt2) { - uint64_t test_val; - char buffer[2 * kMultiVarCount]; - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - // Put N values into the buffer. Adding i to the value ensures that - // each value is different so we can detect if we overwrite values, - // or read the same value over and over. - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x3142) + i)); - } - EXPECT_EQ(writer.length(), 2u * kMultiVarCount); - - // N+1st should fail, the buffer is full. - EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x3142))); - - // Now we should be able to read out the N values that were - // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, (UINT64_C(0x3142) + i)); - } - // And the N+1st should fail. - EXPECT_FALSE(reader.ReadVarInt62(&test_val)); -} - -// Test writing & reading multiple 1-byte-encoded varints -TEST_P(QuicDataWriterTest, MultiVarInt1) { - uint64_t test_val; - char buffer[1 * kMultiVarCount]; - memset(buffer, 0, sizeof(buffer)); - QuicDataWriter writer(sizeof(buffer), static_cast<char*>(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - // Put N values into the buffer. Adding i to the value ensures that - // each value is different so we can detect if we overwrite values, - // or read the same value over and over. &0xf ensures we do not - // overflow the max value for single-byte encoding. - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(writer.WriteVarInt62(UINT64_C(0x30) + (i & 0xf))); - } - EXPECT_EQ(writer.length(), 1u * kMultiVarCount); - - // N+1st should fail, the buffer is full. - EXPECT_FALSE(writer.WriteVarInt62(UINT64_C(0x31))); - - // Now we should be able to read out the N values that were - // successfully encoded. - QuicDataReader reader(buffer, sizeof(buffer), - quiche::Endianness::NETWORK_BYTE_ORDER); - for (int i = 0; i < kMultiVarCount; i++) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, (UINT64_C(0x30) + (i & 0xf))); - } - // And the N+1st should fail. - 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), - quiche::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), - quiche::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, 1u); - } - for (int i = 0; i < 4; ++i) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, 63u); - } - - for (int i = 0; i < 3; ++i) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, 64u); - } - for (int i = 0; i < 3; ++i) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, 16383u); - } - - for (int i = 0; i < 2; ++i) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, 16384u); - } - for (int i = 0; i < 2; ++i) { - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, 1073741823u); - } - - EXPECT_TRUE(reader.ReadVarInt62(&test_val)); - EXPECT_EQ(test_val, 1073741824u); - - // 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) { char buffer[1 * kMultiVarCount];
diff --git a/quiche/quic/core/quic_framer.cc b/quiche/quic/core/quic_framer.cc index b6b0c5b..1630a2c 100644 --- a/quiche/quic/core/quic_framer.cc +++ b/quiche/quic/core/quic_framer.cc
@@ -860,20 +860,20 @@ } if (writer->length() < length_field_offset || writer->length() - length_field_offset < - kQuicDefaultLongHeaderLengthLength) { + quiche::kQuicheDefaultLongHeaderLengthLength) { set_detailed_error("Invalid length_field_offset."); QUIC_BUG(quic_bug_10850_14) << "Invalid length_field_offset."; return false; } size_t length_to_write = writer->length() - length_field_offset - - kQuicDefaultLongHeaderLengthLength; + quiche::kQuicheDefaultLongHeaderLengthLength; // 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)) { + if (!length_writer.WriteVarInt62WithForcedLength( + length_to_write, quiche::kQuicheDefaultLongHeaderLengthLength)) { set_detailed_error("Failed to overwrite long header length."); QUIC_BUG(quic_bug_10850_15) << "Failed to overwrite long header length."; return false; @@ -1741,7 +1741,7 @@ size_t buffer_length) { QUICHE_DCHECK_NE(GOOGLE_QUIC_PACKET, header->form); QUICHE_DCHECK(!header->has_possible_stateless_reset_token); - header->length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + header->length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; header->remaining_packet_length = 0; if (header->form == IETF_QUIC_SHORT_HEADER_PACKET && perspective_ == Perspective::IS_CLIENT) { @@ -2274,13 +2274,13 @@ if (QuicVersionHasLongHeaderLengths(transport_version()) && header.version_flag) { if (header.long_packet_type == INITIAL) { - QUICHE_DCHECK_NE(VARIABLE_LENGTH_INTEGER_LENGTH_0, + QUICHE_DCHECK_NE(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, header.retry_token_length_length) << ENDPOINT << ParsedQuicVersionToString(version_) << " bad retry token length length in header: " << header; // Write retry token length. - if (!writer->WriteVarInt62(header.retry_token.length(), - header.retry_token_length_length)) { + if (!writer->WriteVarInt62WithForcedLength( + header.retry_token.length(), header.retry_token_length_length)) { return false; } // Write retry token. @@ -3963,7 +3963,8 @@ return false; } - if (ack_delay_time_in_us >= (kVarInt62MaxValue >> peer_ack_delay_exponent_)) { + if (ack_delay_time_in_us >= + (quiche::kVarInt62MaxValue >> peer_ack_delay_exponent_)) { ack_frame->ack_delay_time = QuicTime::Delta::Infinite(); } else { ack_delay_time_in_us = (ack_delay_time_in_us << peer_ack_delay_exponent_); @@ -4358,9 +4359,9 @@ QuicConnectionIdLength source_connection_id_length, bool includes_version, bool includes_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, uint64_t retry_token_length, - QuicVariableLengthIntegerLength length_length) { + quiche::QuicheVariableLengthIntegerLength length_length) { // TODO(ianswett): This is identical to QuicData::AssociatedData. return absl::string_view( encrypted.data(), @@ -6028,7 +6029,7 @@ return false; } - uint64_t ack_delay_time_us = kVarInt62MaxValue; + uint64_t ack_delay_time_us = quiche::kVarInt62MaxValue; if (!frame.ack_delay_time.IsInfinite()) { QUICHE_DCHECK_LE(0u, frame.ack_delay_time.ToMicroseconds()); ack_delay_time_us = frame.ack_delay_time.ToMicroseconds(); @@ -6812,7 +6813,7 @@ } const bool ietf_format = QuicUtils::IsIetfPacketHeader(first_byte); uint8_t unused_first_byte; - QuicVariableLengthIntegerLength retry_token_length_length; + quiche::QuicheVariableLengthIntegerLength retry_token_length_length; absl::string_view maybe_retry_token; QuicErrorCode error_code = ParsePublicHeader( &reader, expected_destination_connection_id_length, ietf_format, @@ -6820,7 +6821,7 @@ version_label, parsed_version, destination_connection_id, source_connection_id, long_packet_type, &retry_token_length_length, &maybe_retry_token, detailed_error); - if (retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) { + if (retry_token_length_length != quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0) { *retry_token = maybe_retry_token; } else { retry_token->reset(); @@ -6961,7 +6962,7 @@ QuicConnectionId* destination_connection_id, QuicConnectionId* source_connection_id, QuicLongHeaderType* long_packet_type, - QuicVariableLengthIntegerLength* retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength* retry_token_length_length, absl::string_view* retry_token, std::string* detailed_error) { *version_present = false; *has_length_prefix = false; @@ -6969,7 +6970,7 @@ *parsed_version = UnsupportedQuicVersion(); *source_connection_id = EmptyQuicConnectionId(); *long_packet_type = INVALID_PACKET_TYPE; - *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + *retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; *retry_token = absl::string_view(); *detailed_error = ""; @@ -7047,7 +7048,7 @@ *retry_token_length_length = reader->PeekVarInt62Length(); uint64_t retry_token_length; if (!reader->ReadVarInt62(&retry_token_length)) { - *retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + *retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; *detailed_error = "Unable to read retry token length."; return QUIC_INVALID_PACKET_HEADER; }
diff --git a/quiche/quic/core/quic_framer.h b/quiche/quic/core/quic_framer.h index f60a109..c39ee2b 100644 --- a/quiche/quic/core/quic_framer.h +++ b/quiche/quic/core/quic_framer.h
@@ -425,9 +425,9 @@ QuicConnectionIdLength source_connection_id_length, bool includes_version, bool includes_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, uint64_t retry_token_length, - QuicVariableLengthIntegerLength length_length); + quiche::QuicheVariableLengthIntegerLength length_length); // Parses the unencrypted fields in a QUIC header using |reader| as input, // stores the result in the other parameters. @@ -440,7 +440,7 @@ QuicConnectionId* destination_connection_id, QuicConnectionId* source_connection_id, QuicLongHeaderType* long_packet_type, - QuicVariableLengthIntegerLength* retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength* retry_token_length_length, absl::string_view* retry_token, std::string* detailed_error); // Parses the unencrypted fields in |packet| and stores them in the other
diff --git a/quiche/quic/core/quic_framer_test.cc b/quiche/quic/core/quic_framer_test.cc index 9b022a2..08b53f8 100644 --- a/quiche/quic/core/quic_framer_test.cc +++ b/quiche/quic/core/quic_framer_test.cc
@@ -763,7 +763,8 @@ 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); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0); } bool CheckDecryption( @@ -771,9 +772,9 @@ bool includes_diversification_nonce, QuicConnectionIdLength destination_connection_id_length, QuicConnectionIdLength source_connection_id_length, - QuicVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, size_t retry_token_length, - QuicVariableLengthIntegerLength length_length) { + quiche::QuicheVariableLengthIntegerLength length_length) { if (visitor_.header_->packet_number != decrypter_->packet_number_) { QUIC_LOG(ERROR) << "Decrypted incorrect packet number. expected " << visitor_.header_->packet_number @@ -1081,7 +1082,8 @@ framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size, 0, kMaxIncomingPacketSize - header_size); @@ -1395,8 +1397,8 @@ QuicConnectionId destination_connection_id = EmptyQuicConnectionId(), source_connection_id = EmptyQuicConnectionId(); QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; - QuicVariableLengthIntegerLength retry_token_length_length = - VARIABLE_LENGTH_INTEGER_LENGTH_4; + quiche::QuicheVariableLengthIntegerLength retry_token_length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_4; absl::string_view retry_token; std::string detailed_error = "foobar"; @@ -1418,7 +1420,8 @@ EXPECT_EQ(framer_.version(), parsed_version); EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); - EXPECT_EQ(VARIABLE_LENGTH_INTEGER_LENGTH_0, retry_token_length_length); + EXPECT_EQ(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, + retry_token_length_length); EXPECT_EQ(absl::string_view(), retry_token); if (framer_.version().HasIetfInvariantHeader()) { EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); @@ -1464,8 +1467,8 @@ QuicConnectionId destination_connection_id = EmptyQuicConnectionId(), source_connection_id = EmptyQuicConnectionId(); QuicLongHeaderType long_packet_type = INVALID_PACKET_TYPE; - QuicVariableLengthIntegerLength retry_token_length_length = - VARIABLE_LENGTH_INTEGER_LENGTH_4; + quiche::QuicheVariableLengthIntegerLength retry_token_length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_4; absl::string_view retry_token; std::string detailed_error = "foobar"; @@ -1485,7 +1488,8 @@ EXPECT_EQ(UnsupportedQuicVersion(), parsed_version); EXPECT_EQ(FramerTestConnectionId(), destination_connection_id); EXPECT_EQ(EmptyQuicConnectionId(), source_connection_id); - EXPECT_EQ(VARIABLE_LENGTH_INTEGER_LENGTH_0, retry_token_length_length); + EXPECT_EQ(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, + retry_token_length_length); EXPECT_EQ(absl::string_view(), retry_token); EXPECT_EQ(IETF_QUIC_LONG_HEADER_PACKET, format); } @@ -2964,13 +2968,13 @@ }; // clang-format on - QuicVariableLengthIntegerLength retry_token_length_length = - VARIABLE_LENGTH_INTEGER_LENGTH_0; + quiche::QuicheVariableLengthIntegerLength retry_token_length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; size_t retry_token_length = 0; - QuicVariableLengthIntegerLength length_length = + quiche::QuicheVariableLengthIntegerLength length_length = QuicVersionHasLongHeaderLengths(framer_.transport_version()) - ? VARIABLE_LENGTH_INTEGER_LENGTH_1 - : VARIABLE_LENGTH_INTEGER_LENGTH_0; + ? quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1 + : quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; ReviseFirstByteByVersion(packet_ietf); PacketFragments& fragments = @@ -6551,7 +6555,8 @@ framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxOutgoingPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -6740,7 +6745,8 @@ framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxOutgoingPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -6815,7 +6821,8 @@ framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_2BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxOutgoingPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -6890,7 +6897,8 @@ framer_.transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_1BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0); memset(p + header_size + 1, 0x00, kMaxOutgoingPacketSize - header_size - 1); std::unique_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -6910,7 +6918,7 @@ header.version_flag = false; header.packet_number = kPacketNumber; if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) { - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, @@ -7009,7 +7017,7 @@ } header.packet_number = kPacketNumber; if (QuicVersionHasLongHeaderLengths(framer_.transport_version())) { - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, @@ -10422,11 +10430,12 @@ p = packet46; } - std::unique_ptr<QuicPacket> raw(new QuicPacket( - AsChars(p), p_size, false, PACKET_8BYTE_CONNECTION_ID, - PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)); + std::unique_ptr<QuicPacket> raw( + new QuicPacket(AsChars(p), p_size, false, PACKET_8BYTE_CONNECTION_ID, + PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0)); char buffer[kMaxOutgoingPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_INITIAL, packet_number, *raw, buffer, kMaxOutgoingPacketSize); @@ -10442,8 +10451,8 @@ PACKET_0BYTE_CONNECTION_ID, /*includes_version=*/true, /*includes_diversification_nonce=*/true, PACKET_1BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, - /*retry_token_length=*/0, VARIABLE_LENGTH_INTEGER_LENGTH_0); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, + /*retry_token_length=*/0, quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0); char buffer[kMaxOutgoingPacketSize]; size_t encrypted_length = 1; EXPECT_QUIC_BUG( @@ -10530,11 +10539,12 @@ p_size = ABSL_ARRAYSIZE(packet46); } - std::unique_ptr<QuicPacket> raw(new QuicPacket( - AsChars(p), p_size, false, PACKET_8BYTE_CONNECTION_ID, - PACKET_0BYTE_CONNECTION_ID, kIncludeVersion, - !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, VARIABLE_LENGTH_INTEGER_LENGTH_0)); + std::unique_ptr<QuicPacket> raw( + new QuicPacket(AsChars(p), p_size, false, PACKET_8BYTE_CONNECTION_ID, + PACKET_0BYTE_CONNECTION_ID, kIncludeVersion, + !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0)); char buffer[kMaxOutgoingPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_INITIAL, packet_number, *raw, buffer, kMaxOutgoingPacketSize); @@ -14741,8 +14751,8 @@ header.packet_number = kPacketNumber; header.packet_number_length = PACKET_4BYTE_PACKET_NUMBER; header.long_packet_type = INITIAL; - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; - header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; QuicFrames frames = {QuicFrame(QuicPingFrame()), QuicFrame(QuicPaddingFrame(3))};
diff --git a/quiche/quic/core/quic_packet_creator.cc b/quiche/quic/core/quic_packet_creator.cc index 6d39ae3..3be9c40 100644 --- a/quiche/quic/core/quic_packet_creator.cc +++ b/quiche/quic/core/quic_packet_creator.cc
@@ -384,8 +384,9 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, - QuicVariableLengthIntegerLength length_length, QuicStreamOffset offset) { + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength length_length, + QuicStreamOffset offset) { return GetPacketHeaderSize(version, destination_connection_id_length, source_connection_id_length, include_version, include_diversification_nonce, @@ -1243,14 +1244,14 @@ GetRetryTokenLengthLength(), GetRetryToken().length(), GetLengthLength()); } -QuicVariableLengthIntegerLength QuicPacketCreator::GetRetryTokenLengthLength() - const { +quiche::QuicheVariableLengthIntegerLength +QuicPacketCreator::GetRetryTokenLengthLength() const { if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) && HasIetfLongHeader() && EncryptionlevelToLongHeaderType(packet_.encryption_level) == INITIAL) { return QuicDataWriter::GetVarInt62Len(GetRetryToken().length()); } - return VARIABLE_LENGTH_INTEGER_LENGTH_0; + return quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; } absl::string_view QuicPacketCreator::GetRetryToken() const { @@ -1629,17 +1630,18 @@ return MESSAGE_STATUS_SUCCESS; } -QuicVariableLengthIntegerLength QuicPacketCreator::GetLengthLength() const { +quiche::QuicheVariableLengthIntegerLength QuicPacketCreator::GetLengthLength() + const { if (QuicVersionHasLongHeaderLengths(framer_->transport_version()) && HasIetfLongHeader()) { QuicLongHeaderType long_header_type = EncryptionlevelToLongHeaderType(packet_.encryption_level); if (long_header_type == INITIAL || long_header_type == ZERO_RTT_PROTECTED || long_header_type == HANDSHAKE) { - return VARIABLE_LENGTH_INTEGER_LENGTH_2; + return quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } } - return VARIABLE_LENGTH_INTEGER_LENGTH_0; + return quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; } void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { @@ -1979,7 +1981,7 @@ GetSourceConnectionIdLength(), IncludeVersionInHeader(), IncludeNonceInPublicHeader(), GetPacketNumberLength(), // No Retry token on packets containing application data. - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, GetLengthLength()); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, GetLengthLength()); // This is the largest possible message payload when the length field is // omitted. size_t max_plaintext_size = @@ -2003,13 +2005,13 @@ framer_->version().handshake_protocol == PROTOCOL_QUIC_CRYPTO && framer_->perspective() == Perspective::IS_SERVER; // IETF QUIC long headers include a length on client 0RTT packets. - QuicVariableLengthIntegerLength length_length = - VARIABLE_LENGTH_INTEGER_LENGTH_0; + quiche::QuicheVariableLengthIntegerLength length_length = + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; if (framer_->perspective() == Perspective::IS_CLIENT) { - length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } if (!QuicVersionHasLongHeaderLengths(framer_->transport_version())) { - length_length = VARIABLE_LENGTH_INTEGER_LENGTH_0; + length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0; } const size_t packet_header_size = GetPacketHeaderSize( framer_->transport_version(), GetDestinationConnectionIdLength(), @@ -2017,7 +2019,7 @@ GetSourceConnectionIdLength(), kIncludeVersion, may_include_nonce, PACKET_4BYTE_PACKET_NUMBER, // No Retry token on packets containing application data. - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, length_length); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0, length_length); // This is the largest possible message payload when the length field is // omitted. size_t max_plaintext_size =
diff --git a/quiche/quic/core/quic_packet_creator.h b/quiche/quic/core/quic_packet_creator.h index c2c7e2c..c6b41ad 100644 --- a/quiche/quic/core/quic_packet_creator.h +++ b/quiche/quic/core/quic_packet_creator.h
@@ -146,8 +146,9 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, - QuicVariableLengthIntegerLength length_length, QuicStreamOffset offset); + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength length_length, + QuicStreamOffset offset); // Returns false and flushes all pending frames if current open packet is // full. @@ -578,7 +579,7 @@ // 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; + quiche::QuicheVariableLengthIntegerLength GetRetryTokenLengthLength() const; // Returns the retry token to send over the wire, only sent in // v99 IETF Initial packets. @@ -586,7 +587,7 @@ // 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; + quiche::QuicheVariableLengthIntegerLength GetLengthLength() const; // Returns true if |frame| is a ClientHello. bool StreamFrameIsClientHello(const QuicStreamFrame& frame) const;
diff --git a/quiche/quic/core/quic_packets.cc b/quiche/quic/core/quic_packets.cc index 369a32a..f0b9ccd 100644 --- a/quiche/quic/core/quic_packets.cc +++ b/quiche/quic/core/quic_packets.cc
@@ -105,9 +105,9 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, QuicByteCount retry_token_length, - QuicVariableLengthIntegerLength length_length) { + quiche::QuicheVariableLengthIntegerLength length_length) { if (VersionHasIetfInvariantHeader(version)) { if (include_version) { // Long header. @@ -153,9 +153,9 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, QuicByteCount retry_token_length, - QuicVariableLengthIntegerLength length_length) { + quiche::QuicheVariableLengthIntegerLength length_length) { // Encryption starts before private flags. return GetPacketHeaderSize( version, destination_connection_id_length, source_connection_id_length, @@ -177,9 +177,9 @@ form(GOOGLE_QUIC_PACKET), long_packet_type(INITIAL), possible_stateless_reset_token({}), - retry_token_length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0), + retry_token_length_length(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0), retry_token(absl::string_view()), - length_length(VARIABLE_LENGTH_INTEGER_LENGTH_0), + length_length(quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0), remaining_packet_length(0) {} QuicPacketHeader::QuicPacketHeader(const QuicPacketHeader& other) = default; @@ -239,14 +239,15 @@ os << ", long_packet_type: " << QuicUtils::QuicLongHeaderTypetoString(header.long_packet_type); } - if (header.retry_token_length_length != VARIABLE_LENGTH_INTEGER_LENGTH_0) { + if (header.retry_token_length_length != + quiche::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) { + if (header.length_length != quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0) { os << ", length_length: " << static_cast<int>(header.length_length); } if (header.remaining_packet_length != 0) { @@ -285,9 +286,9 @@ QuicConnectionIdLength source_connection_id_length, bool includes_version, bool includes_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, QuicByteCount retry_token_length, - QuicVariableLengthIntegerLength length_length) + quiche::QuicheVariableLengthIntegerLength length_length) : QuicData(buffer, length, owns_buffer), buffer_(buffer), destination_connection_id_length_(destination_connection_id_length),
diff --git a/quiche/quic/core/quic_packets.h b/quiche/quic/core/quic_packets.h index d4f04c8..c0cc8af 100644 --- a/quiche/quic/core/quic_packets.h +++ b/quiche/quic/core/quic_packets.h
@@ -82,15 +82,15 @@ QUIC_EXPORT_PRIVATE size_t GetPacketHeaderSize(QuicTransportVersion version, const QuicPacketHeader& header); -QUIC_EXPORT_PRIVATE size_t -GetPacketHeaderSize(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); +QUIC_EXPORT_PRIVATE size_t GetPacketHeaderSize( + QuicTransportVersion version, + QuicConnectionIdLength destination_connection_id_length, + QuicConnectionIdLength source_connection_id_length, bool include_version, + bool include_diversification_nonce, + QuicPacketNumberLength packet_number_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + quiche::QuicheVariableLengthIntegerLength length_length); // Index of the first byte in a QUIC packet of encrypted data. QUIC_EXPORT_PRIVATE size_t GetStartOfEncryptedData( @@ -102,9 +102,9 @@ QuicConnectionIdLength source_connection_id_length, bool include_version, bool include_diversification_nonce, QuicPacketNumberLength packet_number_length, - QuicVariableLengthIntegerLength retry_token_length_length, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, QuicByteCount retry_token_length, - QuicVariableLengthIntegerLength length_length); + quiche::QuicheVariableLengthIntegerLength length_length); struct QUIC_EXPORT_PRIVATE QuicPacketHeader { QuicPacketHeader(); @@ -147,12 +147,12 @@ StatelessResetToken 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; + quiche::QuicheVariableLengthIntegerLength retry_token_length_length; // Retry token, carried only by v99 IETF Initial packets. absl::string_view retry_token; // Length of the length variable length integer field, // carried only by v99 IETF Initial, 0-RTT and Handshake packets. - QuicVariableLengthIntegerLength length_length; + quiche::QuicheVariableLengthIntegerLength 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. @@ -222,14 +222,15 @@ class QUIC_EXPORT_PRIVATE QuicPacket : public QuicData { public: - 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); + 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, + quiche::QuicheVariableLengthIntegerLength retry_token_length_length, + QuicByteCount retry_token_length, + quiche::QuicheVariableLengthIntegerLength length_length); QuicPacket(QuicTransportVersion version, char* buffer, size_t length, bool owns_buffer, const QuicPacketHeader& header); QuicPacket(const QuicPacket&) = delete; @@ -247,9 +248,9 @@ const bool includes_version_; const bool includes_diversification_nonce_; const QuicPacketNumberLength packet_number_length_; - const QuicVariableLengthIntegerLength retry_token_length_length_; + const quiche::QuicheVariableLengthIntegerLength retry_token_length_length_; const QuicByteCount retry_token_length_; - const QuicVariableLengthIntegerLength length_length_; + const quiche::QuicheVariableLengthIntegerLength length_length_; }; class QUIC_EXPORT_PRIVATE QuicEncryptedPacket : public QuicData {
diff --git a/quiche/quic/core/quic_stream_test.cc b/quiche/quic/core/quic_stream_test.cc index 51b25a5..1bec69f 100644 --- a/quiche/quic/core/quic_stream_test.cc +++ b/quiche/quic/core/quic_stream_test.cc
@@ -346,8 +346,8 @@ connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u); connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) @@ -431,8 +431,8 @@ connection_->transport_version(), PACKET_8BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludeDiversificationNonce, PACKET_4BYTE_PACKET_NUMBER, - VARIABLE_LENGTH_INTEGER_LENGTH_0, - VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u); + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, + quiche::VARIABLE_LENGTH_INTEGER_LENGTH_0, 0u); connection_->SetMaxPacketLength(length); EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
diff --git a/quiche/quic/core/quic_types.h b/quiche/quic/core/quic_types.h index b0992c8..ffaf6c6 100644 --- a/quiche/quic/core/quic_types.h +++ b/quiche/quic/core/quic_types.h
@@ -21,6 +21,7 @@ #include "quiche/quic/core/quic_time.h" #include "quiche/quic/platform/api/quic_export.h" #include "quiche/quic/platform/api/quic_flags.h" +#include "quiche/common/quiche_endian.h" namespace quic { @@ -353,20 +354,6 @@ #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. - kQuicDefaultLongHeaderLengthLength = VARIABLE_LENGTH_INTEGER_LENGTH_2, -}; - enum QuicPacketNumberLength : uint8_t { PACKET_1BYTE_PACKET_NUMBER = 1, PACKET_2BYTE_PACKET_NUMBER = 2,
diff --git a/quiche/quic/test_tools/quic_packet_creator_peer.cc b/quiche/quic/test_tools/quic_packet_creator_peer.cc index 507de25..2ab9fb0 100644 --- a/quiche/quic/test_tools/quic_packet_creator_peer.cc +++ b/quiche/quic/test_tools/quic_packet_creator_peer.cc
@@ -45,14 +45,14 @@ } // static -QuicVariableLengthIntegerLength +quiche::QuicheVariableLengthIntegerLength QuicPacketCreatorPeer::GetRetryTokenLengthLength(QuicPacketCreator* creator) { return creator->GetRetryTokenLengthLength(); } // static -QuicVariableLengthIntegerLength QuicPacketCreatorPeer::GetLengthLength( - QuicPacketCreator* creator) { +quiche::QuicheVariableLengthIntegerLength +QuicPacketCreatorPeer::GetLengthLength(QuicPacketCreator* creator) { return creator->GetLengthLength(); }
diff --git a/quiche/quic/test_tools/quic_packet_creator_peer.h b/quiche/quic/test_tools/quic_packet_creator_peer.h index 0c9ce77..4607bcd 100644 --- a/quiche/quic/test_tools/quic_packet_creator_peer.h +++ b/quiche/quic/test_tools/quic_packet_creator_peer.h
@@ -26,9 +26,9 @@ QuicPacketCreator* creator, QuicPacketNumberLength packet_number_length); static QuicPacketNumberLength GetPacketNumberLength( QuicPacketCreator* creator); - static QuicVariableLengthIntegerLength GetRetryTokenLengthLength( + static quiche::QuicheVariableLengthIntegerLength GetRetryTokenLengthLength( QuicPacketCreator* creator); - static QuicVariableLengthIntegerLength GetLengthLength( + static quiche::QuicheVariableLengthIntegerLength GetLengthLength( QuicPacketCreator* creator); static void SetPacketNumber(QuicPacketCreator* creator, uint64_t s); static void SetPacketNumber(QuicPacketCreator* creator, QuicPacketNumber num);
diff --git a/quiche/quic/test_tools/quic_test_utils.cc b/quiche/quic/test_tools/quic_test_utils.cc index cfb947a..03948b7 100644 --- a/quiche/quic/test_tools/quic_test_utils.cc +++ b/quiche/quic/test_tools/quic_test_utils.cc
@@ -908,8 +908,8 @@ ParsedQuicVersion version = (*versions)[0]; if (QuicVersionHasLongHeaderLengths(version.transport_version) && version_flag) { - header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicFrames frames; @@ -973,8 +973,8 @@ header.packet_number = QuicPacketNumber(33); header.long_packet_type = ZERO_RTT_PROTECTED; if (version.HasLongHeaderLengths()) { - header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicFrames frames; @@ -1027,8 +1027,8 @@ header.packet_number = QuicPacketNumber(packet_number); if (QuicVersionHasLongHeaderLengths(version.transport_version) && version_flag) { - header.retry_token_length_length = VARIABLE_LENGTH_INTEGER_LENGTH_1; - header.length_length = VARIABLE_LENGTH_INTEGER_LENGTH_2; + header.retry_token_length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_1; + header.length_length = quiche::VARIABLE_LENGTH_INTEGER_LENGTH_2; } QuicFrame frame(QuicStreamFrame(1, false, 0, absl::string_view(data))); QuicFrames frames;