blob: e2871d760bae78a722686dd8783ffafbaf57c648 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/third_party/quiche/src/quic/core/quic_data_reader.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
namespace quic {
QuicDataReader::QuicDataReader(QuicStringPiece data)
: QuicDataReader(data.data(), data.length(), NETWORK_BYTE_ORDER) {}
QuicDataReader::QuicDataReader(const char* data, const size_t len)
: QuicDataReader(data, len, NETWORK_BYTE_ORDER) {}
QuicDataReader::QuicDataReader(const char* data,
const size_t len,
Endianness endianness)
: data_(data), len_(len), pos_(0), endianness_(endianness) {}
bool QuicDataReader::ReadUInt8(uint8_t* result) {
return ReadBytes(result, sizeof(*result));
}
bool QuicDataReader::ReadUInt16(uint16_t* result) {
if (!ReadBytes(result, sizeof(*result))) {
return false;
}
if (endianness_ == NETWORK_BYTE_ORDER) {
*result = QuicEndian::NetToHost16(*result);
}
return true;
}
bool QuicDataReader::ReadUInt32(uint32_t* result) {
if (!ReadBytes(result, sizeof(*result))) {
return false;
}
if (endianness_ == NETWORK_BYTE_ORDER) {
*result = QuicEndian::NetToHost32(*result);
}
return true;
}
bool QuicDataReader::ReadUInt64(uint64_t* result) {
if (!ReadBytes(result, sizeof(*result))) {
return false;
}
if (endianness_ == NETWORK_BYTE_ORDER) {
*result = QuicEndian::NetToHost64(*result);
}
return true;
}
bool QuicDataReader::ReadBytesToUInt64(size_t num_bytes, uint64_t* result) {
*result = 0u;
if (num_bytes > sizeof(*result)) {
return false;
}
if (endianness_ == HOST_BYTE_ORDER) {
return ReadBytes(result, num_bytes);
}
if (!ReadBytes(reinterpret_cast<char*>(result) + sizeof(*result) - num_bytes,
num_bytes)) {
return false;
}
*result = QuicEndian::NetToHost64(*result);
return true;
}
bool QuicDataReader::ReadUFloat16(uint64_t* result) {
uint16_t value;
if (!ReadUInt16(&value)) {
return false;
}
*result = value;
if (*result < (1 << kUFloat16MantissaEffectiveBits)) {
// Fast path: either the value is denormalized (no hidden bit), or
// normalized (hidden bit set, exponent offset by one) with exponent zero.
// Zero exponent offset by one sets the bit exactly where the hidden bit is.
// So in both cases the value encodes itself.
return true;
}
uint16_t exponent =
value >> kUFloat16MantissaBits; // No sign extend on uint!
// After the fast pass, the exponent is at least one (offset by one).
// Un-offset the exponent.
--exponent;
DCHECK_GE(exponent, 1);
DCHECK_LE(exponent, kUFloat16MaxExponent);
// Here we need to clear the exponent and set the hidden bit. We have already
// decremented the exponent, so when we subtract it, it leaves behind the
// hidden bit.
*result -= exponent << kUFloat16MantissaBits;
*result <<= exponent;
DCHECK_GE(*result,
static_cast<uint64_t>(1 << kUFloat16MantissaEffectiveBits));
DCHECK_LE(*result, kUFloat16MaxValue);
return true;
}
bool QuicDataReader::ReadStringPiece16(QuicStringPiece* result) {
// Read resultant length.
uint16_t result_len;
if (!ReadUInt16(&result_len)) {
// OnFailure() already called.
return false;
}
return ReadStringPiece(result, result_len);
}
bool QuicDataReader::ReadStringPiece(QuicStringPiece* result, size_t size) {
// Make sure that we have enough data to read.
if (!CanRead(size)) {
OnFailure();
return false;
}
// Set result.
*result = QuicStringPiece(data_ + pos_, size);
// Iterate.
pos_ += size;
return true;
}
bool QuicDataReader::ReadConnectionId(QuicConnectionId* connection_id,
uint8_t length) {
if (length > kQuicMaxConnectionIdLength) {
QUIC_BUG << "Attempted to read connection ID with length too high "
<< static_cast<int>(length);
return false;
}
if (length == 0) {
connection_id->set_length(0);
return true;
}
if (!GetQuicRestartFlag(quic_use_allocated_connection_ids)) {
const bool ok = ReadBytes(connection_id->mutable_data(), length);
if (ok) {
connection_id->set_length(length);
}
return ok;
}
QUIC_RESTART_FLAG_COUNT_N(quic_use_allocated_connection_ids, 6, 6);
if (BytesRemaining() < length) {
return false;
}
connection_id->set_length(length);
const bool ok = ReadBytes(connection_id->mutable_data(), length);
DCHECK(ok);
return ok;
}
bool QuicDataReader::ReadLengthPrefixedConnectionId(
QuicConnectionId* connection_id) {
uint8_t connection_id_length;
if (!ReadUInt8(&connection_id_length)) {
return false;
}
if (connection_id_length > kQuicMaxConnectionIdLength) {
return false;
}
return ReadConnectionId(connection_id, connection_id_length);
}
bool QuicDataReader::ReadTag(uint32_t* tag) {
return ReadBytes(tag, sizeof(*tag));
}
QuicStringPiece QuicDataReader::ReadRemainingPayload() {
QuicStringPiece payload = PeekRemainingPayload();
pos_ = len_;
return payload;
}
QuicStringPiece QuicDataReader::PeekRemainingPayload() const {
return QuicStringPiece(data_ + pos_, len_ - pos_);
}
bool QuicDataReader::ReadBytes(void* result, size_t size) {
// Make sure that we have enough data to read.
if (!CanRead(size)) {
OnFailure();
return false;
}
// Read into result.
memcpy(result, data_ + pos_, size);
// Iterate.
pos_ += size;
return true;
}
bool QuicDataReader::Seek(size_t size) {
if (!CanRead(size)) {
OnFailure();
return false;
}
pos_ += size;
return true;
}
bool QuicDataReader::IsDoneReading() const {
return len_ == pos_;
}
QuicVariableLengthIntegerLength QuicDataReader::PeekVarInt62Length() {
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<QuicVariableLengthIntegerLength>(
1 << ((*next & 0b11000000) >> 6));
}
size_t QuicDataReader::BytesRemaining() const {
return len_ - pos_;
}
bool QuicDataReader::TruncateRemaining(size_t truncation_length) {
if (truncation_length > BytesRemaining()) {
return false;
}
len_ = pos_ + truncation_length;
return true;
}
bool QuicDataReader::CanRead(size_t bytes) const {
return bytes <= (len_ - pos_);
}
void QuicDataReader::OnFailure() {
// Set our iterator to the end of the buffer so that further reads fail
// immediately.
pos_ = len_;
}
uint8_t QuicDataReader::PeekByte() const {
if (pos_ >= len_) {
QUIC_BUG << "Reading is done, cannot peek next byte. Tried to read pos = "
<< pos_ << " buffer length = " << len_;
return 0;
}
return data_[pos_];
}
// 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) {
DCHECK_EQ(endianness_, 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);
pos_ += 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));
pos_ += 4;
return true;
}
return false;
case 0x40:
// Leading 0b01...... is 2 byte encoding
if (remaining >= 2) {
*result = (((*(next)) & 0x3f) << 8) + (*(next + 1));
pos_ += 2;
return true;
}
return false;
case 0x00:
// Leading 0b00...... is 1 byte encoding
*result = (*next) & 0x3f;
pos_++;
return true;
}
}
return false;
}
bool QuicDataReader::ReadVarIntU32(uint32_t* result) {
uint64_t temp_uint64;
// TODO(fkastenholz): We should disambiguate read-errors from
// value errors.
if (!this->ReadVarInt62(&temp_uint64)) {
return false;
}
if (temp_uint64 > kMaxQuicStreamId) {
return false;
}
*result = static_cast<uint32_t>(temp_uint64);
return true;
}
std::string QuicDataReader::DebugString() const {
return QuicStrCat(" { length: ", len_, ", position: ", pos_, " }");
}
#undef ENDPOINT // undef for jumbo builds
} // namespace quic