blob: 8026e4f59942576262e39c536e6bb650a0d08785 [file] [log] [blame]
/** @file
*
* A brief file description
*
* @section license License
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "QUICPacket.h"
#include <algorithm>
#include <tscore/ink_assert.h>
#include <tscore/Diags.h>
#include "QUICIntUtil.h"
#include "QUICDebugNames.h"
#include "QUICRetryIntegrityTag.h"
using namespace std::literals;
static constexpr uint64_t aead_tag_len = 16;
static constexpr int LONG_HDR_OFFSET_CONNECTION_ID = 6;
static constexpr int LONG_HDR_OFFSET_VERSION = 1;
#define QUICDebug(dcid, scid, fmt, ...) \
Debug(tag.data(), "[%08" PRIx32 "-%08" PRIx32 "] " fmt, dcid.h32(), scid.h32(), ##__VA_ARGS__);
//
// QUICPacket
//
QUICPacket::QUICPacket() {}
QUICPacket::QUICPacket(bool ack_eliciting, bool probing) : _is_ack_eliciting(ack_eliciting), _is_probing_packet(probing) {}
QUICPacket::~QUICPacket() {}
QUICKeyPhase
QUICPacket::key_phase() const
{
ink_assert(!"This function should not be called");
return QUICKeyPhase::INITIAL;
}
bool
QUICPacket::is_ack_eliciting() const
{
return this->_is_ack_eliciting;
}
bool
QUICPacket::is_probing_packet() const
{
return this->_is_probing_packet;
}
uint16_t
QUICPacket::header_size() const
{
uint16_t size = 0;
for (auto b = this->header_block(); b; b = b->next) {
size += b->size();
}
return size;
}
uint16_t
QUICPacket::payload_length() const
{
uint16_t size = 0;
for (auto b = this->payload_block(); b; b = b->next) {
size += b->size();
}
return size;
}
uint16_t
QUICPacket::size() const
{
return this->header_size() + this->payload_length();
}
void
QUICPacket::store(uint8_t *buf, size_t *len) const
{
size_t written = 0;
Ptr<IOBufferBlock> block;
block = this->header_block();
while (block) {
memcpy(buf + written, block->start(), block->size());
written += block->size();
block = block->next;
}
block = this->payload_block();
while (block) {
memcpy(buf + written, block->start(), block->size());
written += block->size();
block = block->next;
}
*len = written;
}
uint8_t
QUICPacket::calc_packet_number_len(QUICPacketNumber num, QUICPacketNumber base)
{
uint64_t d = (num - base) * 2;
uint8_t len = 0;
if (d > 0xFFFFFF) {
len = 4;
} else if (d > 0xFFFF) {
len = 3;
} else if (d > 0xFF) {
len = 2;
} else {
len = 1;
}
return len;
}
bool
QUICPacket::encode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len)
{
uint64_t mask = 0;
switch (len) {
case 1:
mask = 0xFF;
break;
case 2:
mask = 0xFFFF;
break;
case 3:
mask = 0xFFFFFF;
break;
case 4:
mask = 0xFFFFFFFF;
break;
default:
ink_assert(!"len must be 1, 2, or 4");
return false;
}
dst = src & mask;
return true;
}
bool
QUICPacket::decode_packet_number(QUICPacketNumber &dst, QUICPacketNumber src, size_t len, QUICPacketNumber largest_acked)
{
ink_assert(len == 1 || len == 2 || len == 3 || len == 4);
uint64_t maximum_diff = 0;
switch (len) {
case 1:
maximum_diff = 0x100;
break;
case 2:
maximum_diff = 0x10000;
break;
case 3:
maximum_diff = 0x1000000;
break;
case 4:
maximum_diff = 0x100000000;
break;
default:
ink_assert(!"len must be 1, 2, 3 or 4");
}
QUICPacketNumber base = largest_acked & (~(maximum_diff - 1));
QUICPacketNumber candidate1 = base + src;
QUICPacketNumber candidate2 = base + src + maximum_diff;
QUICPacketNumber expected = largest_acked + 1;
if (((candidate1 > expected) ? (candidate1 - expected) : (expected - candidate1)) <
((candidate2 > expected) ? (candidate2 - expected) : (expected - candidate2))) {
dst = candidate1;
} else {
dst = candidate2;
}
return true;
}
//
// QUICPacketR
//
QUICPacketR::QUICPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to) : _udp_con(udp_con), _from(from), _to(to) {}
UDPConnection *
QUICPacketR::udp_con() const
{
return this->_udp_con;
}
const IpEndpoint &
QUICPacketR::from() const
{
return this->_from;
}
const IpEndpoint &
QUICPacketR::to() const
{
return this->_to;
}
bool
QUICPacketR::type(QUICPacketType &type, const uint8_t *packet, size_t packet_len)
{
if (packet_len < 1) {
return false;
}
if (QUICInvariants::is_long_header(packet)) {
return QUICLongHeaderPacketR::type(type, packet, packet_len);
} else {
type = QUICPacketType::PROTECTED;
return true;
}
}
bool
QUICPacketR::read_essential_info(Ptr<IOBufferBlock> block, QUICPacketType &type, QUICVersion &version, QUICConnectionId &dcid,
QUICConnectionId &scid, QUICPacketNumber &packet_number, QUICPacketNumber base_packet_number,
QUICKeyPhase &key_phase)
{
uint8_t tmp[47 + 64];
IOBufferReader reader;
reader.block = block;
int64_t len = std::min(static_cast<int64_t>(sizeof(tmp)), reader.read_avail());
if (len < 10) {
return false;
}
reader.memcpy(tmp, 1, 0);
if (QUICInvariants::is_long_header(tmp)) {
reader.memcpy(tmp, len, 0);
type = static_cast<QUICPacketType>((0x30 & tmp[0]) >> 4);
QUICInvariants::version(version, tmp, len);
if (version == 0x00) {
type = QUICPacketType::VERSION_NEGOTIATION;
}
if (!QUICInvariants::dcid(dcid, tmp, len) || !QUICInvariants::scid(scid, tmp, len)) {
return false;
}
if (type != QUICPacketType::RETRY) {
int packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(tmp);
size_t length_offset = 7 + dcid.length() + scid.length();
if (length_offset >= static_cast<uint64_t>(len)) {
return false;
}
uint64_t value;
size_t field_len;
QUICVariableInt::decode(value, field_len, tmp + length_offset);
switch (type) {
case QUICPacketType::INITIAL:
length_offset += field_len + value;
if (length_offset >= static_cast<uint64_t>(len)) {
return false;
}
QUICVariableInt::decode(value, field_len, tmp + length_offset);
if (length_offset + field_len >= static_cast<uint64_t>(len)) {
return false;
}
if (length_offset + field_len + packet_number_len > static_cast<uint64_t>(len)) {
return false;
}
packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + length_offset + field_len, packet_number_len);
key_phase = QUICKeyPhase::INITIAL;
break;
case QUICPacketType::ZERO_RTT_PROTECTED:
if (length_offset + field_len + packet_number_len >= static_cast<uint64_t>(len)) {
return false;
}
packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + length_offset + field_len, packet_number_len);
key_phase = QUICKeyPhase::ZERO_RTT;
break;
case QUICPacketType::HANDSHAKE:
if (length_offset + field_len + packet_number_len >= static_cast<uint64_t>(len)) {
return false;
}
packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + length_offset + field_len, packet_number_len);
key_phase = QUICKeyPhase::INITIAL;
break;
case QUICPacketType::VERSION_NEGOTIATION:
break;
default:
break;
}
} else {
packet_number = 0;
}
} else {
len = std::min(static_cast<int64_t>(25), len);
reader.memcpy(tmp, len, 0);
type = QUICPacketType::PROTECTED;
QUICInvariants::dcid(dcid, tmp, len);
int packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(tmp);
if (tmp[0] & 0x04) {
key_phase = QUICKeyPhase::PHASE_1;
} else {
key_phase = QUICKeyPhase::PHASE_0;
}
packet_number = QUICTypeUtil::read_QUICPacketNumber(tmp + 1 + dcid.length(), packet_number_len);
}
return true;
}
//
// QUICLongHeaderPacket
//
QUICLongHeaderPacket::QUICLongHeaderPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, bool ack_eliciting,
bool probing, bool crypto)
: QUICPacket(ack_eliciting, probing), _version(version), _dcid(dcid), _scid(scid), _is_crypto_packet(crypto)
{
}
QUICConnectionId
QUICLongHeaderPacket::destination_cid() const
{
return this->_dcid;
}
QUICConnectionId
QUICLongHeaderPacket::source_cid() const
{
return this->_scid;
}
uint16_t
QUICLongHeaderPacket::payload_length() const
{
return this->_payload_length;
}
QUICVersion
QUICLongHeaderPacket::version() const
{
return this->_version;
}
size_t
QUICLongHeaderPacket::_write_common_header(uint8_t *buf) const
{
size_t n;
size_t len = 0;
buf[0] = 0xC0;
buf[0] += static_cast<uint8_t>(this->type()) << 4;
len += 1;
QUICTypeUtil::write_QUICVersion(this->_version, buf + len, &n);
len += n;
// DICD
if (this->_dcid != QUICConnectionId::ZERO()) {
// Len
buf[len] = this->_dcid.length();
len += 1;
// ID
QUICTypeUtil::write_QUICConnectionId(this->_dcid, buf + len, &n);
len += n;
} else {
buf[len] = 0;
len += 1;
}
// SCID
if (this->_scid != QUICConnectionId::ZERO()) {
// Len
buf[len] = this->_scid.length();
len += 1;
// ID
QUICTypeUtil::write_QUICConnectionId(this->_scid, buf + len, &n);
len += n;
} else {
buf[len] = 0;
len += 1;
}
return len;
}
bool
QUICLongHeaderPacket::is_crypto_packet() const
{
return this->_is_crypto_packet;
}
//
// QUICLongHeaderPacketR
//
QUICLongHeaderPacketR::QUICLongHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks)
: QUICPacketR(udp_con, from, to)
{
IOBufferReader reader;
uint8_t data[47];
reader.block = blocks;
int64_t data_len = reader.read(data, sizeof(data));
QUICLongHeaderPacketR::version(this->_version, data, data_len);
}
QUICVersion
QUICLongHeaderPacketR::version() const
{
return this->_version;
}
QUICConnectionId
QUICLongHeaderPacketR::source_cid() const
{
return this->_scid;
}
QUICConnectionId
QUICLongHeaderPacketR::destination_cid() const
{
return this->_dcid;
}
bool
QUICLongHeaderPacketR::type(QUICPacketType &type, const uint8_t *packet, size_t packet_len)
{
if (packet_len < 1) {
return false;
}
QUICVersion version;
if (QUICLongHeaderPacketR::version(version, packet, packet_len) && version == 0x00) {
type = QUICPacketType::VERSION_NEGOTIATION;
} else {
uint8_t raw_type = (packet[0] & 0x30) >> 4;
type = static_cast<QUICPacketType>(raw_type);
}
return true;
}
bool
QUICLongHeaderPacketR::version(QUICVersion &version, const uint8_t *packet, size_t packet_len)
{
if (packet_len < 5) {
return false;
}
version = QUICTypeUtil::read_QUICVersion(packet + LONG_HDR_OFFSET_VERSION);
return true;
}
bool
QUICLongHeaderPacketR::key_phase(QUICKeyPhase &phase, const uint8_t *packet, size_t packet_len)
{
QUICPacketType type = QUICPacketType::UNINITIALIZED;
QUICLongHeaderPacketR::type(type, packet, packet_len);
phase = QUICTypeUtil::key_phase(type);
return true;
}
bool
QUICLongHeaderPacketR::length(size_t &length, uint8_t &length_field_len, size_t &length_field_offset, const uint8_t *packet,
size_t packet_len)
{
// FIXME This is not great because each packet types have different formats.
// We should remove this function and have length() on each packet type classes instead.
uint8_t dcil;
if (!QUICInvariants::dcil(dcil, packet, packet_len)) {
return false;
}
uint8_t scil;
if (!QUICInvariants::scil(scil, packet, packet_len)) {
return false;
}
length_field_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + 1 + scil;
QUICPacketType type = QUICPacketType::UNINITIALIZED;
QUICLongHeaderPacketR::type(type, packet, packet_len);
if (type == QUICPacketType::INITIAL) {
// Token Length (i) + Token (*) (for INITIAL packet)
size_t token_length = 0;
uint8_t token_length_field_len = 0;
size_t token_length_field_offset = 0;
if (!QUICInitialPacketR::token_length(token_length, token_length_field_len, token_length_field_offset, packet, packet_len)) {
return false;
}
length_field_offset += token_length_field_len + token_length;
}
// Length (i)
if (length_field_offset >= packet_len) {
return false;
}
length_field_len = QUICVariableInt::size(packet + length_field_offset);
length = QUICIntUtil::read_QUICVariableInt(packet + length_field_offset, packet_len - length_field_offset);
return true;
}
bool
QUICLongHeaderPacketR::packet_length(size_t &packet_len, const uint8_t *buf, size_t buf_len)
{
size_t length;
uint8_t length_field_len;
size_t length_field_offset;
if (!QUICLongHeaderPacketR::length(length, length_field_len, length_field_offset, buf, buf_len)) {
return false;
}
packet_len = length + length_field_offset + length_field_len;
if (packet_len > buf_len) {
return false;
}
return true;
}
bool
QUICLongHeaderPacketR::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len)
{
size_t dummy;
uint8_t length_field_len;
size_t length_field_offset;
if (!QUICLongHeaderPacketR::length(dummy, length_field_len, length_field_offset, packet, packet_len)) {
return false;
}
pn_offset = length_field_offset + length_field_len;
if (pn_offset >= packet_len) {
return false;
}
return true;
}
//
// QUICShortHeaderPacket
//
QUICShortHeaderPacket::QUICShortHeaderPacket(QUICConnectionId dcid, QUICPacketNumber packet_number,
QUICPacketNumber base_packet_number, QUICKeyPhase key_phase, bool ack_eliciting,
bool probing)
: QUICPacket(ack_eliciting, probing), _dcid(dcid), _packet_number(packet_number), _key_phase(key_phase)
{
this->_packet_number_len = QUICPacket::calc_packet_number_len(packet_number, base_packet_number);
}
QUICPacketType
QUICShortHeaderPacket::type() const
{
return QUICPacketType::PROTECTED;
}
QUICKeyPhase
QUICShortHeaderPacket::key_phase() const
{
return this->_key_phase;
}
QUICConnectionId
QUICShortHeaderPacket::destination_cid() const
{
return this->_dcid;
}
QUICPacketNumber
QUICShortHeaderPacket::packet_number() const
{
return this->_packet_number;
}
uint16_t
QUICShortHeaderPacket::payload_length() const
{
return this->_payload_length;
}
Ptr<IOBufferBlock>
QUICShortHeaderPacket::header_block() const
{
Ptr<IOBufferBlock> block;
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + QUICConnectionId::MAX_LENGTH + 4, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
size_t n;
buf[0] = 0x40;
// Type
buf[0] = 0x40;
// TODO Spin Bit
// KeyPhase
if (this->_key_phase == QUICKeyPhase::PHASE_1) {
buf[0] |= 0x04;
}
written_len += 1;
// Destination Connection ID
if (this->_dcid != QUICConnectionId::ZERO()) {
QUICTypeUtil::write_QUICConnectionId(this->_dcid, buf + written_len, &n);
written_len += n;
}
// Packet Number
QUICPacketNumber dst = 0;
size_t dst_len = this->_packet_number_len;
QUICPacket::encode_packet_number(dst, this->_packet_number, dst_len);
QUICTypeUtil::write_QUICPacketNumber(dst, dst_len, buf + written_len, &n);
written_len += n;
// Packet Number Length
QUICTypeUtil::write_QUICPacketNumberLen(n, buf);
block->fill(written_len);
return block;
}
Ptr<IOBufferBlock>
QUICShortHeaderPacket::payload_block() const
{
return this->_payload_block;
}
void
QUICShortHeaderPacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
this->_payload_length = 0;
Ptr<IOBufferBlock> tmp = payload;
while (tmp) {
this->_payload_length += tmp->size();
tmp = tmp->next;
}
if (unprotected) {
this->_payload_length += aead_tag_len;
}
}
//
// QUICShortHeaderPacketR
//
QUICShortHeaderPacketR::QUICShortHeaderPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
QUICPacketNumber base_packet_number)
: QUICPacketR(udp_con, from, to)
{
size_t len = 0;
for (auto b = blocks; b; b = b->next) {
len += b->size();
}
Ptr<IOBufferBlock> concatenated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
concatenated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
concatenated_block->fill(len);
uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatenated_block->start());
size_t copied_len = 0;
for (auto b = blocks; b; b = b->next) {
memcpy(raw_buf + copied_len, b->start(), b->size());
copied_len += b->size();
}
if (raw_buf[0] & 0x04) {
this->_key_phase = QUICKeyPhase::PHASE_1;
} else {
this->_key_phase = QUICKeyPhase::PHASE_0;
}
QUICInvariants::dcid(this->_dcid, raw_buf, len);
int offset = 1 + this->_dcid.length();
this->_packet_number_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
QUICPacketNumber src = QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, this->_packet_number_len);
QUICPacket::decode_packet_number(this->_packet_number, src, this->_packet_number_len, base_packet_number);
offset += this->_packet_number_len;
this->_header_block = concatenated_block->clone();
this->_header_block->_end = this->_header_block->_start + offset;
this->_header_block->next = nullptr;
this->_payload_block = concatenated_block->clone();
this->_payload_block->_start = this->_payload_block->_start + offset;
}
QUICPacketType
QUICShortHeaderPacketR::type() const
{
return QUICPacketType::PROTECTED;
}
QUICKeyPhase
QUICShortHeaderPacketR::key_phase() const
{
return this->_key_phase;
}
QUICPacketNumber
QUICShortHeaderPacketR::packet_number() const
{
return this->_packet_number;
}
QUICConnectionId
QUICShortHeaderPacketR::destination_cid() const
{
return this->_dcid;
}
Ptr<IOBufferBlock>
QUICShortHeaderPacketR::header_block() const
{
return this->_header_block;
}
Ptr<IOBufferBlock>
QUICShortHeaderPacketR::payload_block() const
{
return this->_payload_block;
}
void
QUICShortHeaderPacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
}
bool
QUICShortHeaderPacketR::packet_number_offset(size_t &pn_offset, const uint8_t *packet, size_t packet_len, int dcil)
{
pn_offset = 1 + dcil;
return true;
}
//
// QUICStatelessResetPacket
//
QUICStatelessResetPacket::QUICStatelessResetPacket(QUICStatelessResetToken token, size_t maximum_size)
: QUICPacket(), _token(token), _maximum_size(maximum_size)
{
}
QUICPacketType
QUICStatelessResetPacket::type() const
{
return QUICPacketType::STATELESS_RESET;
}
QUICConnectionId
QUICStatelessResetPacket::destination_cid() const
{
ink_assert(!"You should not need DCID of Stateless Reset Packet");
return QUICConnectionId::ZERO();
}
Ptr<IOBufferBlock>
QUICStatelessResetPacket::header_block() const
{
// Required shortest length is 38 bits however less than 41 bytes in total indicates this is stateless reset.
constexpr uint8_t MIN_UNPREDICTABLE_FIELD_LEN = 5 + 20;
std::random_device rnd;
Ptr<IOBufferBlock> block;
size_t written_len = 0;
size_t random_extra_length = rnd() & 0x07; // Extra 0 to 7 bytes
if (MIN_UNPREDICTABLE_FIELD_LEN + random_extra_length > this->_maximum_size) {
return block;
}
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(MIN_UNPREDICTABLE_FIELD_LEN + random_extra_length, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
// Generate random octets
for (int i = 0; i < MIN_UNPREDICTABLE_FIELD_LEN; ++i) {
buf[i] = static_cast<uint8_t>(rnd() & 0xFF);
}
buf[0] = (buf[0] | 0x40) & 0x7f;
written_len += MIN_UNPREDICTABLE_FIELD_LEN;
block->fill(written_len);
return block;
}
Ptr<IOBufferBlock>
QUICStatelessResetPacket::payload_block() const
{
Ptr<IOBufferBlock> block;
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(QUICStatelessResetToken::LEN, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
memcpy(buf, this->_token.buf(), QUICStatelessResetToken::LEN);
written_len += QUICStatelessResetToken::LEN;
block->fill(written_len);
return block;
}
QUICPacketNumber
QUICStatelessResetPacket::packet_number() const
{
ink_assert(!"You should not need packet number of Stateless Reset Packet");
return 0;
}
QUICStatelessResetToken
QUICStatelessResetPacket::token() const
{
return this->_token;
}
//
// QUICStatelessResetPacketR
//
QUICStatelessResetPacketR::QUICStatelessResetPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to,
Ptr<IOBufferBlock> blocks)
: QUICPacketR(udp_con, from, to)
{
}
QUICPacketType
QUICStatelessResetPacketR::type() const
{
return QUICPacketType::STATELESS_RESET;
}
QUICPacketNumber
QUICStatelessResetPacketR::packet_number() const
{
ink_assert(!"You should not need packet number of Stateless Reset Packet");
return 0;
}
QUICConnectionId
QUICStatelessResetPacketR::destination_cid() const
{
ink_assert(!"You should not need DCID of Stateless Reset Packet");
return QUICConnectionId::ZERO();
}
//
// QUICVersionNegotiationPacket
//
QUICVersionNegotiationPacket::QUICVersionNegotiationPacket(QUICConnectionId dcid, QUICConnectionId scid,
const QUICVersion versions[], int nversions)
: QUICLongHeaderPacket(0, dcid, scid, false, false, false), _versions(versions), _nversions(nversions)
{
}
QUICPacketType
QUICVersionNegotiationPacket::type() const
{
return QUICPacketType::VERSION_NEGOTIATION;
}
QUICVersion
QUICVersionNegotiationPacket::version() const
{
return 0;
}
QUICPacketNumber
QUICVersionNegotiationPacket::packet_number() const
{
ink_assert(!"You should not need packet number of Version Negotiation Packet");
return 0;
}
uint16_t
QUICVersionNegotiationPacket::payload_length() const
{
uint16_t size = 0;
for (auto b = this->payload_block(); b; b = b->next) {
size += b->size();
}
return size;
}
Ptr<IOBufferBlock>
QUICVersionNegotiationPacket::header_block() const
{
Ptr<IOBufferBlock> block;
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
// Common Long Header
written_len += this->_write_common_header(buf + written_len);
// Overwrite the first byte
buf[0] = 0x80 | rand();
block->fill(written_len);
return block;
}
Ptr<IOBufferBlock>
QUICVersionNegotiationPacket::payload_block() const
{
Ptr<IOBufferBlock> block;
uint8_t *buf;
size_t written_len = 0;
size_t n;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(sizeof(QUICVersion) * (this->_nversions + 1), BUFFER_SIZE_INDEX_32K));
buf = reinterpret_cast<uint8_t *>(block->start());
for (auto i = 0; i < this->_nversions; ++i) {
QUICTypeUtil::write_QUICVersion(*(this->_versions + i), buf + written_len, &n);
written_len += n;
}
// [draft-18] 6.3. Using Reserved Versions
// To help ensure this, a server SHOULD include a reserved version (see Section 15) while generating a
// Version Negotiation packet.
QUICTypeUtil::write_QUICVersion(QUIC_EXERCISE_VERSION, buf + written_len, &n);
written_len += n;
block->fill(written_len);
return block;
}
const QUICVersion *
QUICVersionNegotiationPacket::versions() const
{
return this->_versions;
}
int
QUICVersionNegotiationPacket::nversions() const
{
return this->_nversions;
}
//
// QUICVersionNegotiationPacketR
//
QUICVersionNegotiationPacketR::QUICVersionNegotiationPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to,
Ptr<IOBufferBlock> blocks)
: QUICLongHeaderPacketR(udp_con, from, to, blocks)
{
size_t len = 0;
for (auto b = blocks; b; b = b->next) {
len += b->size();
}
Ptr<IOBufferBlock> concatenated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
concatenated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
concatenated_block->fill(len);
uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatenated_block->start());
size_t copied_len = 0;
for (auto b = blocks; b; b = b->next) {
memcpy(raw_buf + copied_len, b->start(), b->size());
copied_len += b->size();
}
uint8_t dcil = 0;
uint8_t scil = 0;
QUICInvariants::dcil(dcil, raw_buf, len);
QUICInvariants::scil(scil, raw_buf, len);
size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
this->_dcid = {raw_buf + offset, dcil};
offset += dcil + 1;
this->_scid = {raw_buf + offset, scil};
offset += scil;
this->_versions = raw_buf + offset;
this->_nversions = (len - offset) / sizeof(QUICVersion);
this->_header_block = concatenated_block->clone();
this->_header_block->_end = this->_header_block->_start + offset;
this->_header_block->next = nullptr;
this->_payload_block = concatenated_block->clone();
this->_payload_block->_start = this->_payload_block->_start + offset;
}
QUICPacketType
QUICVersionNegotiationPacketR::type() const
{
return QUICPacketType::VERSION_NEGOTIATION;
}
QUICPacketNumber
QUICVersionNegotiationPacketR::packet_number() const
{
ink_assert(!"You should not need packet number of Version Negotiation Packet");
return 0;
}
QUICConnectionId
QUICVersionNegotiationPacketR::destination_cid() const
{
return this->_dcid;
}
Ptr<IOBufferBlock>
QUICVersionNegotiationPacketR::header_block() const
{
return this->_header_block;
}
Ptr<IOBufferBlock>
QUICVersionNegotiationPacketR::payload_block() const
{
return this->_payload_block;
}
const QUICVersion
QUICVersionNegotiationPacketR::supported_version(uint8_t index) const
{
return QUICTypeUtil::read_QUICVersion(this->_versions + sizeof(QUICVersion) * index);
}
int
QUICVersionNegotiationPacketR::nversions() const
{
return this->_nversions;
}
//
// QUICInitialPacket
//
QUICInitialPacket::QUICInitialPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t token_len,
ats_unique_buf token, size_t length, QUICPacketNumber packet_number, bool ack_eliciting,
bool probing, bool crypto)
: QUICLongHeaderPacket(version, dcid, scid, ack_eliciting, probing, crypto),
_token_len(token_len),
_token(std::move(token)),
_packet_number(packet_number)
{
}
QUICPacketType
QUICInitialPacket::type() const
{
return QUICPacketType::INITIAL;
}
QUICKeyPhase
QUICInitialPacket::key_phase() const
{
return QUICKeyPhase::INITIAL;
}
QUICPacketNumber
QUICInitialPacket::packet_number() const
{
return this->_packet_number;
}
Ptr<IOBufferBlock>
QUICInitialPacket::header_block() const
{
Ptr<IOBufferBlock> block;
size_t written_len = 0;
size_t n;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
// Common Long Header
written_len += this->_write_common_header(buf + written_len);
// Token Length
QUICIntUtil::write_QUICVariableInt(this->_token_len, buf + written_len, &n);
written_len += n;
// Token
memcpy(buf + written_len, this->_token.get(), this->_token_len);
written_len += this->_token_len;
QUICPacketNumber pn = 0;
size_t pn_len = 4;
QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len);
if (pn > 0x7FFFFF) {
pn_len = 4;
} else if (pn > 0x7FFF) {
pn_len = 3;
} else if (pn > 0x7F) {
pn_len = 2;
} else {
pn_len = 1;
}
// PN Len
QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf);
// Length
QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length, buf + written_len, &n);
written_len += n;
// PN Field
QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + written_len, &n);
written_len += n;
block->fill(written_len);
return block;
}
Ptr<IOBufferBlock>
QUICInitialPacket::payload_block() const
{
return this->_payload_block;
}
void
QUICInitialPacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
this->_payload_length = 0;
Ptr<IOBufferBlock> tmp = payload;
while (tmp) {
this->_payload_length += tmp->size();
tmp = tmp->next;
}
if (unprotected) {
this->_payload_length += aead_tag_len;
}
}
//
// QUICInitialPacketR
//
QUICInitialPacketR::QUICInitialPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
QUICPacketNumber base_packet_number)
: QUICLongHeaderPacketR(udp_con, from, to, blocks)
{
size_t len = 0;
for (auto b = blocks; b; b = b->next) {
len += b->size();
}
Ptr<IOBufferBlock> concatenated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
concatenated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
concatenated_block->fill(len);
uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatenated_block->start());
size_t copied_len = 0;
for (auto b = blocks; b; b = b->next) {
memcpy(raw_buf + copied_len, b->start(), b->size());
copied_len += b->size();
}
uint8_t dcil = 0;
uint8_t scil = 0;
QUICInvariants::dcil(dcil, raw_buf, len);
QUICInvariants::scil(scil, raw_buf, len);
size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
this->_dcid = {raw_buf + offset, dcil};
offset += dcil + 1;
this->_scid = {raw_buf + offset, scil};
offset += scil;
// Token Length Field
uint64_t token_len = QUICIntUtil::read_QUICVariableInt(raw_buf + offset, len - offset);
offset += QUICVariableInt::size(raw_buf + offset);
// Token Field
if (token_len) {
this->_token = new QUICAddressValidationToken(raw_buf + offset, token_len);
offset += token_len;
} else {
this->_token = new QUICAddressValidationToken(nullptr, 0);
}
// Length Field
offset += QUICVariableInt::size(raw_buf + offset);
// PN Field
int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, pn_len), pn_len,
base_packet_number);
offset += pn_len;
this->_header_block = concatenated_block->clone();
this->_header_block->_end = this->_header_block->_start + offset;
this->_header_block->next = nullptr;
this->_payload_block = concatenated_block->clone();
this->_payload_block->_start = this->_payload_block->_start + offset;
}
QUICInitialPacketR::~QUICInitialPacketR()
{
delete this->_token;
}
QUICPacketType
QUICInitialPacketR::type() const
{
return QUICPacketType::INITIAL;
}
QUICPacketNumber
QUICInitialPacketR::packet_number() const
{
return this->_packet_number;
}
QUICKeyPhase
QUICInitialPacketR::key_phase() const
{
return QUICKeyPhase::INITIAL;
}
Ptr<IOBufferBlock>
QUICInitialPacketR::header_block() const
{
return this->_header_block;
}
Ptr<IOBufferBlock>
QUICInitialPacketR::payload_block() const
{
return this->_payload_block;
}
void
QUICInitialPacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
}
const QUICAddressValidationToken &
QUICInitialPacketR::token() const
{
return *(this->_token);
}
bool
QUICInitialPacketR::token_length(size_t &token_length, uint8_t &field_len, size_t &token_length_filed_offset, const uint8_t *packet,
size_t packet_len)
{
QUICPacketType type = QUICPacketType::UNINITIALIZED;
QUICPacketR::type(type, packet, packet_len);
ink_assert(type == QUICPacketType::INITIAL);
uint8_t dcil, scil;
QUICInvariants::dcil(dcil, packet, packet_len);
QUICInvariants::scil(scil, packet, packet_len);
token_length_filed_offset = LONG_HDR_OFFSET_CONNECTION_ID + dcil + 1 + scil;
if (token_length_filed_offset >= packet_len) {
return false;
}
token_length = QUICIntUtil::read_QUICVariableInt(packet + token_length_filed_offset, packet_len - token_length_filed_offset);
field_len = QUICVariableInt::size(packet + token_length_filed_offset);
return true;
}
//
// QUICZeroRttPacket
//
QUICZeroRttPacket::QUICZeroRttPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t length,
QUICPacketNumber packet_number, bool ack_eliciting, bool probing)
: QUICLongHeaderPacket(version, dcid, scid, ack_eliciting, probing, false), _packet_number(packet_number)
{
}
QUICPacketType
QUICZeroRttPacket::type() const
{
return QUICPacketType::ZERO_RTT_PROTECTED;
}
QUICKeyPhase
QUICZeroRttPacket::key_phase() const
{
return QUICKeyPhase::ZERO_RTT;
}
QUICPacketNumber
QUICZeroRttPacket::packet_number() const
{
return this->_packet_number;
}
Ptr<IOBufferBlock>
QUICZeroRttPacket::header_block() const
{
Ptr<IOBufferBlock> block;
size_t written_len = 0;
size_t n;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
// Common Long Header
written_len += this->_write_common_header(buf + written_len);
QUICPacketNumber pn = 0;
size_t pn_len = 4;
QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len);
if (pn > 0x7FFFFF) {
pn_len = 4;
} else if (pn > 0x7FFF) {
pn_len = 3;
} else if (pn > 0x7F) {
pn_len = 2;
} else {
pn_len = 1;
}
// PN Len
QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf);
// Length
QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length, buf + written_len, &n);
written_len += n;
// PN Field
QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + written_len, &n);
written_len += n;
block->fill(written_len);
return block;
}
Ptr<IOBufferBlock>
QUICZeroRttPacket::payload_block() const
{
return this->_payload_block;
}
void
QUICZeroRttPacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
this->_payload_length = 0;
Ptr<IOBufferBlock> tmp = payload;
while (tmp) {
this->_payload_length += tmp->size();
tmp = tmp->next;
}
if (unprotected) {
this->_payload_length += aead_tag_len;
}
}
//
// QUICZeroRttPacketR
//
QUICZeroRttPacketR::QUICZeroRttPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
QUICPacketNumber base_packet_number)
: QUICLongHeaderPacketR(udp_con, from, to, blocks)
{
size_t len = 0;
for (auto b = blocks; b; b = b->next) {
len += b->size();
}
Ptr<IOBufferBlock> concatenated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
concatenated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
concatenated_block->fill(len);
uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatenated_block->start());
size_t copied_len = 0;
for (auto b = blocks; b; b = b->next) {
memcpy(raw_buf + copied_len, b->start(), b->size());
copied_len += b->size();
}
uint8_t dcil = 0;
uint8_t scil = 0;
QUICInvariants::dcil(dcil, raw_buf, len);
QUICInvariants::scil(scil, raw_buf, len);
size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
this->_dcid = {raw_buf + offset, dcil};
offset += dcil + 1;
this->_scid = {raw_buf + offset, scil};
offset += scil;
// Length Field
offset += QUICVariableInt::size(raw_buf + offset);
// PN Field
int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, pn_len), pn_len,
base_packet_number);
offset += pn_len;
this->_header_block = concatenated_block->clone();
this->_header_block->_end = this->_header_block->_start + offset;
this->_header_block->next = nullptr;
this->_payload_block = concatenated_block->clone();
this->_payload_block->_start = this->_payload_block->_start + offset;
}
QUICPacketType
QUICZeroRttPacketR::type() const
{
return QUICPacketType::ZERO_RTT_PROTECTED;
}
QUICPacketNumber
QUICZeroRttPacketR::packet_number() const
{
return this->_packet_number;
}
QUICKeyPhase
QUICZeroRttPacketR::key_phase() const
{
return QUICKeyPhase::ZERO_RTT;
}
Ptr<IOBufferBlock>
QUICZeroRttPacketR::header_block() const
{
return this->_header_block;
}
Ptr<IOBufferBlock>
QUICZeroRttPacketR::payload_block() const
{
return this->_payload_block;
}
void
QUICZeroRttPacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
}
//
// QUICHandshakePacket
//
QUICHandshakePacket::QUICHandshakePacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, size_t length,
QUICPacketNumber packet_number, bool ack_eliciting, bool probing, bool crypto)
: QUICLongHeaderPacket(version, dcid, scid, ack_eliciting, probing, crypto), _packet_number(packet_number)
{
}
QUICPacketType
QUICHandshakePacket::type() const
{
return QUICPacketType::HANDSHAKE;
}
QUICKeyPhase
QUICHandshakePacket::key_phase() const
{
return QUICKeyPhase::HANDSHAKE;
}
QUICPacketNumber
QUICHandshakePacket::packet_number() const
{
return this->_packet_number;
}
Ptr<IOBufferBlock>
QUICHandshakePacket::header_block() const
{
Ptr<IOBufferBlock> block;
size_t written_len = 0;
size_t n;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
// Common Long Header
written_len += this->_write_common_header(buf + written_len);
QUICPacketNumber pn = 0;
size_t pn_len = 4;
QUICPacket::encode_packet_number(pn, this->_packet_number, pn_len);
if (pn > 0x7FFFFF) {
pn_len = 4;
} else if (pn > 0x7FFF) {
pn_len = 3;
} else if (pn > 0x7F) {
pn_len = 2;
} else {
pn_len = 1;
}
// PN Len
QUICTypeUtil::write_QUICPacketNumberLen(pn_len, buf);
// Length
QUICIntUtil::write_QUICVariableInt(pn_len + this->_payload_length, buf + written_len, &n);
written_len += n;
// PN Field
QUICTypeUtil::write_QUICPacketNumber(pn, pn_len, buf + written_len, &n);
written_len += n;
block->fill(written_len);
return block;
}
Ptr<IOBufferBlock>
QUICHandshakePacket::payload_block() const
{
return this->_payload_block;
}
void
QUICHandshakePacket::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
this->_payload_length = 0;
Ptr<IOBufferBlock> tmp = payload;
while (tmp) {
this->_payload_length += tmp->size();
tmp = tmp->next;
}
if (unprotected) {
this->_payload_length += aead_tag_len;
}
}
//
// QUICHandshakePacketR
//
QUICHandshakePacketR::QUICHandshakePacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks,
QUICPacketNumber base_packet_number)
: QUICLongHeaderPacketR(udp_con, from, to, blocks)
{
size_t len = 0;
for (auto b = blocks; b; b = b->next) {
len += b->size();
}
Ptr<IOBufferBlock> concatenated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
concatenated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
concatenated_block->fill(len);
uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatenated_block->start());
size_t copied_len = 0;
for (auto b = blocks; b; b = b->next) {
memcpy(raw_buf + copied_len, b->start(), b->size());
copied_len += b->size();
}
uint8_t dcil = 0;
uint8_t scil = 0;
QUICInvariants::dcil(dcil, raw_buf, len);
QUICInvariants::scil(scil, raw_buf, len);
size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
this->_dcid = {raw_buf + offset, dcil};
offset += dcil + 1;
this->_scid = {raw_buf + offset, scil};
offset += scil;
// Length Field
offset += QUICVariableInt::size(raw_buf + offset);
// PN Field
int pn_len = QUICTypeUtil::read_QUICPacketNumberLen(raw_buf);
QUICPacket::decode_packet_number(this->_packet_number, QUICTypeUtil::read_QUICPacketNumber(raw_buf + offset, pn_len), pn_len,
base_packet_number);
offset += pn_len;
this->_header_block = concatenated_block->clone();
this->_header_block->_end = this->_header_block->_start + offset;
this->_header_block->next = nullptr;
this->_payload_block = concatenated_block->clone();
this->_payload_block->_start = this->_payload_block->_start + offset;
}
QUICPacketType
QUICHandshakePacketR::type() const
{
return QUICPacketType::HANDSHAKE;
}
QUICKeyPhase
QUICHandshakePacketR::key_phase() const
{
return QUICKeyPhase::HANDSHAKE;
}
QUICPacketNumber
QUICHandshakePacketR::packet_number() const
{
return this->_packet_number;
}
Ptr<IOBufferBlock>
QUICHandshakePacketR::header_block() const
{
return this->_header_block;
}
Ptr<IOBufferBlock>
QUICHandshakePacketR::payload_block() const
{
return this->_payload_block;
}
void
QUICHandshakePacketR::attach_payload(Ptr<IOBufferBlock> payload, bool unprotected)
{
this->_payload_block = payload;
}
//
// QUICRetryPacket
//
QUICRetryPacket::QUICRetryPacket(QUICVersion version, QUICConnectionId dcid, QUICConnectionId scid, QUICRetryToken &token)
: QUICLongHeaderPacket(version, dcid, scid, false, false, false), _token(token)
{
}
QUICPacketType
QUICRetryPacket::type() const
{
return QUICPacketType::RETRY;
}
QUICPacketNumber
QUICRetryPacket::packet_number() const
{
ink_assert(!"You should not need packet number of Retry Packet");
return 0;
}
uint16_t
QUICRetryPacket::payload_length() const
{
uint16_t size = 0;
for (auto b = this->payload_block(); b; b = b->next) {
size += b->size();
}
return size;
}
Ptr<IOBufferBlock>
QUICRetryPacket::header_block() const
{
Ptr<IOBufferBlock> block;
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(2048, BUFFER_SIZE_INDEX_32K));
uint8_t *buf = reinterpret_cast<uint8_t *>(block->start());
// Common Long Header
written_len += this->_write_common_header(buf + written_len);
block->fill(written_len);
return block;
}
Ptr<IOBufferBlock>
QUICRetryPacket::payload_block() const
{
Ptr<IOBufferBlock> block;
uint8_t *buf;
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(QUICConnectionId::MAX_LENGTH + this->_token.length() + QUICRetryIntegrityTag::LEN,
BUFFER_SIZE_INDEX_32K));
buf = reinterpret_cast<uint8_t *>(block->start());
// Retry Token
memcpy(buf + written_len, this->_token.buf(), this->_token.length());
written_len += this->_token.length();
block->fill(written_len);
// Retry Integrity Tag
QUICRetryIntegrityTag::compute(buf + written_len, this->_token.original_dcid(), this->header_block(), block);
written_len += QUICRetryIntegrityTag::LEN;
block->fill(QUICRetryIntegrityTag::LEN);
return block;
}
const QUICRetryToken &
QUICRetryPacket::token() const
{
return this->_token;
}
//
// QUICRetryPacketR
//
QUICRetryPacketR::QUICRetryPacketR(UDPConnection *udp_con, IpEndpoint from, IpEndpoint to, Ptr<IOBufferBlock> blocks)
: QUICLongHeaderPacketR(udp_con, from, to, blocks)
{
size_t len = 0;
for (auto b = blocks; b; b = b->next) {
len += b->size();
}
Ptr<IOBufferBlock> concatenated_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
concatenated_block->alloc(iobuffer_size_to_index(len, BUFFER_SIZE_INDEX_32K));
concatenated_block->fill(len);
uint8_t *raw_buf = reinterpret_cast<uint8_t *>(concatenated_block->start());
size_t copied_len = 0;
for (auto b = blocks; b; b = b->next) {
memcpy(raw_buf + copied_len, b->start(), b->size());
copied_len += b->size();
}
uint8_t dcil = 0;
uint8_t scil = 0;
QUICInvariants::dcil(dcil, raw_buf, len);
QUICInvariants::scil(scil, raw_buf, len);
size_t offset = LONG_HDR_OFFSET_CONNECTION_ID;
this->_dcid = {raw_buf + offset, dcil};
offset += dcil + 1;
this->_scid = {raw_buf + offset, scil};
offset += scil;
// Retry Token field
this->_token = new QUICRetryToken(raw_buf + offset, len - offset - QUICRetryIntegrityTag::LEN);
offset += this->_token->length();
// Retry Integrity Tag
memcpy(this->_integrity_tag, raw_buf + offset, QUICRetryIntegrityTag::LEN);
this->_header_block = concatenated_block->clone();
this->_header_block->_end = this->_header_block->_start + offset;
this->_header_block->next = nullptr;
this->_payload_block = concatenated_block->clone();
this->_payload_block->_start = this->_payload_block->_start + offset;
this->_payload_block_without_tag = this->_payload_block->clone();
this->_payload_block_without_tag->_end = this->_payload_block_without_tag->_end - QUICRetryIntegrityTag::LEN;
}
QUICRetryPacketR::~QUICRetryPacketR()
{
delete this->_token;
}
Ptr<IOBufferBlock>
QUICRetryPacketR::header_block() const
{
return this->_header_block;
}
Ptr<IOBufferBlock>
QUICRetryPacketR::payload_block() const
{
return this->_payload_block;
}
QUICPacketType
QUICRetryPacketR::type() const
{
return QUICPacketType::RETRY;
}
QUICPacketNumber
QUICRetryPacketR::packet_number() const
{
return 0;
}
const QUICAddressValidationToken &
QUICRetryPacketR::token() const
{
return *(this->_token);
}
bool
QUICRetryPacketR::has_valid_tag(QUICConnectionId &odcid) const
{
uint8_t tag_computed[QUICRetryIntegrityTag::LEN];
QUICRetryIntegrityTag::compute(tag_computed, odcid, this->_header_block, this->_payload_block_without_tag);
return memcmp(this->_integrity_tag, tag_computed, QUICRetryIntegrityTag::LEN) == 0;
}