blob: a86a5dd8e541ea068255265732d816c51b2f8659 [file] [log] [blame]
// Copyright 2018 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_connection_id.h"
#include <cstdint>
#include <cstring>
#include <iomanip>
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
namespace quic {
QuicConnectionId::QuicConnectionId() {
if (!QuicConnectionIdUseNetworkByteOrder()) {
id64_ = 0;
length_ = sizeof(uint64_t);
return;
}
length_ = 0;
}
QuicConnectionId::QuicConnectionId(const char* data, uint8_t length) {
QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
<< "new constructor called when flag disabled";
if (length > kQuicMaxConnectionIdLength) {
QUIC_BUG << "Attempted to create connection ID of length " << length;
length = kQuicMaxConnectionIdLength;
}
length_ = length;
if (length_ > 0) {
memcpy(data_, data, length_);
}
QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 2, 3);
}
QuicConnectionId::QuicConnectionId(uint64_t connection_id64)
: length_(sizeof(uint64_t)) {
if (!QuicConnectionIdUseNetworkByteOrder()) {
id64_ = connection_id64;
return;
}
QUIC_BUG_IF(QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT) &&
QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER))
<< "old constructor called when flag enabled";
const uint64_t connection_id64_net = QuicEndian::HostToNet64(connection_id64);
memcpy(&data_, &connection_id64_net, sizeof(connection_id64_net));
}
QuicConnectionId::~QuicConnectionId() {}
uint64_t QuicConnectionId::ToUInt64() const {
if (!QuicConnectionIdUseNetworkByteOrder()) {
return id64_;
}
QUIC_BUG_IF(QuicConnectionIdSupportsVariableLength(Perspective::IS_CLIENT) &&
QuicConnectionIdSupportsVariableLength(Perspective::IS_SERVER))
<< "ToUInt64 called when flag enabled";
uint64_t connection_id64_net = 0;
memcpy(&connection_id64_net, &data_,
std::min<size_t>(static_cast<size_t>(length_),
sizeof(connection_id64_net)));
return QuicEndian::NetToHost64(connection_id64_net);
}
const char* QuicConnectionId::data() const {
QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
<< "data called when flag disabled";
QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 3, 3);
return data_;
}
char* QuicConnectionId::mutable_data() {
QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
<< "mutable_data called when flag disabled";
return data_;
}
uint8_t QuicConnectionId::length() const {
return length_;
}
void QuicConnectionId::set_length(uint8_t length) {
QUIC_BUG_IF(!QuicConnectionIdUseNetworkByteOrder())
<< "set_length called when flag disabled";
length_ = length;
}
bool QuicConnectionId::IsEmpty() const {
if (!QuicConnectionIdUseNetworkByteOrder()) {
return id64_ == 0;
}
return length_ == 0;
}
size_t QuicConnectionId::Hash() const {
if (!QuicConnectionIdUseNetworkByteOrder()) {
return id64_;
}
uint64_t data_bytes[3] = {0, 0, 0};
static_assert(sizeof(data_bytes) >= sizeof(data_), "sizeof(data_) changed");
memcpy(data_bytes, data_, length_);
// This Hash function is designed to return the same value
// as ToUInt64() when the connection ID length is 64 bits.
return QuicEndian::NetToHost64(kQuicDefaultConnectionIdLength ^ length_ ^
data_bytes[0] ^ data_bytes[1] ^ data_bytes[2]);
}
QuicString QuicConnectionId::ToString() const {
if (!QuicConnectionIdUseNetworkByteOrder()) {
return QuicTextUtils::Uint64ToString(id64_);
}
if (IsEmpty()) {
return QuicString("0");
}
return QuicTextUtils::HexEncode(data_, length_);
}
std::ostream& operator<<(std::ostream& os, const QuicConnectionId& v) {
os << v.ToString();
return os;
}
bool QuicConnectionId::operator==(const QuicConnectionId& v) const {
if (!QuicConnectionIdUseNetworkByteOrder()) {
return id64_ == v.id64_;
}
return length_ == v.length_ && memcmp(data_, v.data_, length_) == 0;
}
bool QuicConnectionId::operator!=(const QuicConnectionId& v) const {
return !(v == *this);
}
bool QuicConnectionId::operator<(const QuicConnectionId& v) const {
if (!QuicConnectionIdUseNetworkByteOrder()) {
return id64_ < v.id64_;
}
if (length_ < v.length_) {
return true;
}
if (length_ > v.length_) {
return false;
}
return memcmp(data_, v.data_, length_) < 0;
}
QuicConnectionId EmptyQuicConnectionId() {
return QuicConnectionId();
}
QuicConnectionId QuicConnectionIdFromUInt64(uint64_t connection_id64) {
return QuicConnectionId(connection_id64);
}
uint64_t QuicConnectionIdToUInt64(QuicConnectionId connection_id) {
return connection_id.ToUInt64();
}
bool QuicConnectionIdUseNetworkByteOrder() {
const bool res = GetQuicRestartFlag(quic_connection_ids_network_byte_order);
if (res) {
QUIC_RESTART_FLAG_COUNT(quic_connection_ids_network_byte_order);
}
return res;
}
bool QuicConnectionIdSupportsVariableLength(Perspective perspective) {
if (!QuicConnectionIdUseNetworkByteOrder()) {
return false;
}
bool res;
if (perspective == Perspective::IS_SERVER) {
res = GetQuicRestartFlag(quic_variable_length_connection_ids_server);
if (res) {
QUIC_RESTART_FLAG_COUNT_N(quic_variable_length_connection_ids_server, 1,
3);
}
} else {
res = GetQuicRestartFlag(quic_variable_length_connection_ids_client);
if (res) {
QUIC_RESTART_FLAG_COUNT(quic_variable_length_connection_ids_client);
}
}
return res;
}
static_assert(kQuicDefaultConnectionIdLength == sizeof(uint64_t),
"kQuicDefaultConnectionIdLength changed");
static_assert(kQuicDefaultConnectionIdLength == PACKET_8BYTE_CONNECTION_ID,
"kQuicDefaultConnectionIdLength changed");
} // namespace quic