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 | |
| 5 | #include "net/third_party/quiche/src/quic/core/quic_data_reader.h" |
| 6 | |
| 7 | #include "net/third_party/quiche/src/quic/core/quic_packets.h" |
| 8 | #include "net/third_party/quiche/src/quic/core/quic_utils.h" |
| 9 | #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" |
| 10 | #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" |
QUICHE team | 173c48f | 2019-11-19 16:34:44 -0800 | [diff] [blame] | 11 | #include "net/third_party/quiche/src/common/platform/api/quiche_endian.h" |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 12 | #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h" |
| 13 | #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 14 | |
| 15 | namespace quic { |
| 16 | |
dmcardle | cf0bfcf | 2019-12-13 08:08:21 -0800 | [diff] [blame] | 17 | QuicDataReader::QuicDataReader(quiche::QuicheStringPiece data) |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 18 | : quiche::QuicheDataReader(data) {} |
nharper | 55fa613 | 2019-05-07 19:37:21 -0700 | [diff] [blame] | 19 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 20 | QuicDataReader::QuicDataReader(const char* data, const size_t len) |
QUICHE team | 173c48f | 2019-11-19 16:34:44 -0800 | [diff] [blame] | 21 | : QuicDataReader(data, len, quiche::NETWORK_BYTE_ORDER) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 22 | |
| 23 | QuicDataReader::QuicDataReader(const char* data, |
| 24 | const size_t len, |
QUICHE team | 173c48f | 2019-11-19 16:34:44 -0800 | [diff] [blame] | 25 | quiche::Endianness endianness) |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 26 | : quiche::QuicheDataReader(data, len, endianness) {} |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 27 | |
| 28 | bool QuicDataReader::ReadUFloat16(uint64_t* result) { |
| 29 | uint16_t value; |
| 30 | if (!ReadUInt16(&value)) { |
| 31 | return false; |
| 32 | } |
| 33 | |
| 34 | *result = value; |
| 35 | if (*result < (1 << kUFloat16MantissaEffectiveBits)) { |
| 36 | // Fast path: either the value is denormalized (no hidden bit), or |
| 37 | // normalized (hidden bit set, exponent offset by one) with exponent zero. |
| 38 | // Zero exponent offset by one sets the bit exactly where the hidden bit is. |
| 39 | // So in both cases the value encodes itself. |
| 40 | return true; |
| 41 | } |
| 42 | |
| 43 | uint16_t exponent = |
| 44 | value >> kUFloat16MantissaBits; // No sign extend on uint! |
| 45 | // After the fast pass, the exponent is at least one (offset by one). |
| 46 | // Un-offset the exponent. |
| 47 | --exponent; |
| 48 | DCHECK_GE(exponent, 1); |
| 49 | DCHECK_LE(exponent, kUFloat16MaxExponent); |
| 50 | // Here we need to clear the exponent and set the hidden bit. We have already |
| 51 | // decremented the exponent, so when we subtract it, it leaves behind the |
| 52 | // hidden bit. |
| 53 | *result -= exponent << kUFloat16MantissaBits; |
| 54 | *result <<= exponent; |
| 55 | DCHECK_GE(*result, |
| 56 | static_cast<uint64_t>(1 << kUFloat16MantissaEffectiveBits)); |
| 57 | DCHECK_LE(*result, kUFloat16MaxValue); |
| 58 | return true; |
| 59 | } |
| 60 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 61 | bool QuicDataReader::ReadConnectionId(QuicConnectionId* connection_id, |
| 62 | uint8_t length) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 63 | if (length == 0) { |
| 64 | connection_id->set_length(0); |
| 65 | return true; |
| 66 | } |
| 67 | |
dschinazi | b324116 | 2019-06-10 17:59:37 -0700 | [diff] [blame] | 68 | if (BytesRemaining() < length) { |
| 69 | return false; |
| 70 | } |
| 71 | |
| 72 | connection_id->set_length(length); |
dschinazi | b953d02 | 2019-08-01 18:05:58 -0700 | [diff] [blame] | 73 | const bool ok = |
| 74 | ReadBytes(connection_id->mutable_data(), connection_id->length()); |
dschinazi | b324116 | 2019-06-10 17:59:37 -0700 | [diff] [blame] | 75 | DCHECK(ok); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 76 | return ok; |
| 77 | } |
| 78 | |
dschinazi | cf5b1e2 | 2019-07-17 18:35:17 -0700 | [diff] [blame] | 79 | bool QuicDataReader::ReadLengthPrefixedConnectionId( |
| 80 | QuicConnectionId* connection_id) { |
| 81 | uint8_t connection_id_length; |
| 82 | if (!ReadUInt8(&connection_id_length)) { |
| 83 | return false; |
| 84 | } |
dschinazi | cf5b1e2 | 2019-07-17 18:35:17 -0700 | [diff] [blame] | 85 | return ReadConnectionId(connection_id, connection_id_length); |
| 86 | } |
| 87 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 88 | QuicVariableLengthIntegerLength QuicDataReader::PeekVarInt62Length() { |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 89 | DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 90 | const unsigned char* next = |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 91 | reinterpret_cast<const unsigned char*>(data() + pos()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 92 | if (BytesRemaining() == 0) { |
| 93 | return VARIABLE_LENGTH_INTEGER_LENGTH_0; |
| 94 | } |
| 95 | return static_cast<QuicVariableLengthIntegerLength>( |
| 96 | 1 << ((*next & 0b11000000) >> 6)); |
| 97 | } |
| 98 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 99 | // Read an IETF/QUIC formatted 62-bit Variable Length Integer. |
| 100 | // |
| 101 | // Performance notes |
| 102 | // |
| 103 | // Measurements and experiments showed that unrolling the four cases |
| 104 | // like this and dereferencing next_ as we do (*(next_+n) --- and then |
| 105 | // doing a single pos_+=x at the end) gains about 10% over making a |
| 106 | // loop and dereferencing next_ such as *(next_++) |
| 107 | // |
| 108 | // Using a register for pos_ was not helpful. |
| 109 | // |
| 110 | // Branches are ordered to increase the likelihood of the first being |
| 111 | // taken. |
| 112 | // |
| 113 | // Low-level optimization is useful here because this function will be |
| 114 | // called frequently, leading to outsize benefits. |
| 115 | bool QuicDataReader::ReadVarInt62(uint64_t* result) { |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 116 | DCHECK_EQ(endianness(), quiche::NETWORK_BYTE_ORDER); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 117 | |
| 118 | size_t remaining = BytesRemaining(); |
| 119 | const unsigned char* next = |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 120 | reinterpret_cast<const unsigned char*>(data() + pos()); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 121 | if (remaining != 0) { |
| 122 | switch (*next & 0xc0) { |
| 123 | case 0xc0: |
| 124 | // Leading 0b11...... is 8 byte encoding |
| 125 | if (remaining >= 8) { |
| 126 | *result = (static_cast<uint64_t>((*(next)) & 0x3f) << 56) + |
| 127 | (static_cast<uint64_t>(*(next + 1)) << 48) + |
| 128 | (static_cast<uint64_t>(*(next + 2)) << 40) + |
| 129 | (static_cast<uint64_t>(*(next + 3)) << 32) + |
| 130 | (static_cast<uint64_t>(*(next + 4)) << 24) + |
| 131 | (static_cast<uint64_t>(*(next + 5)) << 16) + |
| 132 | (static_cast<uint64_t>(*(next + 6)) << 8) + |
| 133 | (static_cast<uint64_t>(*(next + 7)) << 0); |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 134 | AdvancePos(8); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 135 | return true; |
| 136 | } |
| 137 | return false; |
| 138 | |
| 139 | case 0x80: |
| 140 | // Leading 0b10...... is 4 byte encoding |
| 141 | if (remaining >= 4) { |
| 142 | *result = (((*(next)) & 0x3f) << 24) + (((*(next + 1)) << 16)) + |
| 143 | (((*(next + 2)) << 8)) + (((*(next + 3)) << 0)); |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 144 | AdvancePos(4); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 145 | return true; |
| 146 | } |
| 147 | return false; |
| 148 | |
| 149 | case 0x40: |
| 150 | // Leading 0b01...... is 2 byte encoding |
| 151 | if (remaining >= 2) { |
| 152 | *result = (((*(next)) & 0x3f) << 8) + (*(next + 1)); |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 153 | AdvancePos(2); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 154 | return true; |
| 155 | } |
| 156 | return false; |
| 157 | |
| 158 | case 0x00: |
| 159 | // Leading 0b00...... is 1 byte encoding |
| 160 | *result = (*next) & 0x3f; |
dmcardle | 2b64f50 | 2020-01-07 15:22:36 -0800 | [diff] [blame] | 161 | AdvancePos(1); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 162 | return true; |
| 163 | } |
| 164 | } |
| 165 | return false; |
| 166 | } |
| 167 | |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 168 | bool QuicDataReader::ReadVarIntU32(uint32_t* result) { |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 169 | uint64_t temp_uint64; |
| 170 | // TODO(fkastenholz): We should disambiguate read-errors from |
| 171 | // value errors. |
| 172 | if (!this->ReadVarInt62(&temp_uint64)) { |
| 173 | return false; |
| 174 | } |
| 175 | if (temp_uint64 > kMaxQuicStreamId) { |
| 176 | return false; |
| 177 | } |
fkastenholz | 3c4eabf | 2019-04-22 07:49:59 -0700 | [diff] [blame] | 178 | *result = static_cast<uint32_t>(temp_uint64); |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 179 | return true; |
| 180 | } |
| 181 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 182 | #undef ENDPOINT // undef for jumbo builds |
| 183 | } // namespace quic |