blob: 2c3978128577730b8ff27f0393a0f030c8feacf4 [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 <cstddef>
#include <cstdint>
#include <initializer_list>
#include <optional>
#include <string>
#include <type_traits>
#include "absl/numeric/bits.h"
#include "absl/numeric/int128.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "quiche/quic/core/crypto/quic_random.h"
#include "quiche/quic/core/frames/quic_frame.h"
#include "quiche/quic/core/quic_connection_id.h"
#include "quiche/quic/core/quic_error_codes.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/quic_versions.h"
#include "quiche/quic/platform/api/quic_export.h"
#include "quiche/quic/platform/api/quic_socket_address.h"
#include "quiche/common/platform/api/quiche_mem_slice.h"
namespace quic {
class QUICHE_EXPORT QuicUtils {
QuicUtils() = delete;
// Returns the 64 bit FNV1a hash of the data. See
static uint64_t FNV1a_64_Hash(absl::string_view data);
// Returns the 128 bit FNV1a hash of the data. See
static absl::uint128 FNV1a_128_Hash(absl::string_view data);
// Returns the 128 bit FNV1a hash of the two sequences of data. See
static absl::uint128 FNV1a_128_Hash_Two(absl::string_view data1,
absl::string_view data2);
// Returns the 128 bit FNV1a hash of the three sequences of data. See
static absl::uint128 FNV1a_128_Hash_Three(absl::string_view data1,
absl::string_view data2,
absl::string_view data3);
// SerializeUint128 writes the first 96 bits of |v| in little-endian form
// to |out|.
static void SerializeUint128Short(absl::uint128 v, uint8_t* out);
// Returns AddressChangeType as a string.
static std::string AddressChangeTypeToString(AddressChangeType type);
// Returns SentPacketState as a char*.
static const char* SentPacketStateToString(SentPacketState state);
// Returns QuicLongHeaderType as a char*.
static const char* QuicLongHeaderTypetoString(QuicLongHeaderType type);
// Returns AckResult as a char*.
static const char* AckResultToString(AckResult result);
// Determines and returns change type of address change from |old_address| to
// |new_address|.
static AddressChangeType DetermineAddressChangeType(
const QuicSocketAddress& old_address,
const QuicSocketAddress& new_address);
// Returns the opposite Perspective of the |perspective| passed in.
static constexpr Perspective InvertPerspective(Perspective perspective) {
return perspective == Perspective::IS_CLIENT ? Perspective::IS_SERVER
: Perspective::IS_CLIENT;
// Returns true if a packet is ackable. A packet is unackable if it can never
// be acked. Occurs when a packet is never sent, after it is acknowledged
// once, or if it's a crypto packet we never expect to receive an ack for.
static bool IsAckable(SentPacketState state);
// Returns true if frame with |type| is retransmittable. A retransmittable
// frame should be retransmitted if it is detected as lost.
static bool IsRetransmittableFrame(QuicFrameType type);
// Returns true if |frame| is a handshake frame in version |version|.
static bool IsHandshakeFrame(const QuicFrame& frame,
QuicTransportVersion transport_version);
// Return true if any frame in |frames| is of |type|.
static bool ContainsFrameType(const QuicFrames& frames, QuicFrameType type);
// Returns packet state corresponding to |retransmission_type|.
static SentPacketState RetransmissionTypeToPacketState(
TransmissionType retransmission_type);
// Returns true if header with |first_byte| is considered as an IETF QUIC
// packet header. This only works on the server.
static bool IsIetfPacketHeader(uint8_t first_byte);
// Returns true if header with |first_byte| is considered as an IETF QUIC
// short packet header.
static bool IsIetfPacketShortHeader(uint8_t first_byte);
// Returns ID to denote an invalid stream of |version|.
static QuicStreamId GetInvalidStreamId(QuicTransportVersion version);
// Returns crypto stream ID of |version|.
static QuicStreamId GetCryptoStreamId(QuicTransportVersion version);
// Returns whether |id| is the stream ID for the crypto stream. If |version|
// is a version where crypto data doesn't go over stream frames, this function
// will always return false.
static bool IsCryptoStreamId(QuicTransportVersion version, QuicStreamId id);
// Returns headers stream ID of |version|.
static QuicStreamId GetHeadersStreamId(QuicTransportVersion version);
// Returns true if |id| is considered as client initiated stream ID.
static bool IsClientInitiatedStreamId(QuicTransportVersion version,
QuicStreamId id);
// Returns true if |id| is considered as server initiated stream ID.
static bool IsServerInitiatedStreamId(QuicTransportVersion version,
QuicStreamId id);
// Returns true if the stream ID represents a stream initiated by the
// provided perspective.
static bool IsOutgoingStreamId(ParsedQuicVersion version, QuicStreamId id,
Perspective perspective);
// Returns true if |id| is considered as bidirectional stream ID. Only used in
// v99.
static bool IsBidirectionalStreamId(QuicStreamId id,
ParsedQuicVersion version);
// Returns stream type. Either |perspective| or |peer_initiated| would be
// enough together with |id|. This method enforces that the three parameters
// are consistent. Only used in v99.
static StreamType GetStreamType(QuicStreamId id, Perspective perspective,
bool peer_initiated,
ParsedQuicVersion version);
// Returns the delta between consecutive stream IDs of the same type.
static QuicStreamId StreamIdDelta(QuicTransportVersion version);
// Returns the first initiated bidirectional stream ID of |perspective|.
static QuicStreamId GetFirstBidirectionalStreamId(
QuicTransportVersion version, Perspective perspective);
// Returns the first initiated unidirectional stream ID of |perspective|.
static QuicStreamId GetFirstUnidirectionalStreamId(
QuicTransportVersion version, Perspective perspective);
// Returns the largest possible client initiated bidirectional stream ID.
static QuicStreamId GetMaxClientInitiatedBidirectionalStreamId(
QuicTransportVersion version);
// Generates a random 64bit connection ID.
static QuicConnectionId CreateRandomConnectionId();
// Generates a random 64bit connection ID using the provided QuicRandom.
static QuicConnectionId CreateRandomConnectionId(QuicRandom* random);
// Generates a random connection ID of the given length.
static QuicConnectionId CreateRandomConnectionId(
uint8_t connection_id_length);
// Generates a random connection ID of the given length using the provided
// QuicRandom.
static QuicConnectionId CreateRandomConnectionId(uint8_t connection_id_length,
QuicRandom* random);
// Returns true if the connection ID length is valid for this QUIC version.
static bool IsConnectionIdLengthValidForVersion(
size_t connection_id_length, QuicTransportVersion transport_version);
// Returns true if the connection ID is valid for this QUIC version.
static bool IsConnectionIdValidForVersion(
QuicConnectionId connection_id, QuicTransportVersion transport_version);
// Returns a connection ID suitable for QUIC use-cases that do not need the
// connection ID for multiplexing. If the version allows variable lengths,
// a connection of length zero is returned, otherwise 64bits set to zero.
static QuicConnectionId CreateZeroConnectionId(QuicTransportVersion version);
// Generates a 128bit stateless reset token based on a connection ID.
static StatelessResetToken GenerateStatelessResetToken(
QuicConnectionId connection_id);
// Determines packet number space from |encryption_level|.
static PacketNumberSpace GetPacketNumberSpace(
EncryptionLevel encryption_level);
// Determines encryption level to send ACK in |packet_number_space|.
static EncryptionLevel GetEncryptionLevelToSendAckofSpace(
PacketNumberSpace packet_number_space);
// Get the maximum value for a V99/IETF QUIC stream count. If a count
// exceeds this value, it will result in a stream ID that exceeds the
// implementation limit on stream ID size.
static QuicStreamCount GetMaxStreamCount();
// Return true if this frame is an IETF probing frame.
static bool IsProbingFrame(QuicFrameType type);
// Return true if the two stateless reset tokens are equal. Performs the
// comparison in constant time.
static bool AreStatelessResetTokensEqual(const StatelessResetToken& token1,
const StatelessResetToken& token2);
// Return ture if this frame is an ack-eliciting frame.
static bool IsAckElicitingFrame(QuicFrameType type);
// Returns true if the specific ID is a valid WebTransport session ID that our
// implementation can process.
bool IsValidWebTransportSessionId(WebTransportSessionId id,
ParsedQuicVersion transport_version);
QuicByteCount MemSliceSpanTotalSize(absl::Span<quiche::QuicheMemSlice> span);
// Computes a SHA-256 hash and returns the raw bytes of the hash.
QUICHE_EXPORT std::string RawSha256(absl::string_view input);
// BitMask<Index, Mask> is a set of elements of type `Index` represented as a
// bitmask of an underlying integer type `Mask` (uint64_t by default). The
// underlying type has to be large enough to fit all possible values of `Index`.
template <typename Index, typename Mask = uint64_t>
class QUICHE_EXPORT BitMask {
explicit constexpr BitMask(std::initializer_list<Index> bits) {
for (Index bit : bits) {
mask_ |= MakeMask(bit);
BitMask() = default;
BitMask(const BitMask& other) = default;
BitMask& operator=(const BitMask& other) = default;
constexpr void Set(Index bit) { mask_ |= MakeMask(bit); }
constexpr void Set(std::initializer_list<Index> bits) {
mask_ |= BitMask(bits).mask();
constexpr bool IsSet(Index bit) const { return (MakeMask(bit) & mask_) != 0; }
constexpr void ClearAll() { mask_ = 0; }
// Returns true if any of the bits is set.
bool Any() const { return mask_ != 0; }
// Returns the highest bit set, or nullopt if the mask is all zeroes.
std::optional<Index> Max() const {
if (!Any()) {
return std::nullopt;
return static_cast<Index>(NumBits() - absl::countl_zero(mask_) - 1);
static constexpr size_t NumBits() { return 8 * sizeof(Mask); }
friend bool operator==(const BitMask& lhs, const BitMask& rhs) {
return lhs.mask_ == rhs.mask_;
// Bitwise AND that can act as a set intersection between two bit masks.
BitMask<Index, Mask> operator&(const BitMask<Index, Mask>& rhs) const {
return BitMask<Index, Mask>(mask_ & rhs.mask_);
std::string DebugString() const {
return absl::StrCat("0x", absl::Hex(mask_));
constexpr Mask mask() const { return mask_; }
explicit constexpr BitMask(Mask mask) : mask_(mask) {}
template <typename Bit>
static constexpr std::enable_if_t<std::is_enum_v<Bit>, Mask> MakeMask(
Bit bit) {
using IntType = typename std::underlying_type<Bit>::type;
return MakeMask(static_cast<IntType>(bit));
template <typename Bit>
static constexpr std::enable_if_t<!std::is_enum_v<Bit>, Mask> MakeMask(
Bit bit) {
// We can't use QUICHE_DCHECK_LT here, since it doesn't work with constexpr.
QUICHE_DCHECK(bit < static_cast<Bit>(NumBits()));
if constexpr (std::is_signed_v<Bit>) {
QUICHE_DCHECK(bit >= 0);
return Mask(1) << bit;
Mask mask_ = 0;
// Ensure that the BitMask constructor can be evaluated as constexpr.
static_assert(BitMask<int>({1, 2, 3}).mask() == 0x0e);
} // namespace quic