#1 - quicr module

This commit is contained in:
Martin Slachta
2026-07-22 17:34:44 +02:00
parent a04f0dc262
commit f4174eb0c7
177 changed files with 5309 additions and 2265 deletions
+185
View File
@@ -0,0 +1,185 @@
#include "quicr/QuicrEncoder.hpp"
#include "quicr/QuicrConnection.hpp"
#include "bytebuffer/ByteBufferReader.hpp"
#include "quicr/QuicrFrameType.hpp"
#include <spdlog/spdlog.h>
namespace tw::net::quicr {
QuicrPacket QuicrDecoder::decode_packet_header(std::span<std::byte> data, size_t &offset) {
ByteBufferReader reader(data);
QuicrPacket packet;
reader.pop_bytes(&packet.type);
reader.pop_bytes(&packet.destination_id);
reader.pop_bytes(&packet.local_id);
reader.pop_bytes(&packet.require_ack);
// if(packet.require_ack) {
uint32_t packet_number = 0;
reader.pop_bytes(&packet_number);
packet.packet_number = packet_number;
// }
// packet.require_ack = false;
uint32_t length = 0;
reader.pop_bytes(&length);
offset = data.size() - reader.remaining();
return packet;
}
QuicrPacket QuicrDecoder::decode_packet(std::span<std::byte> data) {
size_t offset = 0;
QuicrPacket packet = decode_packet_header(data, offset);
ByteBufferReader reader(data.subspan(offset));
while(reader.remaining()) {
FrameType frame_type;
reader.pop_bytes(&frame_type);
switch(frame_type) {
case FrameType::KeepAlive:
case FrameType::Padding: {
break;
}
case FrameType::Ack: {
uint8_t num_acks = 0;
reader.pop_bytes(&num_acks);
std::vector<uint32_t> acked_packets(num_acks);
reader.pop_bytes(acked_packets.data(), acked_packets.size() * sizeof(uint32_t));
packet.frames.push_back(QuicrFrame::make_ack(acked_packets));
break;
}
case FrameType::Hello: {
packet.require_ack = true;
packet.frames.push_back(QuicrFrame::make_hello());
break;
}
case FrameType::HelloFin: {
packet.require_ack = true;
packet.frames.push_back(QuicrFrame::make_hello_fin());
break;
}
case FrameType::StreamBase:
packet.require_ack = true;
case FrameType::StreamUnreliable: {
uint32_t size = 0;
reader.pop_bytes(&size);
std::vector<std::byte> content(size);
reader.pop_bytes(content.data(), size);
packet.frames.push_back(QuicrFrame::make_stream(content));
break;
}
default: {
throw std::runtime_error("Unrecognized frame type: " + std::to_string((uint8_t)frame_type));
spdlog::error("Unrecognized frame type: {}", (uint8_t)frame_type);
break;
}
}
}
return packet;
}
QuicrPacketEncoder::QuicrPacketEncoder(std::span<std::byte> target, size_t& offset,
QuicrPacketType type, std::optional<uint32_t> packet_number,
QuicrConnection& connection)
: m_target(target), m_offset(offset), m_type(type), m_connection(connection), m_writer(m_target),
size_val_offset(0), is_reliable_val_offset(0) {
m_writer.write_bytes((uint8_t*)&type);
m_writer.write_bytes(&m_connection.peer_id());
m_writer.write_bytes(&m_connection.self_id());
is_reliable_val_offset = m_writer.length();
bool require_ack = false; // TODO: When does it need the ACK?
m_writer.write_bytes(&require_ack);
//if(require_ack) {
uint32_t _packet_num = packet_number.value();
m_writer.write_bytes(&_packet_num);
//}
uint32_t length_offset = m_writer.remaining();
uint32_t length = 0;
m_writer.write_bytes(&length);
}
QuicrPacketEncoder& QuicrPacketEncoder::encode_stream_frame(std::span<std::byte> data, bool is_reliable) {
uint8_t frame_type = is_reliable ? FrameType::StreamBase : FrameType::StreamUnreliable;
if(is_reliable) {
set_as_reliable();
}
m_writer.write_bytes(&frame_type);
uint32_t length = data.size();
m_writer.write_bytes(&length);
m_writer.write_bytes(data);
return *this;
}
QuicrPacketEncoder& QuicrPacketEncoder::encode_ack_frame(std::vector<uint32_t>& acked_packets) {
if(!acked_packets.empty()) {
uint8_t ack_frame_type = FrameType::Ack;
uint8_t acks_count = acked_packets.size();
m_writer.write_bytes(&ack_frame_type);
m_writer.write_bytes(&acks_count);
for(auto& ack : acked_packets) {
m_writer.write_bytes(&ack);
}
}
return *this;
}
QuicrPacketEncoder& QuicrPacketEncoder::encode_frame(QuicrFrame& frame) {
m_offset += m_writer.write_bytes(&frame.type);
switch(frame.type) {
case FrameType::KeepAlive:
case FrameType::Padding:
case FrameType::Hello:
set_as_reliable();
break;
case FrameType::StreamBase:
set_as_reliable();
case FrameType::StreamUnreliable:
{
m_offset += m_writer.write_bytes(frame.content);
break;
}
case FrameType::Ack:
case FrameType::AckEcn:
case FrameType::ResetStream:
case FrameType::StopSending:
case FrameType::Crypto:
case FrameType::NewToken:
case FrameType::HandshakeDone:
set_as_reliable();
m_offset += m_writer.write_bytes(frame.content);
break;
default: {
break;
}
}
return *this;
}
}