QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 5 | #include "quic/core/quic_data_writer.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 6 | |
| 7 | #include <algorithm> |
| 8 | #include <limits> |
| 9 | |
vasilvv | c872ee4 | 2020-10-07 19:50:22 -0700 | [diff] [blame] | 10 | #include "absl/strings/string_view.h" |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 11 | #include "quic/core/crypto/quic_random.h" |
| 12 | #include "quic/core/quic_constants.h" |
| 13 | #include "quic/platform/api/quic_bug_tracker.h" |
| 14 | #include "quic/platform/api/quic_flags.h" |
QUICHE team | 5be974e | 2020-12-29 18:35:24 -0500 | [diff] [blame] | 15 | #include "common/quiche_endian.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 16 | |
| 17 | namespace quic { |
| 18 | |
| 19 | QuicDataWriter::QuicDataWriter(size_t size, char* buffer) |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 20 | : quiche::QuicheDataWriter(size, buffer) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 21 | |
QUICHE team | 173c48f | 2019-11-19 16:34:44 -0800 | [diff] [blame] | 22 | QuicDataWriter::QuicDataWriter(size_t size, |
| 23 | char* buffer, |
| 24 | quiche::Endianness endianness) |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 25 | : quiche::QuicheDataWriter(size, buffer, endianness) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 26 | |
| 27 | QuicDataWriter::~QuicDataWriter() {} |
| 28 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 29 | bool QuicDataWriter::WriteUFloat16(uint64_t value) { |
| 30 | uint16_t result; |
| 31 | if (value < (UINT64_C(1) << kUFloat16MantissaEffectiveBits)) { |
| 32 | // Fast path: either the value is denormalized, or has exponent zero. |
| 33 | // Both cases are represented by the value itself. |
| 34 | result = static_cast<uint16_t>(value); |
| 35 | } else if (value >= kUFloat16MaxValue) { |
| 36 | // Value is out of range; clamp it to the maximum representable. |
| 37 | result = std::numeric_limits<uint16_t>::max(); |
| 38 | } else { |
| 39 | // The highest bit is between position 13 and 42 (zero-based), which |
| 40 | // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10, |
| 41 | // hidden bit is 11 and exponent is 11 to 15. Shift the highest bit to 11 |
| 42 | // and count the shifts. |
| 43 | uint16_t exponent = 0; |
| 44 | for (uint16_t offset = 16; offset > 0; offset /= 2) { |
| 45 | // Right-shift the value until the highest bit is in position 11. |
| 46 | // For offset of 16, 8, 4, 2 and 1 (binary search over 1-30), |
| 47 | // shift if the bit is at or above 11 + offset. |
| 48 | if (value >= (UINT64_C(1) << (kUFloat16MantissaBits + offset))) { |
| 49 | exponent += offset; |
| 50 | value >>= offset; |
| 51 | } |
| 52 | } |
| 53 | |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 54 | QUICHE_DCHECK_GE(exponent, 1); |
| 55 | QUICHE_DCHECK_LE(exponent, kUFloat16MaxExponent); |
| 56 | QUICHE_DCHECK_GE(value, UINT64_C(1) << kUFloat16MantissaBits); |
| 57 | QUICHE_DCHECK_LT(value, UINT64_C(1) << kUFloat16MantissaEffectiveBits); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 58 | |
| 59 | // Hidden bit (position 11) is set. We should remove it and increment the |
| 60 | // exponent. Equivalently, we just add it to the exponent. |
| 61 | // This hides the bit. |
| 62 | result = static_cast<uint16_t>(value + (exponent << kUFloat16MantissaBits)); |
| 63 | } |
| 64 | |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 65 | if (endianness() == quiche::NETWORK_BYTE_ORDER) { |
QUICHE team | 173c48f | 2019-11-19 16:34:44 -0800 | [diff] [blame] | 66 | result = quiche::QuicheEndian::HostToNet16(result); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 67 | } |
| 68 | return WriteBytes(&result, sizeof(result)); |
| 69 | } |
| 70 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 71 | bool QuicDataWriter::WriteConnectionId(QuicConnectionId connection_id) { |
| 72 | if (connection_id.IsEmpty()) { |
| 73 | return true; |
| 74 | } |
| 75 | return WriteBytes(connection_id.data(), connection_id.length()); |
| 76 | } |
| 77 | |
dschinazi | cf5b1e2 | 2019-07-17 18:35:17 -0700 | [diff] [blame] | 78 | bool QuicDataWriter::WriteLengthPrefixedConnectionId( |
| 79 | QuicConnectionId connection_id) { |
| 80 | return WriteUInt8(connection_id.length()) && WriteConnectionId(connection_id); |
| 81 | } |
| 82 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 83 | bool QuicDataWriter::WriteRandomBytes(QuicRandom* random, size_t length) { |
| 84 | char* dest = BeginWrite(length); |
| 85 | if (!dest) { |
| 86 | return false; |
| 87 | } |
| 88 | |
| 89 | random->RandBytes(dest, length); |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 90 | IncreaseLength(length); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 91 | return true; |
| 92 | } |
| 93 | |
dschinazi | 9a5d7c0 | 2021-02-22 13:05:47 -0800 | [diff] [blame] | 94 | bool QuicDataWriter::WriteInsecureRandomBytes(QuicRandom* random, |
| 95 | size_t length) { |
| 96 | char* dest = BeginWrite(length); |
| 97 | if (!dest) { |
| 98 | return false; |
| 99 | } |
| 100 | |
| 101 | random->InsecureRandBytes(dest, length); |
| 102 | IncreaseLength(length); |
| 103 | return true; |
| 104 | } |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 105 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 106 | // Converts a uint64_t into an IETF/Quic formatted Variable Length |
| 107 | // Integer. IETF Variable Length Integers have 62 significant bits, so |
| 108 | // the value to write must be in the range of 0..(2^62)-1. |
| 109 | // |
| 110 | // Performance notes |
| 111 | // |
| 112 | // Measurements and experiments showed that unrolling the four cases |
| 113 | // like this and dereferencing next_ as we do (*(next_+n)) gains about |
| 114 | // 10% over making a loop and dereferencing it as *(next_++) |
| 115 | // |
| 116 | // Using a register for next didn't help. |
| 117 | // |
| 118 | // Branches are ordered to increase the likelihood of the first being |
| 119 | // taken. |
| 120 | // |
| 121 | // Low-level optimization is useful here because this function will be |
| 122 | // called frequently, leading to outsize benefits. |
| 123 | bool QuicDataWriter::WriteVarInt62(uint64_t value) { |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 124 | QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 125 | |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 126 | size_t remaining_bytes = remaining(); |
| 127 | char* next = buffer() + length(); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 128 | |
| 129 | if ((value & kVarInt62ErrorMask) == 0) { |
| 130 | // We know the high 2 bits are 0 so |value| is legal. |
| 131 | // We can do the encoding. |
| 132 | if ((value & kVarInt62Mask8Bytes) != 0) { |
| 133 | // Someplace in the high-4 bytes is a 1-bit. Do an 8-byte |
| 134 | // encoding. |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 135 | if (remaining_bytes >= 8) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 136 | *(next + 0) = ((value >> 56) & 0x3f) + 0xc0; |
| 137 | *(next + 1) = (value >> 48) & 0xff; |
| 138 | *(next + 2) = (value >> 40) & 0xff; |
| 139 | *(next + 3) = (value >> 32) & 0xff; |
| 140 | *(next + 4) = (value >> 24) & 0xff; |
| 141 | *(next + 5) = (value >> 16) & 0xff; |
| 142 | *(next + 6) = (value >> 8) & 0xff; |
| 143 | *(next + 7) = value & 0xff; |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 144 | IncreaseLength(8); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 145 | return true; |
| 146 | } |
| 147 | return false; |
| 148 | } |
| 149 | // The high-order-4 bytes are all 0, check for a 1, 2, or 4-byte |
| 150 | // encoding |
| 151 | if ((value & kVarInt62Mask4Bytes) != 0) { |
| 152 | // The encoding will not fit into 2 bytes, Do a 4-byte |
| 153 | // encoding. |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 154 | if (remaining_bytes >= 4) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 155 | *(next + 0) = ((value >> 24) & 0x3f) + 0x80; |
| 156 | *(next + 1) = (value >> 16) & 0xff; |
| 157 | *(next + 2) = (value >> 8) & 0xff; |
| 158 | *(next + 3) = value & 0xff; |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 159 | IncreaseLength(4); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 160 | return true; |
| 161 | } |
| 162 | return false; |
| 163 | } |
| 164 | // The high-order bits are all 0. Check to see if the number |
| 165 | // can be encoded as one or two bytes. One byte encoding has |
| 166 | // only 6 significant bits (bits 0xffffffff ffffffc0 are all 0). |
| 167 | // Two byte encoding has more than 6, but 14 or less significant |
| 168 | // bits (bits 0xffffffff ffffc000 are 0 and 0x00000000 00003fc0 |
| 169 | // are not 0) |
| 170 | if ((value & kVarInt62Mask2Bytes) != 0) { |
| 171 | // Do 2-byte encoding |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 172 | if (remaining_bytes >= 2) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 173 | *(next + 0) = ((value >> 8) & 0x3f) + 0x40; |
| 174 | *(next + 1) = (value)&0xff; |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 175 | IncreaseLength(2); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 176 | return true; |
| 177 | } |
| 178 | return false; |
| 179 | } |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 180 | if (remaining_bytes >= 1) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 181 | // Do 1-byte encoding |
| 182 | *next = (value & 0x3f); |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 183 | IncreaseLength(1); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 184 | return true; |
| 185 | } |
| 186 | return false; |
| 187 | } |
| 188 | // Can not encode, high 2 bits not 0 |
| 189 | return false; |
| 190 | } |
| 191 | |
| 192 | bool QuicDataWriter::WriteVarInt62( |
| 193 | uint64_t value, |
| 194 | QuicVariableLengthIntegerLength write_length) { |
vasilvv | f803516 | 2021-02-01 14:49:14 -0800 | [diff] [blame] | 195 | QUICHE_DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 196 | |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 197 | size_t remaining_bytes = remaining(); |
| 198 | if (remaining_bytes < write_length) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 199 | return false; |
| 200 | } |
| 201 | |
| 202 | const QuicVariableLengthIntegerLength min_length = GetVarInt62Len(value); |
| 203 | if (write_length < min_length) { |
QUICHE team | 60aff82 | 2021-03-16 15:21:02 -0700 | [diff] [blame] | 204 | QUIC_BUG(quic_bug_10347_1) << "Cannot write value " << value |
| 205 | << " with write_length " << write_length; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 206 | return false; |
| 207 | } |
| 208 | if (write_length == min_length) { |
| 209 | return WriteVarInt62(value); |
| 210 | } |
| 211 | |
| 212 | if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_2) { |
| 213 | return WriteUInt8(0b01000000) && WriteUInt8(value); |
| 214 | } |
| 215 | if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_4) { |
| 216 | return WriteUInt8(0b10000000) && WriteUInt8(0) && WriteUInt16(value); |
| 217 | } |
| 218 | if (write_length == VARIABLE_LENGTH_INTEGER_LENGTH_8) { |
| 219 | return WriteUInt8(0b11000000) && WriteUInt8(0) && WriteUInt16(0) && |
| 220 | WriteUInt32(value); |
| 221 | } |
| 222 | |
QUICHE team | 60aff82 | 2021-03-16 15:21:02 -0700 | [diff] [blame] | 223 | QUIC_BUG(quic_bug_10347_2) |
QUICHE team | b89112a | 2021-03-09 16:02:46 -0800 | [diff] [blame] | 224 | << "Invalid write_length " << static_cast<int>(write_length); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 225 | return false; |
| 226 | } |
| 227 | |
| 228 | // static |
| 229 | QuicVariableLengthIntegerLength QuicDataWriter::GetVarInt62Len(uint64_t value) { |
| 230 | if ((value & kVarInt62ErrorMask) != 0) { |
QUICHE team | 60aff82 | 2021-03-16 15:21:02 -0700 | [diff] [blame] | 231 | QUIC_BUG(quic_bug_10347_3) << "Attempted to encode a value, " << value |
| 232 | << ", that is too big for VarInt62"; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 233 | return VARIABLE_LENGTH_INTEGER_LENGTH_0; |
| 234 | } |
| 235 | if ((value & kVarInt62Mask8Bytes) != 0) { |
| 236 | return VARIABLE_LENGTH_INTEGER_LENGTH_8; |
| 237 | } |
| 238 | if ((value & kVarInt62Mask4Bytes) != 0) { |
| 239 | return VARIABLE_LENGTH_INTEGER_LENGTH_4; |
| 240 | } |
| 241 | if ((value & kVarInt62Mask2Bytes) != 0) { |
| 242 | return VARIABLE_LENGTH_INTEGER_LENGTH_2; |
| 243 | } |
| 244 | return VARIABLE_LENGTH_INTEGER_LENGTH_1; |
| 245 | } |
| 246 | |
| 247 | bool QuicDataWriter::WriteStringPieceVarInt62( |
vasilvv | c872ee4 | 2020-10-07 19:50:22 -0700 | [diff] [blame] | 248 | const absl::string_view& string_piece) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 249 | if (!WriteVarInt62(string_piece.size())) { |
| 250 | return false; |
| 251 | } |
| 252 | if (!string_piece.empty()) { |
| 253 | if (!WriteBytes(string_piece.data(), string_piece.size())) { |
| 254 | return false; |
| 255 | } |
| 256 | } |
| 257 | return true; |
| 258 | } |
| 259 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 260 | } // namespace quic |