blob: 7af9a7a11b5a159e7612d1791ca7b3318e89cb33 [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 "QUICFrame.h"
#include <algorithm>
#include "QUICStream.h"
#include "QUICIntUtil.h"
#include "QUICDebugNames.h"
#include "QUICPacket.h"
#define LEFT_SPACE(pos) ((size_t)(buf + len - pos))
#define FRAME_SIZE(pos) (pos - buf)
// the pos will auto move forward . return true if the data valid
static bool
read_varint(uint8_t *&pos, size_t len, uint64_t &field, size_t &field_len)
{
if (len < 1) {
return false;
}
field_len = QUICVariableInt::size(pos);
if (len < field_len) {
return false;
}
field = QUICIntUtil::read_QUICVariableInt(pos, len);
pos += field_len;
return true;
}
QUICFrameType
QUICFrame::type() const
{
ink_assert("should not be called");
return QUICFrameType::UNKNOWN;
}
bool
QUICFrame::ack_eliciting() const
{
auto type = this->type();
return type != QUICFrameType::PADDING && type != QUICFrameType::ACK && type != QUICFrameType::CONNECTION_CLOSE;
}
const QUICPacketR *
QUICFrame::packet() const
{
return this->_packet;
}
bool
QUICFrame::is_probing_frame() const
{
return false;
}
bool
QUICFrame::is_flow_controlled() const
{
return false;
}
QUICFrameId
QUICFrame::id() const
{
return this->_id;
}
QUICFrameGenerator *
QUICFrame::generated_by()
{
return this->_owner;
}
QUICFrameType
QUICFrame::type(const uint8_t *buf)
{
if (buf[0] >= static_cast<uint8_t>(QUICFrameType::UNKNOWN)) {
return QUICFrameType::UNKNOWN;
} else if (static_cast<uint8_t>(QUICFrameType::ACK) <= buf[0] && buf[0] < static_cast<uint8_t>(QUICFrameType::RESET_STREAM)) {
return QUICFrameType::ACK;
} else if (static_cast<uint8_t>(QUICFrameType::STREAM) <= buf[0] && buf[0] < static_cast<uint8_t>(QUICFrameType::MAX_DATA)) {
return QUICFrameType::STREAM;
} else if (static_cast<uint8_t>(QUICFrameType::MAX_STREAMS) <= buf[0] &&
buf[0] < static_cast<uint8_t>(QUICFrameType::DATA_BLOCKED)) {
return QUICFrameType::MAX_STREAMS;
} else if (static_cast<uint8_t>(QUICFrameType::STREAMS_BLOCKED) <= buf[0] &&
buf[0] < static_cast<uint8_t>(QUICFrameType::NEW_CONNECTION_ID)) {
return QUICFrameType::STREAMS_BLOCKED;
} else if (static_cast<uint8_t>(QUICFrameType::CONNECTION_CLOSE) <= buf[0] &&
buf[0] < static_cast<uint8_t>(QUICFrameType::HANDSHAKE_DONE)) {
return QUICFrameType::CONNECTION_CLOSE;
} else {
return static_cast<QUICFrameType>(buf[0]);
}
}
int
QUICFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "%s size=%zu", QUICDebugNames::frame_type(this->type()), this->size());
}
bool
QUICFrame::valid() const
{
return this->_valid;
}
//
// STREAM Frame
//
QUICStreamFrame::QUICStreamFrame(Ptr<IOBufferBlock> &block, QUICStreamId stream_id, QUICOffset offset, bool last,
bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner)
: QUICFrame(id, owner),
_block(block),
_stream_id(stream_id),
_offset(offset),
_fin(last),
_has_offset_field(has_offset_field),
_has_length_field(has_length_field)
{
}
QUICStreamFrame::QUICStreamFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
QUICStreamFrame::QUICStreamFrame(const QUICStreamFrame &o)
: QUICFrame(o),
_block(make_ptr<IOBufferBlock>(o._block->clone())),
_stream_id(o._stream_id),
_offset(o._offset),
_fin(o._fin),
_has_offset_field(o._has_offset_field),
_has_length_field(o._has_length_field)
{
}
void
QUICStreamFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf);
this->_has_offset_field = (buf[0] & 0x04) != 0; // "O" of "0b00010OLF"
this->_has_length_field = (buf[0] & 0x02) != 0; // "L" of "0b00010OLF"
this->_fin = (buf[0] & 0x01) != 0; // "F" of "0b00010OLF"
pos += 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) {
return;
}
if (this->_has_offset_field && !read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) {
return;
}
uint64_t data_len = 0;
if (this->_has_length_field && !read_varint(pos, LEFT_SPACE(pos), data_len, field_len)) {
return;
}
if (!this->_has_length_field) {
data_len = LEFT_SPACE(pos);
}
if (LEFT_SPACE(pos) < data_len) {
return;
}
this->_valid = true;
this->_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
this->_block->alloc(BUFFER_SIZE_INDEX_32K);
ink_assert(static_cast<uint64_t>(this->_block->write_avail()) > data_len);
memcpy(this->_block->start(), pos, data_len);
this->_block->fill(data_len);
pos += data_len;
this->_size = FRAME_SIZE(pos);
}
void
QUICStreamFrame::_reset()
{
this->_block = nullptr;
this->_fin = false;
this->_has_length_field = true;
this->_has_offset_field = true;
this->_offset = 0;
this->_stream_id = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
QUICFrameType
QUICStreamFrame::type() const
{
return QUICFrameType::STREAM;
}
size_t
QUICStreamFrame::size() const
{
if (this->_size) {
return this->_size;
}
size_t size = 1;
size_t data_len = 0;
if (this->_block.get() != nullptr) {
data_len = this->_block->read_avail();
}
size += QUICVariableInt::size(this->_stream_id);
if (this->_has_offset_field) {
size += QUICVariableInt::size(this->_offset);
}
if (this->_has_length_field) {
size += QUICVariableInt::size(data_len);
size += data_len;
}
return size;
}
bool
QUICStreamFrame::is_flow_controlled() const
{
return true;
}
int
QUICStreamFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "STREAM size=%zu id=%" PRIu64 " offset=%" PRIu64 " data_len=%" PRIu64 " fin=%d", this->size(),
this->stream_id(), this->offset(), this->data_length(), this->has_fin_flag());
}
Ptr<IOBufferBlock>
QUICStreamFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> header;
if (limit < this->size()) {
return header;
}
// Create header block
size_t written_len = 0;
header = make_ptr<IOBufferBlock>(new_IOBufferBlock());
header->alloc(iobuffer_size_to_index(MAX_HEADER_SIZE, BUFFER_SIZE_INDEX_32K));
this->_store_header(reinterpret_cast<uint8_t *>(header->start()), &written_len, true);
header->fill(written_len);
// Append payload block to a chain
ink_assert(written_len + this->data_length() <= limit);
header->next = this->data();
// Return the chain
return header;
}
size_t
QUICStreamFrame::_store_header(uint8_t *buf, size_t *len, bool include_length_field) const
{
// Build Frame Type: "0b0010OLF"
buf[0] = static_cast<uint8_t>(QUICFrameType::STREAM);
*len = 1;
size_t n;
// Stream ID (i)
QUICTypeUtil::write_QUICStreamId(this->stream_id(), buf + *len, &n);
*len += n;
// [Offset (i)] "O" of "0b0010OLF"
if (this->has_offset_field()) {
QUICTypeUtil::write_QUICOffset(this->offset(), buf + *len, &n);
*len += n;
buf[0] += 0x04;
}
// [Length (i)] "L of "0b0010OLF"
if (include_length_field) {
QUICIntUtil::write_QUICVariableInt(this->data_length(), buf + *len, &n);
*len += n;
buf[0] += 0x02;
}
// "F" of "0b0010OLF"
if (this->has_fin_flag()) {
buf[0] += 0x01;
}
return *len;
}
QUICStreamId
QUICStreamFrame::stream_id() const
{
return this->_stream_id;
}
QUICOffset
QUICStreamFrame::offset() const
{
if (this->has_offset_field()) {
return this->_offset;
}
return 0;
}
uint64_t
QUICStreamFrame::data_length() const
{
return this->_block->read_avail();
}
IOBufferBlock *
QUICStreamFrame::data() const
{
return this->_block.get();
}
/**
* "O" of "0b00010OLF"
*/
bool
QUICStreamFrame::has_offset_field() const
{
return this->_has_offset_field;
}
/**
* "L" of "0b00010OLF"
*/
bool
QUICStreamFrame::has_length_field() const
{
// This depends on `include_length_field` arg of QUICStreamFrame::store.
// Returning true for just in case.
return this->_has_length_field;
}
/**
* "F" of "0b00010OLF"
*/
bool
QUICStreamFrame::has_fin_flag() const
{
return this->_fin;
}
//
// CRYPTO frame
//
QUICCryptoFrame::QUICCryptoFrame(Ptr<IOBufferBlock> &block, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner)
: QUICFrame(id, owner), _offset(offset), _block(block)
{
}
QUICCryptoFrame::QUICCryptoFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
QUICCryptoFrame::QUICCryptoFrame(const QUICCryptoFrame &o)
: QUICFrame(o), _offset(o._offset), _block(make_ptr<IOBufferBlock>(o._block->clone()))
{
}
void
QUICCryptoFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) {
return;
}
uint64_t data_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), data_len, field_len)) {
return;
}
if (LEFT_SPACE(pos) < data_len) {
return;
}
this->_valid = true;
this->_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
this->_block->alloc(BUFFER_SIZE_INDEX_32K);
ink_assert(static_cast<uint64_t>(this->_block->write_avail()) > data_len);
memcpy(this->_block->start(), pos, data_len);
this->_block->fill(data_len);
pos += data_len;
this->_size = FRAME_SIZE(pos);
}
void
QUICCryptoFrame::_reset()
{
this->_block = nullptr;
this->_offset = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
// QUICFrame *
// QUICCryptoFrame::clone(uint8_t *buf) const
// {
// Ptr<IOBufferBlock> block = make_ptr<IOBufferBlock>(this->_block->clone());
// return QUICFrameFactory::create_crypto_frame(buf, block, this->offset(), this->_id, this->_owner);
// }
QUICFrameType
QUICCryptoFrame::type() const
{
return QUICFrameType::CRYPTO;
}
size_t
QUICCryptoFrame::size() const
{
if (this->_size) {
return this->_size;
}
return 1 + this->_block->read_avail() + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_block->read_avail());
}
int
QUICCryptoFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "CRYPTO size=%zu offset=%" PRIu64 " data_len=%" PRIu64, this->size(), this->offset(),
this->data_length());
}
Ptr<IOBufferBlock>
QUICCryptoFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> header;
if (limit < this->size()) {
return header;
}
// Create header block
size_t written_len = 0;
header = make_ptr<IOBufferBlock>(new_IOBufferBlock());
header->alloc(iobuffer_size_to_index(MAX_HEADER_SIZE, BUFFER_SIZE_INDEX_32K));
this->_store_header(reinterpret_cast<uint8_t *>(header->start()), &written_len);
header->fill(written_len);
// Append payload block to a chain
ink_assert(written_len + this->data_length() <= limit);
header->next = this->data();
// Return the chain
return header;
}
size_t
QUICCryptoFrame::_store_header(uint8_t *buf, size_t *len) const
{
// Type
buf[0] = static_cast<uint8_t>(QUICFrameType::CRYPTO);
*len = 1;
size_t n;
// Offset (i)
QUICTypeUtil::write_QUICOffset(this->offset(), buf + *len, &n);
*len += n;
// Length (i)
QUICIntUtil::write_QUICVariableInt(this->data_length(), buf + *len, &n);
*len += n;
return *len;
}
QUICOffset
QUICCryptoFrame::offset() const
{
return this->_offset;
}
uint64_t
QUICCryptoFrame::data_length() const
{
return this->_block->read_avail();
}
IOBufferBlock *
QUICCryptoFrame::data() const
{
return this->_block.get();
}
//
// ACK frame
//
std::set<QUICAckFrame::PacketNumberRange>
QUICAckFrame::ranges() const
{
std::set<QUICAckFrame::PacketNumberRange> numbers;
QUICPacketNumber x = this->largest_acknowledged();
numbers.insert({x, static_cast<uint64_t>(x) - this->ack_block_section()->first_ack_block()});
x -= this->ack_block_section()->first_ack_block() + 1;
for (auto &&block : *(this->ack_block_section())) {
x -= block.gap() + 1;
numbers.insert({x, static_cast<uint64_t>(x) - block.length()});
x -= block.length() + 1;
}
return numbers;
}
QUICAckFrame::QUICAckFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICAckFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
bool has_ecn = (buf[0] == static_cast<uint8_t>(QUICFrameType::ACK_WITH_ECN));
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_largest_acknowledged, field_len)) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_ack_delay, field_len)) {
return;
}
uint64_t ack_block_count = 0;
if (!read_varint(pos, LEFT_SPACE(pos), ack_block_count, field_len)) {
return;
}
uint64_t first_ack_block = 0;
if (!read_varint(pos, LEFT_SPACE(pos), first_ack_block, field_len)) {
return;
}
this->_ack_block_section = new AckBlockSection(first_ack_block);
for (size_t i = 0; i < ack_block_count; i++) {
uint64_t gap = 0;
uint64_t add_ack_block = 0;
if (!read_varint(pos, LEFT_SPACE(pos), gap, field_len)) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), add_ack_block, field_len)) {
return;
}
this->_ack_block_section->add_ack_block({gap, add_ack_block});
}
if (has_ecn) {
this->_ecn_section = new EcnSection(pos, LEFT_SPACE(pos));
if (!this->_ecn_section->valid()) {
return;
}
pos += this->_ecn_section->size();
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
QUICAckFrame::QUICAckFrame(QUICPacketNumber largest_acknowledged, uint64_t ack_delay, uint64_t first_ack_block, QUICFrameId id,
QUICFrameGenerator *owner)
: QUICFrame(id, owner)
{
this->_largest_acknowledged = largest_acknowledged;
this->_ack_delay = ack_delay;
this->_ack_block_section = new AckBlockSection(first_ack_block);
}
void
QUICAckFrame::_reset()
{
if (this->_ack_block_section) {
delete this->_ack_block_section;
this->_ack_block_section = nullptr;
}
if (this->_ecn_section) {
delete this->_ecn_section;
this->_ecn_section = nullptr;
}
this->_largest_acknowledged = 0;
this->_ack_delay = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
QUICAckFrame::~QUICAckFrame()
{
if (this->_ack_block_section) {
delete this->_ack_block_section;
this->_ack_block_section = nullptr;
}
if (this->_ecn_section) {
delete this->_ecn_section;
this->_ecn_section = nullptr;
}
}
QUICFrameType
QUICAckFrame::type() const
{
// TODO ECN
return QUICFrameType::ACK;
}
size_t
QUICAckFrame::size() const
{
if (this->_size) {
return this->_size;
}
size_t pre_len = 1 + QUICVariableInt::size(this->_largest_acknowledged) + QUICVariableInt::size(this->_ack_delay) +
QUICVariableInt::size(this->_ack_block_section->count());
if (this->_ack_block_section) {
pre_len += this->_ack_block_section->size();
}
if (this->_ecn_section) {
return pre_len + this->_ecn_section->size();
}
return pre_len;
}
Ptr<IOBufferBlock>
QUICAckFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + 24, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::ACK);
n += 1;
// Largest Acknowledged (i)
QUICIntUtil::write_QUICVariableInt(this->_largest_acknowledged, block_start + n, &written_len);
n += written_len;
// Ack Delay (i)
QUICIntUtil::write_QUICVariableInt(this->_ack_delay, block_start + n, &written_len);
n += written_len;
// Ack Range Count (i)
QUICIntUtil::write_QUICVariableInt(this->ack_block_count(), block_start + n, &written_len);
n += written_len;
block->fill(n);
// First Ack Range (i) + Ack Ranges (*)
block->next = this->_ack_block_section->to_io_buffer_block(limit - n);
return block;
}
int
QUICAckFrame::debug_msg(char *msg, size_t msg_len) const
{
int len = snprintf(msg, msg_len, "ACK size=%zu largest_acked=%" PRIu64 " delay=%" PRIu64 " block_count=%" PRIu64, this->size(),
this->largest_acknowledged(), this->ack_delay(), this->ack_block_count());
msg_len -= len;
if (this->ack_block_section()) {
len += snprintf(msg + len, msg_len, " first_ack_block=%" PRIu64, this->ack_block_section()->first_ack_block());
}
return len;
}
QUICPacketNumber
QUICAckFrame::largest_acknowledged() const
{
return this->_largest_acknowledged;
}
uint64_t
QUICAckFrame::ack_delay() const
{
return this->_ack_delay;
}
uint64_t
QUICAckFrame::ack_block_count() const
{
return this->_ack_block_section->count();
}
QUICAckFrame::AckBlockSection *
QUICAckFrame::ack_block_section()
{
return this->_ack_block_section;
}
const QUICAckFrame::AckBlockSection *
QUICAckFrame::ack_block_section() const
{
return this->_ack_block_section;
}
QUICAckFrame::EcnSection *
QUICAckFrame::ecn_section()
{
return this->_ecn_section;
}
const QUICAckFrame::EcnSection *
QUICAckFrame::ecn_section() const
{
return this->_ecn_section;
}
//
// QUICAckFrame::PacketNumberRange
//
QUICAckFrame::PacketNumberRange::PacketNumberRange(PacketNumberRange &&a) noexcept
{
this->_first = a._first;
this->_last = a._last;
}
uint64_t
QUICAckFrame::PacketNumberRange::first() const
{
return this->_first;
}
uint64_t
QUICAckFrame::PacketNumberRange::last() const
{
return this->_last;
}
uint64_t
QUICAckFrame::PacketNumberRange::size() const
{
return this->_first - this->_last;
}
bool
QUICAckFrame::PacketNumberRange::contains(QUICPacketNumber x) const
{
return static_cast<uint64_t>(this->_last) <= static_cast<uint64_t>(x) &&
static_cast<uint64_t>(x) <= static_cast<uint64_t>(this->_first);
}
//
// QUICAckFrame::AckBlock
//
uint64_t
QUICAckFrame::AckBlock::gap() const
{
return this->_gap;
}
uint64_t
QUICAckFrame::AckBlock::length() const
{
return this->_length;
}
size_t
QUICAckFrame::AckBlock::size() const
{
return QUICVariableInt::size(this->_gap) + QUICVariableInt::size(this->_length);
}
//
// QUICAckFrame::AckBlockSection
//
uint8_t
QUICAckFrame::AckBlockSection::count() const
{
return this->_ack_blocks.size();
}
size_t
QUICAckFrame::AckBlockSection::size() const
{
size_t n = 0;
n += QUICVariableInt::size(this->_first_ack_block);
for (auto &&block : *this) {
n += block.size();
}
return n;
}
Ptr<IOBufferBlock>
QUICAckFrame::AckBlockSection::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(limit, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
QUICIntUtil::write_QUICVariableInt(this->_first_ack_block, block_start + n, &written_len);
n += written_len;
for (auto &&block : *this) {
QUICIntUtil::write_QUICVariableInt(block.gap(), block_start + n, &written_len);
n += written_len;
QUICIntUtil::write_QUICVariableInt(block.length(), block_start + n, &written_len);
n += written_len;
}
block->fill(n);
return block;
}
uint64_t
QUICAckFrame::AckBlockSection::first_ack_block() const
{
return this->_first_ack_block;
}
void
QUICAckFrame::AckBlockSection::add_ack_block(const AckBlock &block)
{
this->_ack_blocks.push_back(block);
}
QUICAckFrame::AckBlockSection::const_iterator
QUICAckFrame::AckBlockSection::begin() const
{
return const_iterator(0, &this->_ack_blocks);
}
QUICAckFrame::AckBlockSection::const_iterator
QUICAckFrame::AckBlockSection::end() const
{
return const_iterator(this->_ack_blocks.size(), &this->_ack_blocks);
}
QUICAckFrame::AckBlockSection::const_iterator::const_iterator(uint8_t index, const std::vector<QUICAckFrame::AckBlock> *ack_blocks)
: _index(index), _ack_blocks(ack_blocks)
{
if (this->_ack_blocks->size()) {
if (this->_ack_blocks->size() == this->_index) {
this->_current_block = {UINT64_C(0), UINT64_C(0)};
} else {
this->_current_block = this->_ack_blocks->at(this->_index);
}
}
}
// FIXME: something wrong with clang-format?
const QUICAckFrame::AckBlock &
QUICAckFrame::AckBlockSection::const_iterator::operator++()
{
++(this->_index);
if (this->_ack_blocks->size() == this->_index) {
this->_current_block = {UINT64_C(0), UINT64_C(0)};
} else {
this->_current_block = this->_ack_blocks->at(this->_index);
}
return this->_current_block;
}
const bool
QUICAckFrame::AckBlockSection::const_iterator::operator!=(const const_iterator &ite) const
{
return this->_index != ite._index;
}
const bool
QUICAckFrame::AckBlockSection::const_iterator::operator==(const const_iterator &ite) const
{
return this->_index == ite._index;
}
QUICAckFrame::EcnSection::EcnSection(const uint8_t *buf, size_t len)
{
uint8_t *pos = const_cast<uint8_t *>(buf);
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_ect0_count, field_len)) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_ect1_count, field_len)) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_ecn_ce_count, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
bool
QUICAckFrame::EcnSection::valid() const
{
return this->_valid;
}
size_t
QUICAckFrame::EcnSection::size() const
{
return QUICVariableInt::size(this->_ect0_count) + QUICVariableInt::size(this->_ect1_count) +
QUICVariableInt::size(this->_ecn_ce_count);
}
uint64_t
QUICAckFrame::EcnSection::ect0_count() const
{
return this->_ect0_count;
}
uint64_t
QUICAckFrame::EcnSection::ect1_count() const
{
return this->_ect1_count;
}
uint64_t
QUICAckFrame::EcnSection::ecn_ce_count() const
{
return this->_ecn_ce_count;
}
//
// RESET_STREAM frame
//
QUICRstStreamFrame::QUICRstStreamFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICOffset final_offset, QUICFrameId id,
QUICFrameGenerator *owner)
: QUICFrame(id, owner), _stream_id(stream_id), _error_code(error_code), _final_offset(final_offset)
{
}
QUICRstStreamFrame::QUICRstStreamFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICRstStreamFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = 1 + const_cast<uint8_t *>(buf);
size_t field_len = 0;
// Stream ID (i)
if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) {
return;
}
// Error Code (i)
if (LEFT_SPACE(pos) < 1) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_error_code, field_len)) {
return;
}
// Final Offset (i)
if (!read_varint(pos, LEFT_SPACE(pos), this->_final_offset, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
void
QUICRstStreamFrame::_reset()
{
this->_stream_id = 0;
this->_error_code = 0;
this->_final_offset = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
QUICFrameType
QUICRstStreamFrame::type() const
{
return QUICFrameType::RESET_STREAM;
}
size_t
QUICRstStreamFrame::size() const
{
if (this->_size) {
return this->_size;
}
return 1 + QUICVariableInt::size(this->_stream_id) + QUICVariableInt::size(this->_error_code) +
QUICVariableInt::size(this->_final_offset);
}
Ptr<IOBufferBlock>
QUICRstStreamFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + 24, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::RESET_STREAM);
n += 1;
// Stream ID (i)
QUICTypeUtil::write_QUICStreamId(this->_stream_id, block_start + n, &written_len);
n += written_len;
// Application Error Code (i)
QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, block_start + n, &written_len);
n += written_len;
// Final Size (i)
QUICTypeUtil::write_QUICOffset(this->_final_offset, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
int
QUICRstStreamFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "RESET_STREAM size=%zu stream_id=%" PRIu64 " code=0x%" PRIx64, this->size(), this->stream_id(),
this->error_code());
}
QUICStreamId
QUICRstStreamFrame::stream_id() const
{
return this->_stream_id;
}
QUICAppErrorCode
QUICRstStreamFrame::error_code() const
{
return this->_error_code;
}
QUICOffset
QUICRstStreamFrame::final_offset() const
{
return this->_final_offset;
}
//
// PING frame
//
QUICPingFrame::QUICPingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICPingFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
this->_reset();
this->_packet = packet;
this->_valid = true;
this->_size = 1;
}
QUICFrameType
QUICPingFrame::type() const
{
return QUICFrameType::PING;
}
size_t
QUICPingFrame::size() const
{
return 1;
}
Ptr<IOBufferBlock>
QUICPingFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(this->size(), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::PING);
n += 1;
block->fill(n);
return block;
}
//
// PADDING frame
//
QUICPaddingFrame::QUICPaddingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICPaddingFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
this->_size = 0;
this->_valid = true;
// find out how many padding frames in this buf
for (size_t i = 0; i < len; i++) {
if (*(buf + i) == static_cast<uint8_t>(QUICFrameType::PADDING)) {
++this->_size;
} else {
break;
}
}
}
QUICFrameType
QUICPaddingFrame::type() const
{
return QUICFrameType::PADDING;
}
size_t
QUICPaddingFrame::size() const
{
return this->_size;
}
bool
QUICPaddingFrame::is_probing_frame() const
{
return true;
}
Ptr<IOBufferBlock>
QUICPaddingFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(this->_size, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
memset(block_start, 0, this->_size);
n = this->_size;
block->fill(n);
return block;
}
//
// CONNECTION_CLOSE frame
//
QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint64_t error_code, QUICFrameType frame_type, uint64_t reason_phrase_length,
const char *reason_phrase, QUICFrameId id, QUICFrameGenerator *owner)
: QUICFrame(id, owner),
_type(0x1c),
_error_code(error_code),
_frame_type(frame_type),
_reason_phrase_length(reason_phrase_length),
_reason_phrase(reason_phrase)
{
}
QUICConnectionCloseFrame::QUICConnectionCloseFrame(uint64_t error_code, uint64_t reason_phrase_length, const char *reason_phrase,
QUICFrameId id, QUICFrameGenerator *owner)
: QUICFrame(id, owner),
_type(0x1d),
_error_code(error_code),
_reason_phrase_length(reason_phrase_length),
_reason_phrase(reason_phrase)
{
}
QUICConnectionCloseFrame::QUICConnectionCloseFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICConnectionCloseFrame::_reset()
{
this->_error_code = 0;
this->_reason_phrase_length = 0;
this->_reason_phrase = nullptr;
this->_frame_type = QUICFrameType::UNKNOWN;
this->_owner = nullptr;
this->_id = 0;
this->_size = 0;
this->_valid = false;
}
void
QUICConnectionCloseFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
this->_type = buf[0];
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
uint64_t field = 0;
// Error Code (i)
if (LEFT_SPACE(pos) < 1) {
return;
}
read_varint(pos, LEFT_SPACE(pos), field, field_len);
this->_error_code = field;
if (this->_type == 0x1c) {
// Frame Type (i)
if (!read_varint(pos, LEFT_SPACE(pos), field, field_len)) {
return;
}
this->_frame_type = static_cast<QUICFrameType>(field);
/**
Frame Type Field Accessor
PADDING frame in Frame Type field means frame type that triggered the error is unknown.
Return QUICFrameType::UNKNOWN when Frame Type field is PADDING (0x0).
*/
if (this->_frame_type == QUICFrameType::PADDING) {
this->_frame_type = QUICFrameType::UNKNOWN;
}
}
// Reason Phrase Length (i)
if (LEFT_SPACE(pos) < 1) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_reason_phrase_length, field_len)) {
return;
}
// Reason Phrase
if (LEFT_SPACE(pos) < this->_reason_phrase_length) {
return;
}
this->_reason_phrase = reinterpret_cast<const char *>(pos);
this->_valid = true;
pos += this->_reason_phrase_length;
this->_size = FRAME_SIZE(pos);
}
QUICFrameType
QUICConnectionCloseFrame::type() const
{
return QUICFrameType::CONNECTION_CLOSE;
}
size_t
QUICConnectionCloseFrame::size() const
{
if (this->_size) {
return this->_size;
}
return 1 + QUICVariableInt::size(sizeof(QUICTransErrorCode)) + QUICVariableInt::size(sizeof(QUICFrameType)) +
QUICVariableInt::size(this->_reason_phrase_length) + this->_reason_phrase_length;
}
/**
Store CONNECTION_CLOSE frame in buffer.
PADDING frame in Frame Type field means frame type that triggered the error is unknown.
When `_frame_type` is QUICFrameType::UNKNOWN, it's converted to QUICFrameType::PADDING (0x0).
*/
Ptr<IOBufferBlock>
QUICConnectionCloseFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> first_block;
size_t n = 0;
if (limit < this->size()) {
return first_block;
}
// Create a block for Error Code(i) and Frame Type(i)
size_t written_len = 0;
first_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
first_block->alloc(iobuffer_size_to_index(1 + 24, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(first_block->start());
// Type
block_start[0] = this->_type;
n += 1;
// Error Code (i)
QUICIntUtil::write_QUICVariableInt(this->_error_code, block_start + n, &written_len);
n += written_len;
// Frame Type (i)
QUICFrameType frame_type = this->_frame_type;
if (frame_type == QUICFrameType::UNKNOWN) {
frame_type = QUICFrameType::PADDING;
}
QUICIntUtil::write_QUICVariableInt(static_cast<uint64_t>(frame_type), block_start + n, &written_len);
n += written_len;
// Reason Phrase Length (i)
QUICIntUtil::write_QUICVariableInt(this->_reason_phrase_length, block_start + n, &written_len);
n += written_len;
first_block->fill(n);
// Create a block for reason if necessary
if (this->_reason_phrase_length != 0) {
// Reason Phrase (*)
Ptr<IOBufferBlock> reason_block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
reason_block->alloc(iobuffer_size_to_index(this->_reason_phrase_length, BUFFER_SIZE_INDEX_32K));
memcpy(reinterpret_cast<uint8_t *>(reason_block->start()), this->_reason_phrase, this->_reason_phrase_length);
reason_block->fill(this->_reason_phrase_length);
// Append reason block to the first block
first_block->next = reason_block;
}
// Return the chain
return first_block;
}
int
QUICConnectionCloseFrame::debug_msg(char *msg, size_t msg_len) const
{
int len;
if (this->_type == 0x1c) {
len =
snprintf(msg, msg_len, "CONNECTION_CLOSE size=%zu code=%s (0x%" PRIx16 ") frame=%s", this->size(),
QUICDebugNames::error_code(this->error_code()), this->error_code(), QUICDebugNames::frame_type(this->frame_type()));
} else {
// Application-specific error. It doesn't have a frame type and we don't know string representations of error codes.
len = snprintf(msg, msg_len, "CONNECTION_CLOSE size=%zu code=0x%" PRIx16 " ", this->size(), this->error_code());
}
if (this->reason_phrase_length() != 0 && this->reason_phrase() != nullptr) {
memcpy(msg + len, " reason=", 8);
len += 8;
int phrase_len = std::min(msg_len - len, static_cast<size_t>(this->reason_phrase_length()));
memcpy(msg + len, this->reason_phrase(), phrase_len);
len += phrase_len;
msg[len] = '\0';
++len;
}
return len;
}
uint16_t
QUICConnectionCloseFrame::error_code() const
{
return this->_error_code;
}
QUICFrameType
QUICConnectionCloseFrame::frame_type() const
{
return this->_frame_type;
}
uint64_t
QUICConnectionCloseFrame::reason_phrase_length() const
{
return this->_reason_phrase_length;
}
const char *
QUICConnectionCloseFrame::reason_phrase() const
{
return this->_reason_phrase;
}
//
// MAX_DATA frame
//
QUICMaxDataFrame::QUICMaxDataFrame(uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner) : QUICFrame(id, owner)
{
this->_maximum_data = maximum_data;
}
void
QUICMaxDataFrame::_reset()
{
this->_maximum_data = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
QUICMaxDataFrame::QUICMaxDataFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICMaxDataFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = 1 + const_cast<uint8_t *>(buf);
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_data, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
QUICFrameType
QUICMaxDataFrame::type() const
{
return QUICFrameType::MAX_DATA;
}
size_t
QUICMaxDataFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_data);
}
Ptr<IOBufferBlock>
QUICMaxDataFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(size_t), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::MAX_DATA);
n += 1;
// Maximum Data (i)
QUICTypeUtil::write_QUICMaxData(this->_maximum_data, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
int
QUICMaxDataFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "MAX_DATA size=%zu maximum=%" PRIu64, this->size(), this->maximum_data());
}
uint64_t
QUICMaxDataFrame::maximum_data() const
{
return this->_maximum_data;
}
//
// MAX_STREAM_DATA
//
QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(QUICStreamId stream_id, uint64_t maximum_stream_data, QUICFrameId id,
QUICFrameGenerator *owner)
: QUICFrame(id, owner)
{
this->_stream_id = stream_id;
this->_maximum_stream_data = maximum_stream_data;
}
void
QUICMaxStreamDataFrame::_reset()
{
this->_stream_id = 0;
this->_maximum_stream_data = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
QUICMaxStreamDataFrame::QUICMaxStreamDataFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICMaxStreamDataFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_stream_data, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
QUICFrameType
QUICMaxStreamDataFrame::type() const
{
return QUICFrameType::MAX_STREAM_DATA;
}
size_t
QUICMaxStreamDataFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_stream_data) + QUICVariableInt::size(this->_stream_id);
}
Ptr<IOBufferBlock>
QUICMaxStreamDataFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(uint64_t) + sizeof(size_t), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::MAX_STREAM_DATA);
n += 1;
// Stream ID (i)
QUICTypeUtil::write_QUICStreamId(this->_stream_id, block_start + n, &written_len);
n += written_len;
// Maximum Stream Data (i)
QUICTypeUtil::write_QUICMaxData(this->_maximum_stream_data, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
int
QUICMaxStreamDataFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "MAX_STREAM_DATA size=%zu id=%" PRIu64 " maximum=%" PRIu64, this->size(), this->stream_id(),
this->maximum_stream_data());
}
QUICStreamId
QUICMaxStreamDataFrame::stream_id() const
{
return this->_stream_id;
}
uint64_t
QUICMaxStreamDataFrame::maximum_stream_data() const
{
return this->_maximum_stream_data;
}
//
// MAX_STREAMS
//
QUICMaxStreamsFrame::QUICMaxStreamsFrame(QUICStreamId maximum_streams, QUICFrameId id, QUICFrameGenerator *owner)
: QUICFrame(id, owner)
{
this->_maximum_streams = maximum_streams;
}
void
QUICMaxStreamsFrame::_reset()
{
this->_maximum_streams = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
QUICMaxStreamsFrame::QUICMaxStreamsFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICMaxStreamsFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_maximum_streams, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
QUICFrameType
QUICMaxStreamsFrame::type() const
{
return QUICFrameType::MAX_STREAMS;
}
size_t
QUICMaxStreamsFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_maximum_streams);
}
Ptr<IOBufferBlock>
QUICMaxStreamsFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(size_t), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::MAX_STREAMS);
n += 1;
// Maximum Streams (i)
QUICTypeUtil::write_QUICStreamId(this->_maximum_streams, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
uint64_t
QUICMaxStreamsFrame::maximum_streams() const
{
return this->_maximum_streams;
}
//
// DATA_BLOCKED frame
//
QUICDataBlockedFrame::QUICDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICDataBlockedFrame::_reset()
{
this->_offset = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
void
QUICDataBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
int
QUICDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "DATA_BLOCKED size=%zu offset=%" PRIu64, this->size(), this->offset());
}
QUICFrameType
QUICDataBlockedFrame::type() const
{
return QUICFrameType::DATA_BLOCKED;
}
size_t
QUICDataBlockedFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->offset());
}
Ptr<IOBufferBlock>
QUICDataBlockedFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(size_t), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::DATA_BLOCKED);
n += 1;
// Data Limit (i)
QUICTypeUtil::write_QUICOffset(this->_offset, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
QUICOffset
QUICDataBlockedFrame::offset() const
{
return this->_offset;
}
//
// STREAM_DATA_BLOCKED frame
//
QUICStreamDataBlockedFrame::QUICStreamDataBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICStreamDataBlockedFrame::_reset()
{
this->_stream_id = 0;
this->_offset = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
void
QUICStreamDataBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_offset, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
int
QUICStreamDataBlockedFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "STREAM_DATA_BLOCKED size=%zu id=%" PRIu64 " offset=%" PRIu64, this->size(), this->stream_id(),
this->offset());
}
QUICFrameType
QUICStreamDataBlockedFrame::type() const
{
return QUICFrameType::STREAM_DATA_BLOCKED;
}
size_t
QUICStreamDataBlockedFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_offset) + QUICVariableInt::size(this->_stream_id);
}
Ptr<IOBufferBlock>
QUICStreamDataBlockedFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(size_t), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::STREAM_DATA_BLOCKED);
n += 1;
// Stream ID (i)
QUICTypeUtil::write_QUICStreamId(this->_stream_id, block_start + n, &written_len);
n += written_len;
// Data Limit (i)
QUICTypeUtil::write_QUICOffset(this->_offset, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
QUICStreamId
QUICStreamDataBlockedFrame::stream_id() const
{
return this->_stream_id;
}
QUICOffset
QUICStreamDataBlockedFrame::offset() const
{
return this->_offset;
}
//
// STREAMS_BLOCKED frame
//
QUICStreamIdBlockedFrame::QUICStreamIdBlockedFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICStreamIdBlockedFrame::_reset()
{
this->_stream_id = 0;
this->_owner = nullptr;
this->_id = 0;
this->_size = 0;
this->_valid = false;
}
void
QUICStreamIdBlockedFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
QUICFrameType
QUICStreamIdBlockedFrame::type() const
{
return QUICFrameType::STREAMS_BLOCKED;
}
size_t
QUICStreamIdBlockedFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_stream_id);
}
Ptr<IOBufferBlock>
QUICStreamIdBlockedFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(size_t), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::STREAMS_BLOCKED);
n += 1;
// Stream Limit (i)
QUICTypeUtil::write_QUICStreamId(this->_stream_id, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
QUICStreamId
QUICStreamIdBlockedFrame::stream_id() const
{
return this->_stream_id;
}
//
// NEW_CONNECTION_ID frame
//
QUICNewConnectionIdFrame::QUICNewConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICNewConnectionIdFrame::_reset()
{
this->_sequence = 0;
this->_retire_prior_to = 0;
this->_connection_id = QUICConnectionId::ZERO();
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
void
QUICNewConnectionIdFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
// Sequence Number (i)
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_sequence, field_len)) {
return;
}
// Retire Prior To (i)
if (LEFT_SPACE(pos) < 1) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_retire_prior_to, field_len)) {
return;
}
// Length (8)
if (LEFT_SPACE(pos) < 1) {
return;
}
size_t cid_len = *pos;
pos += 1;
// Connection ID (8..160)
if (LEFT_SPACE(pos) < cid_len) {
return;
}
this->_connection_id = QUICTypeUtil::read_QUICConnectionId(pos, cid_len);
pos += cid_len;
// Stateless Reset Token (128)
if (LEFT_SPACE(pos) < QUICStatelessResetToken::LEN) {
return;
}
this->_stateless_reset_token = QUICStatelessResetToken(pos);
this->_valid = true;
this->_size = FRAME_SIZE(pos) + QUICStatelessResetToken::LEN;
}
QUICFrameType
QUICNewConnectionIdFrame::type() const
{
return QUICFrameType::NEW_CONNECTION_ID;
}
size_t
QUICNewConnectionIdFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_sequence) + QUICVariableInt::size(this->_retire_prior_to) + 1 +
this->_connection_id.length() + QUICStatelessResetToken::LEN;
}
Ptr<IOBufferBlock>
QUICNewConnectionIdFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(uint64_t) + sizeof(uint64_t) + 1 + QUICConnectionId::MAX_LENGTH +
QUICStatelessResetToken::LEN,
BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::NEW_CONNECTION_ID);
n += 1;
// Sequence Number (i)
QUICIntUtil::write_QUICVariableInt(this->_sequence, block_start + n, &written_len);
n += written_len;
// Retire Prior To (i)
QUICIntUtil::write_QUICVariableInt(this->_retire_prior_to, block_start + n, &written_len);
n += written_len;
// Length (8)
*(block_start + n) = this->_connection_id.length();
n += 1;
// Connection ID (8..160)
QUICTypeUtil::write_QUICConnectionId(this->_connection_id, block_start + n, &written_len);
n += written_len;
// Stateless Reset Token (128)
memcpy(block_start + n, this->_stateless_reset_token.buf(), QUICStatelessResetToken::LEN);
n += QUICStatelessResetToken::LEN;
block->fill(n);
return block;
}
int
QUICNewConnectionIdFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "NEW_CONNECTION_ID size=%zu seq=%" PRIu64 " rpt=%" PRIu64 " cid=0x%s srt=%02x%02x%02x%02x",
this->size(), this->sequence(), this->retire_prior_to(), this->connection_id().hex().c_str(),
this->stateless_reset_token().buf()[0], this->stateless_reset_token().buf()[1],
this->stateless_reset_token().buf()[2], this->stateless_reset_token().buf()[3]);
}
uint64_t
QUICNewConnectionIdFrame::sequence() const
{
return this->_sequence;
}
uint64_t
QUICNewConnectionIdFrame::retire_prior_to() const
{
return this->_retire_prior_to;
}
QUICConnectionId
QUICNewConnectionIdFrame::connection_id() const
{
return this->_connection_id;
}
QUICStatelessResetToken
QUICNewConnectionIdFrame::stateless_reset_token() const
{
return this->_stateless_reset_token;
}
//
// STOP_SENDING frame
//
QUICStopSendingFrame::QUICStopSendingFrame(QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id,
QUICFrameGenerator *owner)
: QUICFrame(id, owner), _stream_id(stream_id), _error_code(error_code)
{
}
void
QUICStopSendingFrame::_reset()
{
this->_stream_id = 0;
this->_error_code = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
QUICStopSendingFrame::QUICStopSendingFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICStopSendingFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
// Stream ID (i)
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_stream_id, field_len)) {
return;
}
// Error Code (i)
if (LEFT_SPACE(pos) < 1) {
return;
}
if (!read_varint(pos, LEFT_SPACE(pos), this->_error_code, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
QUICFrameType
QUICStopSendingFrame::type() const
{
return QUICFrameType::STOP_SENDING;
}
size_t
QUICStopSendingFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_stream_id) + QUICVariableInt::size(sizeof(QUICAppErrorCode));
}
Ptr<IOBufferBlock>
QUICStopSendingFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + 24, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::STOP_SENDING);
n += 1;
// Stream ID (i)
QUICTypeUtil::write_QUICStreamId(this->_stream_id, block_start + n, &written_len);
n += written_len;
// Application Error Code (i)
QUICTypeUtil::write_QUICAppErrorCode(this->_error_code, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
QUICAppErrorCode
QUICStopSendingFrame::error_code() const
{
return this->_error_code;
}
QUICStreamId
QUICStopSendingFrame::stream_id() const
{
return this->_stream_id;
}
//
// PATH_CHALLENGE frame
//
QUICPathChallengeFrame::QUICPathChallengeFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICPathChallengeFrame::_reset()
{
this->_data = nullptr;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
void
QUICPathChallengeFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
if (LEFT_SPACE(pos) < QUICPathChallengeFrame::DATA_LEN) {
return;
}
this->_data = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN);
memcpy(this->_data.get(), pos, QUICPathChallengeFrame::DATA_LEN);
this->_valid = true;
this->_size = FRAME_SIZE(pos) + QUICPathChallengeFrame::DATA_LEN;
}
QUICFrameType
QUICPathChallengeFrame::type() const
{
return QUICFrameType::PATH_CHALLENGE;
}
size_t
QUICPathChallengeFrame::size() const
{
if (this->_size) {
return this->_size;
}
return 1 + QUICPathChallengeFrame::DATA_LEN;
}
bool
QUICPathChallengeFrame::is_probing_frame() const
{
return true;
}
Ptr<IOBufferBlock>
QUICPathChallengeFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + QUICPathChallengeFrame::DATA_LEN, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::PATH_CHALLENGE);
n += 1;
// Data (64)
memcpy(block_start + n, this->data(), QUICPathChallengeFrame::DATA_LEN);
n += QUICPathChallengeFrame::DATA_LEN;
block->fill(n);
return block;
}
int
QUICPathChallengeFrame::debug_msg(char *msg, size_t msg_len) const
{
auto data = this->data();
return snprintf(msg, msg_len, "PATH_CHALLENGE size=%zu data=0x%02x%02x%02x%02x%02x%02x%02x%02x", this->size(), data[0], data[1],
data[2], data[3], data[4], data[5], data[6], data[7]);
}
const uint8_t *
QUICPathChallengeFrame::data() const
{
return this->_data.get();
}
//
// PATH_RESPONSE frame
//
QUICPathResponseFrame::QUICPathResponseFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICPathResponseFrame::_reset()
{
this->_data = nullptr;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
Ptr<IOBufferBlock>
QUICPathResponseFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + QUICPathResponseFrame::DATA_LEN, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::PATH_RESPONSE);
n += 1;
// Data (64)
memcpy(block_start + n, this->data(), QUICPathChallengeFrame::DATA_LEN);
n += QUICPathChallengeFrame::DATA_LEN;
block->fill(n);
return block;
}
void
QUICPathResponseFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
if (LEFT_SPACE(pos) < QUICPathChallengeFrame::DATA_LEN) {
return;
}
this->_data = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN);
memcpy(this->_data.get(), pos, QUICPathChallengeFrame::DATA_LEN);
this->_valid = true;
this->_size = FRAME_SIZE(pos) + QUICPathChallengeFrame::DATA_LEN;
}
QUICFrameType
QUICPathResponseFrame::type() const
{
return QUICFrameType::PATH_RESPONSE;
}
size_t
QUICPathResponseFrame::size() const
{
return 1 + 8;
}
bool
QUICPathResponseFrame::is_probing_frame() const
{
return true;
}
int
QUICPathResponseFrame::debug_msg(char *msg, size_t msg_len) const
{
auto data = this->data();
return snprintf(msg, msg_len, "PATH_RESPONSE size=%zu data=0x%02x%02x%02x%02x%02x%02x%02x%02x", this->size(), data[0], data[1],
data[2], data[3], data[4], data[5], data[6], data[7]);
}
const uint8_t *
QUICPathResponseFrame::data() const
{
return this->_data.get();
}
//
// QUICNewTokenFrame
//
QUICNewTokenFrame::QUICNewTokenFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet) : QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICNewTokenFrame::_reset()
{
this->_token = nullptr;
this->_token_length = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
}
void
QUICNewTokenFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_token_length, field_len)) {
return;
}
if (LEFT_SPACE(pos) < this->_token_length) {
return;
}
this->_token = ats_unique_malloc(this->_token_length);
memcpy(this->_token.get(), pos, this->_token_length);
this->_valid = true;
this->_size = FRAME_SIZE(pos) + this->_token_length;
}
QUICFrameType
QUICNewTokenFrame::type() const
{
return QUICFrameType::NEW_TOKEN;
}
size_t
QUICNewTokenFrame::size() const
{
if (this->_size) {
return this->_size;
}
return 1 + QUICVariableInt::size(this->_token_length) + this->token_length();
}
Ptr<IOBufferBlock>
QUICNewTokenFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + 24, BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::NEW_TOKEN);
n += 1;
// Token Length (i)
QUICIntUtil::write_QUICVariableInt(this->_token_length, block_start + n, &written_len);
n += written_len;
// Token (*)
memcpy(block_start + n, this->token(), this->token_length());
n += this->token_length();
block->fill(n);
return block;
}
uint64_t
QUICNewTokenFrame::token_length() const
{
return this->_token_length;
}
const uint8_t *
QUICNewTokenFrame::token() const
{
return this->_token.get();
}
//
// RETIRE_CONNECTION_ID frame
//
QUICRetireConnectionIdFrame::QUICRetireConnectionIdFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICRetireConnectionIdFrame::_reset()
{
this->_seq_num = 0;
this->_owner = nullptr;
this->_id = 0;
this->_valid = false;
this->_size = 0;
this->_size = 0;
}
void
QUICRetireConnectionIdFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
ink_assert(len >= 1);
this->_reset();
this->_packet = packet;
uint8_t *pos = const_cast<uint8_t *>(buf) + 1;
size_t field_len = 0;
if (!read_varint(pos, LEFT_SPACE(pos), this->_seq_num, field_len)) {
return;
}
this->_valid = true;
this->_size = FRAME_SIZE(pos);
}
QUICFrameType
QUICRetireConnectionIdFrame::type() const
{
return QUICFrameType::RETIRE_CONNECTION_ID;
}
size_t
QUICRetireConnectionIdFrame::size() const
{
if (this->_size) {
return this->_size;
}
return sizeof(QUICFrameType) + QUICVariableInt::size(this->_seq_num);
}
Ptr<IOBufferBlock>
QUICRetireConnectionIdFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
size_t written_len = 0;
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(1 + sizeof(uint64_t), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::RETIRE_CONNECTION_ID);
n += 1;
// Sequence Number (i)
QUICIntUtil::write_QUICVariableInt(this->_seq_num, block_start + n, &written_len);
n += written_len;
block->fill(n);
return block;
}
int
QUICRetireConnectionIdFrame::debug_msg(char *msg, size_t msg_len) const
{
return snprintf(msg, msg_len, "RETIRE_CONNECTION_ID size=%zu seq_num=%" PRIu64, this->size(), this->seq_num());
}
uint64_t
QUICRetireConnectionIdFrame::seq_num() const
{
return this->_seq_num;
}
//
// HANDSHAKE_DONE frame
//
QUICHandshakeDoneFrame::QUICHandshakeDoneFrame(const uint8_t *buf, size_t len, const QUICPacketR *packet)
: QUICFrame(0, nullptr, packet)
{
this->parse(buf, len, packet);
}
void
QUICHandshakeDoneFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
this->_reset();
this->_packet = packet;
this->_valid = true;
this->_size = 1;
}
QUICFrameType
QUICHandshakeDoneFrame::type() const
{
return QUICFrameType::HANDSHAKE_DONE;
}
size_t
QUICHandshakeDoneFrame::size() const
{
return 1;
}
Ptr<IOBufferBlock>
QUICHandshakeDoneFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
size_t n = 0;
if (limit < this->size()) {
return block;
}
block = make_ptr<IOBufferBlock>(new_IOBufferBlock());
block->alloc(iobuffer_size_to_index(this->size(), BUFFER_SIZE_INDEX_32K));
uint8_t *block_start = reinterpret_cast<uint8_t *>(block->start());
// Type
block_start[0] = static_cast<uint8_t>(QUICFrameType::HANDSHAKE_DONE);
n += 1;
block->fill(n);
return block;
}
//
// UNKNOWN
//
QUICFrameType
QUICUnknownFrame::type() const
{
return QUICFrameType::UNKNOWN;
}
size_t
QUICUnknownFrame::size() const
{
// FIXME size should be readable
return 0;
}
Ptr<IOBufferBlock>
QUICUnknownFrame::to_io_buffer_block(size_t limit) const
{
Ptr<IOBufferBlock> block;
return block;
}
void
QUICUnknownFrame::parse(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
this->_packet = packet;
}
int
QUICUnknownFrame::debug_msg(char *msg, size_t msg_len) const
{
return 0;
}
//
// QUICFrameFactory
//
QUICFrame *
QUICFrameFactory::create(uint8_t *buf, const uint8_t *src, size_t len, const QUICPacketR *packet)
{
switch (QUICFrame::type(src)) {
case QUICFrameType::STREAM:
new (buf) QUICStreamFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::CRYPTO:
new (buf) QUICCryptoFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::ACK:
new (buf) QUICAckFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::PADDING:
new (buf) QUICPaddingFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::RESET_STREAM:
new (buf) QUICRstStreamFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::CONNECTION_CLOSE:
new (buf) QUICConnectionCloseFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::MAX_DATA:
new (buf) QUICMaxDataFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::MAX_STREAM_DATA:
new (buf) QUICMaxStreamDataFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::MAX_STREAMS:
new (buf) QUICMaxStreamsFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::PING:
new (buf) QUICPingFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::DATA_BLOCKED:
new (buf) QUICDataBlockedFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::STREAM_DATA_BLOCKED:
new (buf) QUICStreamDataBlockedFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::STREAMS_BLOCKED:
new (buf) QUICStreamIdBlockedFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::NEW_CONNECTION_ID:
new (buf) QUICNewConnectionIdFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::STOP_SENDING:
new (buf) QUICStopSendingFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::PATH_CHALLENGE:
new (buf) QUICPathChallengeFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::PATH_RESPONSE:
new (buf) QUICPathResponseFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::NEW_TOKEN:
new (buf) QUICNewTokenFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::RETIRE_CONNECTION_ID:
new (buf) QUICRetireConnectionIdFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
case QUICFrameType::HANDSHAKE_DONE:
new (buf) QUICHandshakeDoneFrame(src, len, packet);
return reinterpret_cast<QUICFrame *>(buf);
default:
// Unknown frame
Debug("quic_frame_factory", "Unknown frame type %x", src[0]);
return nullptr;
}
}
const QUICFrame &
QUICFrameFactory::fast_create(const uint8_t *buf, size_t len, const QUICPacketR *packet)
{
if (QUICFrame::type(buf) == QUICFrameType::UNKNOWN) {
return this->_unknown_frame;
}
ptrdiff_t type_index = static_cast<ptrdiff_t>(QUICFrame::type(buf));
QUICFrame *frame = this->_reusable_frames[type_index];
if (frame == nullptr) {
frame = QUICFrameFactory::create(this->_buf_for_fast_create + (type_index * QUICFrame::MAX_INSTANCE_SIZE), buf, len, packet);
if (frame != nullptr) {
this->_reusable_frames[static_cast<ptrdiff_t>(QUICFrame::type(buf))] = frame;
}
} else {
frame->parse(buf, len, packet);
}
return *frame;
}
QUICStreamFrame *
QUICFrameFactory::create_stream_frame(uint8_t *buf, Ptr<IOBufferBlock> &block, QUICStreamId stream_id, QUICOffset offset, bool last,
bool has_offset_field, bool has_length_field, QUICFrameId id, QUICFrameGenerator *owner)
{
Ptr<IOBufferBlock> new_block = make_ptr<IOBufferBlock>(block->clone());
new (buf) QUICStreamFrame(new_block, stream_id, offset, last, has_offset_field, has_length_field, id, owner);
return reinterpret_cast<QUICStreamFrame *>(buf);
}
QUICCryptoFrame *
QUICFrameFactory::create_crypto_frame(uint8_t *buf, Ptr<IOBufferBlock> &block, QUICOffset offset, QUICFrameId id,
QUICFrameGenerator *owner)
{
Ptr<IOBufferBlock> new_block = make_ptr<IOBufferBlock>(block->clone());
new (buf) QUICCryptoFrame(new_block, offset, id, owner);
return reinterpret_cast<QUICCryptoFrame *>(buf);
}
QUICAckFrame *
QUICFrameFactory::create_ack_frame(uint8_t *buf, QUICPacketNumber largest_acknowledged, uint64_t ack_delay,
uint64_t first_ack_block, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICAckFrame(largest_acknowledged, ack_delay, first_ack_block, id, owner);
return reinterpret_cast<QUICAckFrame *>(buf);
}
QUICConnectionCloseFrame *
QUICFrameFactory::create_connection_close_frame(uint8_t *buf, uint16_t error_code, QUICFrameType frame_type,
uint16_t reason_phrase_length, const char *reason_phrase, QUICFrameId id,
QUICFrameGenerator *owner)
{
new (buf) QUICConnectionCloseFrame(error_code, frame_type, reason_phrase_length, reason_phrase, id, owner);
return reinterpret_cast<QUICConnectionCloseFrame *>(buf);
}
QUICConnectionCloseFrame *
QUICFrameFactory::create_connection_close_frame(uint8_t *buf, const QUICConnectionError &error, QUICFrameId id,
QUICFrameGenerator *owner)
{
ink_assert(error.cls == QUICErrorClass::TRANSPORT);
if (error.msg) {
return QUICFrameFactory::create_connection_close_frame(buf, error.code, error.frame_type(), strlen(error.msg), error.msg, id,
owner);
} else {
return QUICFrameFactory::create_connection_close_frame(buf, error.code, error.frame_type(), 0, nullptr, id, owner);
}
}
QUICMaxDataFrame *
QUICFrameFactory::create_max_data_frame(uint8_t *buf, uint64_t maximum_data, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICMaxDataFrame(maximum_data, id, owner);
return reinterpret_cast<QUICMaxDataFrame *>(buf);
}
QUICMaxStreamDataFrame *
QUICFrameFactory::create_max_stream_data_frame(uint8_t *buf, QUICStreamId stream_id, uint64_t maximum_data, QUICFrameId id,
QUICFrameGenerator *owner)
{
new (buf) QUICMaxStreamDataFrame(stream_id, maximum_data, id, owner);
return reinterpret_cast<QUICMaxStreamDataFrame *>(buf);
}
QUICMaxStreamsFrame *
QUICFrameFactory::create_max_streams_frame(uint8_t *buf, QUICStreamId maximum_streams, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICMaxStreamsFrame(maximum_streams, id, owner);
return reinterpret_cast<QUICMaxStreamsFrame *>(buf);
}
QUICPingFrame *
QUICFrameFactory::create_ping_frame(uint8_t *buf, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICPingFrame(id, owner);
return reinterpret_cast<QUICPingFrame *>(buf);
}
QUICPaddingFrame *
QUICFrameFactory::create_padding_frame(uint8_t *buf, size_t size, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICPaddingFrame(size);
return reinterpret_cast<QUICPaddingFrame *>(buf);
}
QUICPathChallengeFrame *
QUICFrameFactory::create_path_challenge_frame(uint8_t *buf, const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner)
{
ats_unique_buf challenge_data = ats_unique_malloc(QUICPathChallengeFrame::DATA_LEN);
memcpy(challenge_data.get(), data, QUICPathChallengeFrame::DATA_LEN);
new (buf) QUICPathChallengeFrame(std::move(challenge_data), id, owner);
return reinterpret_cast<QUICPathChallengeFrame *>(buf);
}
QUICPathResponseFrame *
QUICFrameFactory::create_path_response_frame(uint8_t *buf, const uint8_t *data, QUICFrameId id, QUICFrameGenerator *owner)
{
ats_unique_buf response_data = ats_unique_malloc(QUICPathResponseFrame::DATA_LEN);
memcpy(response_data.get(), data, QUICPathResponseFrame::DATA_LEN);
new (buf) QUICPathResponseFrame(std::move(response_data), id, owner);
return reinterpret_cast<QUICPathResponseFrame *>(buf);
}
QUICDataBlockedFrame *
QUICFrameFactory::create_data_blocked_frame(uint8_t *buf, QUICOffset offset, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICDataBlockedFrame(offset, id, owner);
return reinterpret_cast<QUICDataBlockedFrame *>(buf);
}
QUICStreamDataBlockedFrame *
QUICFrameFactory::create_stream_data_blocked_frame(uint8_t *buf, QUICStreamId stream_id, QUICOffset offset, QUICFrameId id,
QUICFrameGenerator *owner)
{
new (buf) QUICStreamDataBlockedFrame(stream_id, offset, id, owner);
return reinterpret_cast<QUICStreamDataBlockedFrame *>(buf);
}
QUICStreamIdBlockedFrame *
QUICFrameFactory::create_stream_id_blocked_frame(uint8_t *buf, QUICStreamId stream_id, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICStreamIdBlockedFrame(stream_id, id, owner);
return reinterpret_cast<QUICStreamIdBlockedFrame *>(buf);
}
QUICRstStreamFrame *
QUICFrameFactory::create_rst_stream_frame(uint8_t *buf, QUICStreamId stream_id, QUICAppErrorCode error_code,
QUICOffset final_offset, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICRstStreamFrame(stream_id, error_code, final_offset, id, owner);
return reinterpret_cast<QUICRstStreamFrame *>(buf);
}
QUICRstStreamFrame *
QUICFrameFactory::create_rst_stream_frame(uint8_t *buf, QUICStreamError &error, QUICFrameId id, QUICFrameGenerator *owner)
{
return QUICFrameFactory::create_rst_stream_frame(buf, error.stream->id(), error.code, error.stream->final_offset(), id, owner);
}
QUICStopSendingFrame *
QUICFrameFactory::create_stop_sending_frame(uint8_t *buf, QUICStreamId stream_id, QUICAppErrorCode error_code, QUICFrameId id,
QUICFrameGenerator *owner)
{
new (buf) QUICStopSendingFrame(stream_id, error_code, id, owner);
return reinterpret_cast<QUICStopSendingFrame *>(buf);
}
QUICNewConnectionIdFrame *
QUICFrameFactory::create_new_connection_id_frame(uint8_t *buf, uint64_t sequence, uint64_t retire_prior_to,
QUICConnectionId connection_id, QUICStatelessResetToken stateless_reset_token,
QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICNewConnectionIdFrame(sequence, retire_prior_to, connection_id, stateless_reset_token, id, owner);
return reinterpret_cast<QUICNewConnectionIdFrame *>(buf);
}
QUICNewTokenFrame *
QUICFrameFactory::create_new_token_frame(uint8_t *buf, const QUICResumptionToken &token, QUICFrameId id, QUICFrameGenerator *owner)
{
uint64_t token_len = token.length();
ats_unique_buf token_buf = ats_unique_malloc(token_len);
memcpy(token_buf.get(), token.buf(), token_len);
new (buf) QUICNewTokenFrame(std::move(token_buf), token_len, id, owner);
return reinterpret_cast<QUICNewTokenFrame *>(buf);
}
QUICRetireConnectionIdFrame *
QUICFrameFactory::create_retire_connection_id_frame(uint8_t *buf, uint64_t seq_num, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICRetireConnectionIdFrame(seq_num, id, owner);
return reinterpret_cast<QUICRetireConnectionIdFrame *>(buf);
}
QUICHandshakeDoneFrame *
QUICFrameFactory::create_handshake_done_frame(uint8_t *buf, QUICFrameId id, QUICFrameGenerator *owner)
{
new (buf) QUICHandshakeDoneFrame(id, owner);
return reinterpret_cast<QUICHandshakeDoneFrame *>(buf);
}
QUICFrameId
QUICFrameInfo::id() const
{
return this->_id;
}
QUICFrameGenerator *
QUICFrameInfo::generated_by() const
{
return this->_generator;
}