initial
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
#include "metrics/NetworkStatsLogger.hpp"
|
||||
|
||||
namespace tw::net {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include "frames/FrameCodec.hpp"
|
||||
|
||||
#include "bytebuffer/ByteBufferDecoder.hpp"
|
||||
|
||||
namespace tw::net::frame {
|
||||
|
||||
// static void encode(ByteBuffer& target, const Frame& frame) {
|
||||
// if(frame.frame_type() == quicr::FrameType::StreamBase) {
|
||||
// uint32_t frame_type = frame.frame_type();
|
||||
// target.write_bytes(&frame_type, sizeof(frame_type));
|
||||
|
||||
// uint32_t length = frame.buffer().size();
|
||||
// target.write_bytes(&length, sizeof(length));
|
||||
|
||||
// target.write_bytes((void*)frame.buffer().data(), frame.buffer().size());
|
||||
// return;
|
||||
// }
|
||||
|
||||
// spdlog::warn("Unknown frame type");
|
||||
// }
|
||||
|
||||
// static std::vector<Frame> decode(ByteBuffer& bytes) {
|
||||
// spdlog::info("Parsing frames");
|
||||
// std::vector<Frame> frames;
|
||||
|
||||
// // parse first byte as packet type
|
||||
// if(bytes.remaining_read() < 1) {
|
||||
// spdlog::warn("Nothing to read");
|
||||
// return {};
|
||||
// }
|
||||
|
||||
// size_t offset = 0;
|
||||
// size_t magic_search_length = 0;
|
||||
|
||||
// while (offset < bytes.remaining_read()) {
|
||||
// if(magic_search_length > 3) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
// auto magic = ByteBufferDecoder<uint32_t>::decode(bytes);
|
||||
// if(magic != 0xDEADBEEF) {
|
||||
// spdlog::warn("DEADBEEF not found");
|
||||
// bytes.skip(1);
|
||||
// magic_search_length++;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// auto t = ByteBufferDecoder<uint32_t>::decode(bytes, 4);
|
||||
// if(!t) {
|
||||
// spdlog::warn("Failed to decode frame type bytes");
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (*t == quicr::FrameType::Padding) {
|
||||
// spdlog::info("padding");
|
||||
// bytes.skip(2 * sizeof(uint32_t));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (*t == quicr::FrameType::KeepAlive) {
|
||||
// spdlog::info("keep alive");
|
||||
// bytes.skip(2 * sizeof(uint32_t));
|
||||
// // TODO: dispatch to connection if you want per-conn ping
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (*t == quicr::FrameType::StreamBase) {
|
||||
// spdlog::info("Stream!");
|
||||
// auto length_r = ByteBufferDecoder<uint32_t>::decode(bytes, 8);
|
||||
// if(!length_r) {
|
||||
// spdlog::warn("Length could not be decoded");
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// std::vector<std::byte> payload(*length_r + 4 * sizeof(uint32_t));
|
||||
// auto popped_bytes = bytes.pop_bytes(payload); // skip length field
|
||||
// spdlog::info("Popped: {} ", popped_bytes);
|
||||
// if(popped_bytes == 0) {
|
||||
// spdlog::warn("Not enought bytes in the buffer");
|
||||
// break;
|
||||
// }
|
||||
|
||||
// std::vector<std::byte> payload_without_header(payload.begin() + 3 * sizeof(uint32_t), payload.end());
|
||||
|
||||
// frames.emplace_back(quicr::FrameType::StreamBase, payload_without_header);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// bytes.skip(2 * sizeof(uint32_t));
|
||||
// spdlog::warn("unknown frame {}", *t);
|
||||
|
||||
// // Unknown frame — can't skip safely
|
||||
// break;
|
||||
// }
|
||||
|
||||
// spdlog::info("Parsed {} frames", frames.size());
|
||||
|
||||
// return frames;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "messenger/Messenger.hpp"
|
||||
|
||||
namespace tw::net {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "messenger/MessengerDebugLog.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
MessengerDebugLog::MessengerDebugLog(const std::string& log_file_path) : m_log_file(log_file_path) {
|
||||
if (!m_log_file.is_open()) {
|
||||
throw std::runtime_error("Failed to open log file");
|
||||
}
|
||||
}
|
||||
|
||||
MessengerDebugLog::~MessengerDebugLog() {
|
||||
m_log_file.close();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
#include "metrics/HistoryBufferExporter.hpp"
|
||||
@@ -0,0 +1,556 @@
|
||||
#include "protocol/quicr/QuicrConnection.hpp"
|
||||
|
||||
#include "bytebuffer/ByteBuffer.hpp"
|
||||
#include "bytebuffer/ByteBufferReader.hpp"
|
||||
#include "protocol/quicr/QuicrConnectionIdGenerator.hpp"
|
||||
#include "protocol/quicr/QuicrEncoder.hpp"
|
||||
#include "protocol/quicr/QuicrFrame.hpp"
|
||||
#include "protocol/quicr/QuicrPacket.hpp"
|
||||
#include "protocol/quicr/QuicrPacketType.hpp"
|
||||
#include "protocol/quicr/VarInt.hpp"
|
||||
#include "protocol/quicr/QuicrFrameType.hpp"
|
||||
#include <absl/strings/str_format.h>
|
||||
|
||||
|
||||
|
||||
namespace tw::net::quicr {
|
||||
|
||||
tl::expected<size_t, NetworkError> QuicrConnection::write_datagram(std::span<std::byte> data) {
|
||||
if(m_state == QuicrConnectionState::Closed) {
|
||||
spdlog::warn("Attempted to write in Closed state");
|
||||
return tl::make_unexpected(NetworkError::from_errno(ENOTCONN));
|
||||
}
|
||||
|
||||
if(m_last_heartbeat_received < Clock::now() - std::chrono::milliseconds(TW_NET_HEARTBEAT_INTERVAL_IN_MILLIS * 2)) {
|
||||
m_state = QuicrConnectionState::Closed;
|
||||
return tl::make_unexpected(NetworkError::from_errno(CONNECTION_RESET));
|
||||
}
|
||||
|
||||
std::vector<std::byte> dgram;
|
||||
dgram.insert(dgram.end(), data.begin(), data.end());
|
||||
|
||||
auto r = m_endpoint->send_to(dgram, m_peer_address);
|
||||
if (!r) return tl::make_unexpected(r.error());
|
||||
|
||||
m_last_heartbeat_sent = Clock::now();
|
||||
return data.size();
|
||||
}
|
||||
|
||||
void QuicrConnection::send_initial_hello() {
|
||||
m_reliability_unit->push_reliable_frame(Clock::now(), QuicrFrame::make_hello());
|
||||
m_state = QuicrConnectionState::SentHello;
|
||||
}
|
||||
|
||||
|
||||
void QuicrConnection::send_hello() {
|
||||
std::vector<std::byte> dgram;
|
||||
|
||||
if(m_state != QuicrConnectionState::Closed && m_state != QuicrConnectionState::SentHello) {
|
||||
spdlog::warn("Attempted to send Hello in state {}, expected Closed", (int)m_state);
|
||||
return;
|
||||
}
|
||||
|
||||
VarInt(peer_id()).encode(dgram);
|
||||
VarInt(self_id()).encode(dgram);
|
||||
VarInt(FrameType::Hello).encode(dgram);
|
||||
VarInt(0).encode(dgram);
|
||||
VarInt(PROTOCOL_VERSION).encode(dgram);
|
||||
VarInt(self_id()).encode(dgram);
|
||||
|
||||
m_state = QuicrConnectionState::SentHello;
|
||||
auto r = write_datagram(dgram);
|
||||
if(!r) {
|
||||
spdlog::error("Failed to send HelloAck: {}", r.error().message());
|
||||
}
|
||||
}
|
||||
|
||||
bool QuicrConnection::process_hello(const QuicrPacket& packet, const QuicrFrame& frame) {
|
||||
// auto frame_number_v = VarInt::decode(dgram.subspan(off));
|
||||
// if (!frame_number_v) return false;
|
||||
// uint64_t frame_number = frame_number_v->value;
|
||||
// off += frame_number_v->bytes;
|
||||
|
||||
// auto versionV = VarInt::decode(dgram.subspan(off));
|
||||
// if (!versionV) return false;
|
||||
// uint64_t peer_version = versionV->value;
|
||||
// off += versionV->bytes;
|
||||
|
||||
// auto peer_connection_id_v = VarInt::decode(dgram.subspan(off));
|
||||
// if (!peer_connection_id_v) return false;
|
||||
// uint64_t peer_connection_id = peer_connection_id_v->value;
|
||||
// off += peer_connection_id_v->bytes;
|
||||
|
||||
// spdlog::info("Processing hello from: {}", peer_connection_id);
|
||||
|
||||
// if(m_state != QuicrConnectionState::Closed) {
|
||||
// spdlog::warn("Received unexpected Hello in state {}, expected Closed", (int)m_state);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if(peer_version != PROTOCOL_VERSION) {
|
||||
// spdlog::warn("Unsupported protocol version: {}, expected {}", peer_version, PROTOCOL_VERSION);
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if(m_state == QuicrConnectionState::Closed) {
|
||||
m_peer_id = packet.local_id;
|
||||
m_state = QuicrConnectionState::ReceivedHello;
|
||||
m_reliability_unit->push_reliable_frame(Clock::now(), QuicrFrame::make_hello());
|
||||
} else if(m_state == QuicrConnectionState::SentHello) {
|
||||
m_peer_id = packet.local_id;
|
||||
m_state = QuicrConnectionState::Established;
|
||||
m_reliability_unit->push_reliable_frame(Clock::now(), QuicrFrame::make_hello_fin());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QuicrConnection::process_hello_fin(const QuicrPacket& packet, const QuicrFrame& frame) {
|
||||
if(m_state == QuicrConnectionState::ReceivedHello) {
|
||||
m_state = QuicrConnectionState::Established;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QuicrConnection::send_hello_ack_frame() {
|
||||
std::vector<std::byte> dgram;
|
||||
|
||||
VarInt(peer_id()).encode(dgram);
|
||||
VarInt(self_id()).encode(dgram);
|
||||
VarInt(FrameType::HelloFin).encode(dgram);
|
||||
VarInt(PROTOCOL_VERSION).encode(dgram);
|
||||
VarInt(self_id()).encode(dgram);
|
||||
VarInt(peer_id()).encode(dgram); // acknoledge it's ID
|
||||
|
||||
auto r = write_datagram(dgram);
|
||||
if(!r) {
|
||||
spdlog::error("Failed to send HelloAck: {}", r.error().message());
|
||||
}
|
||||
}
|
||||
|
||||
bool QuicrConnection::process_hello_ack_frame(std::span<const std::byte> dgram, size_t& off) {
|
||||
auto peer_version_v = VarInt::decode(dgram.subspan(off));
|
||||
if (!peer_version_v) return false;
|
||||
uint64_t peer_version = peer_version_v->value;
|
||||
off += peer_version_v->bytes;
|
||||
|
||||
auto peer_connection_id_v = VarInt::decode(dgram.subspan(off));
|
||||
if (!peer_connection_id_v) return false;
|
||||
uint64_t peer_connection_id = peer_connection_id_v->value;
|
||||
off += peer_connection_id_v->bytes;
|
||||
|
||||
auto echoed_connection_id_v = VarInt::decode(dgram.subspan(off));
|
||||
if (!echoed_connection_id_v) return false;
|
||||
uint64_t echoed_connection_id = echoed_connection_id_v->value;
|
||||
off += echoed_connection_id_v->bytes;
|
||||
|
||||
if(m_state != QuicrConnectionState::SentHello) {
|
||||
spdlog::warn("Received unexpected HelloAck in state {}, expected SentHello", (int)m_state);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(peer_version != PROTOCOL_VERSION) {
|
||||
spdlog::warn("Unsupported protocol version in HelloAck: {}, expected {}", peer_version, PROTOCOL_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(echoed_connection_id != self_id()) {
|
||||
spdlog::warn("HelloAck echoed wrong connection ID: {}, expected {}", echoed_connection_id, self_id());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_peer_id = peer_connection_id;
|
||||
|
||||
send_handshake_done();
|
||||
|
||||
m_state = QuicrConnectionState::Established;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void QuicrConnection::send_handshake_done() {
|
||||
std::vector<std::byte> dgram;
|
||||
|
||||
VarInt(peer_id()).encode(dgram);
|
||||
VarInt(self_id()).encode(dgram);
|
||||
VarInt(FrameType::HandshakeDone).encode(dgram);
|
||||
VarInt(PROTOCOL_VERSION).encode(dgram);
|
||||
VarInt(self_id()).encode(dgram);
|
||||
VarInt(peer_id()).encode(dgram);
|
||||
|
||||
auto r = write_datagram(dgram);
|
||||
if(!r) {
|
||||
spdlog::error("Failed to send Handshake Done: {}", r.error().message());
|
||||
}
|
||||
}
|
||||
|
||||
bool QuicrConnection::process_handshake_done(std::span<const std::byte> dgram, size_t& off) {
|
||||
auto peer_version_v = VarInt::decode(dgram.subspan(off));
|
||||
if (!peer_version_v) return false;
|
||||
uint64_t peer_version = peer_version_v->value;
|
||||
off += peer_version_v->bytes;
|
||||
|
||||
auto peer_connection_id_v = VarInt::decode(dgram.subspan(off));
|
||||
if (!peer_connection_id_v) return false;
|
||||
uint64_t peer_connection_id = peer_connection_id_v->value;
|
||||
off += peer_connection_id_v->bytes;
|
||||
|
||||
auto echoed_connection_id_v = VarInt::decode(dgram.subspan(off));
|
||||
if (!echoed_connection_id_v) return false;
|
||||
uint64_t echoed_connection_id = echoed_connection_id_v->value;
|
||||
off += echoed_connection_id_v->bytes;
|
||||
|
||||
if(peer_version != PROTOCOL_VERSION) {
|
||||
spdlog::warn("Unsupported protocol version in HelloAck: {}, expected {}", peer_version, PROTOCOL_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(echoed_connection_id != self_id()) {
|
||||
spdlog::warn("HelloAck echoed wrong connection ID: {}, expected {}", echoed_connection_id, self_id());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_state = QuicrConnectionState::Established;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
tl::expected<void, QuicrError>
|
||||
QuicrConnection::send_message(std::span<std::byte> data, bool is_reliable) {
|
||||
if(state() == QuicrConnectionState::Closed) {
|
||||
return tl::make_unexpected(QuicrError(QuicrErrorType::ConnectionClosed));
|
||||
}
|
||||
|
||||
m_outbound_messages.emplace_back(data.begin(), data.end());
|
||||
|
||||
return {};
|
||||
|
||||
// std::vector<std::byte> dgram;
|
||||
|
||||
// VarInt(peer_id()).encode(dgram);
|
||||
// VarInt(self_id()).encode(dgram);
|
||||
// VarInt(FrameType::StreamBase).encode(dgram);
|
||||
// VarInt(data.size()).encode(dgram);
|
||||
|
||||
// dgram.insert(dgram.end(), data.begin(), data.end());
|
||||
|
||||
// auto r = write_datagram(dgram);
|
||||
// if (!r) {
|
||||
// spdlog::error("Failed to send stream frame: {}", r.error().message());
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// return true;
|
||||
}
|
||||
|
||||
bool QuicrConnection::process_stream_frame(uint64_t type, std::span<const std::byte> dgram, size_t& offset) {
|
||||
uint32_t length = (uint32_t)dgram.size();
|
||||
|
||||
m_messages.push_back(std::vector<std::byte>(dgram.begin() + offset, dgram.begin() + offset + length));
|
||||
offset += length;
|
||||
|
||||
return true;
|
||||
|
||||
// bool has_off = (type & STREAM_FLAG_OFF) != 0;
|
||||
// bool has_len = (type & STREAM_FLAG_LEN) != 0;
|
||||
|
||||
// if (has_off) {
|
||||
// auto off_val = VarInt::decode(dgram.subspan(offset));
|
||||
// if (!off_val) return false;
|
||||
// offset += off_val->bytes;
|
||||
// }
|
||||
|
||||
// size_t payload_len;
|
||||
// // if (has_len) {
|
||||
// auto len_val = VarInt::decode(dgram.subspan(offset));
|
||||
// if (!len_val) return false;
|
||||
// offset += len_val->bytes;
|
||||
// payload_len = len_val->value;
|
||||
|
||||
// if (offset + payload_len > dgram.size()) return false;
|
||||
// // } else {
|
||||
// // payload_len = dgram.size() - offset;
|
||||
// // }
|
||||
|
||||
// auto payload = dgram.subspan(offset, payload_len);
|
||||
// m_messages.push_back(std::vector<std::byte>(payload.begin(), payload.end()));
|
||||
// offset += payload_len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tl::expected<void, NetworkError> QuicrConnection::send_keep_alive() {
|
||||
std::vector<std::byte> dgram;
|
||||
VarInt(FrameType::KeepAlive).encode(dgram);
|
||||
VarInt(m_self_id).encode(dgram);
|
||||
|
||||
auto r = m_endpoint->send_to(dgram, m_peer_address);
|
||||
if (!r) return tl::make_unexpected(r.error());
|
||||
|
||||
m_last_heartbeat_sent = Clock::now();
|
||||
return {};
|
||||
}
|
||||
|
||||
// void QuicrConnection::update() {
|
||||
// if(m_state == QuicrConnectionState::Established) {
|
||||
// if(m_last_heartbeat_sent < std::chrono::steady_clock::now() - std::chrono::milliseconds(TW_NET_HEARTBEAT_INTERVAL_IN_MILLIS)) {
|
||||
// auto r = send_keep_alive();
|
||||
// if(!r.has_value()) {
|
||||
// spdlog::error("Failed to send heartbeat - closing connection: {}", r.error().message());
|
||||
// m_state = QuicrConnectionState::Closed;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if(m_last_heartbeat_received < std::chrono::steady_clock::now() - std::chrono::milliseconds(TW_NET_HEARTBEAT_INTERVAL_IN_MILLIS * 2)) {
|
||||
// // Connection is considered lost if we haven't received a heartbeat for twice the interval
|
||||
// spdlog::warn("Connection lost due to heartbeat timeout");
|
||||
// m_state = QuicrConnectionState::Closed;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
bool QuicrConnection::process_ack_frame(const QuicrPacket& packet, const QuicrFrame& frame) {
|
||||
ByteBufferReader reader(std::span(frame.content));
|
||||
|
||||
uint32_t num_acks = frame.content.size() / sizeof(uint32_t);
|
||||
// reader.pop_bytes(&num_acks);
|
||||
|
||||
for(int i = 0; i < num_acks; i++) {
|
||||
uint32_t acked_packet = 0;
|
||||
reader.pop_bytes(&acked_packet);
|
||||
|
||||
m_reliability_unit->on_ack_received(acked_packet);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void QuicrConnection::process_datagram(std::span<std::byte> dgram) {
|
||||
m_last_heartbeat_received = Clock::now();
|
||||
|
||||
QuicrPacket packet = QuicrDecoder::decode_packet(dgram);
|
||||
|
||||
if(packet.require_ack) {
|
||||
m_reliability_unit->push_ack(packet.packet_number.value());
|
||||
}
|
||||
|
||||
for(auto& frame : packet.frames) {
|
||||
switch(frame.type) {
|
||||
case FrameType::StreamBase:
|
||||
case FrameType::StreamUnreliable: {
|
||||
size_t offset = 0;
|
||||
process_stream_frame(frame.type, frame.content, offset);
|
||||
} break;
|
||||
case FrameType::Hello:
|
||||
process_hello(packet, frame);
|
||||
break;
|
||||
case FrameType::HelloFin:
|
||||
process_hello_fin(packet, frame);
|
||||
break;
|
||||
case FrameType::Ack:
|
||||
process_ack_frame(packet, frame);
|
||||
break;
|
||||
// case FrameType::HelloAck:
|
||||
// process_hello_ack_frame(dgram.subspan(offset + packet.header_size), offset);
|
||||
// break;
|
||||
// case FrameType::HandshakeDone:
|
||||
// process_handshake_done(dgram.subspan(offset + packet.header_size), offset);
|
||||
// break;
|
||||
default:
|
||||
spdlog::warn("Unknown frame type: {}", static_cast<int>(frame.type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// auto destination_id_v = VarInt::decode(dgram.subspan(offset));
|
||||
// if (!destination_id_v) return;
|
||||
// uint64_t destination_id = destination_id_v->value;
|
||||
// offset += destination_id_v->bytes;
|
||||
|
||||
// auto source_id_v = VarInt::decode(dgram.subspan(offset));
|
||||
// if (!source_id_v) return;
|
||||
// uint64_t source_id = source_id_v->value;
|
||||
// offset += source_id_v->bytes;
|
||||
|
||||
// m_peer_id = source_id;
|
||||
|
||||
// while (offset < dgram.size()) {
|
||||
// auto typeV = VarInt::decode(dgram.subspan(offset));
|
||||
// if (!typeV) {
|
||||
// spdlog::warn("Failed to decode frame type, dropping rest of datagram");
|
||||
// return;
|
||||
// }
|
||||
// uint64_t t = typeV->value;
|
||||
// offset += typeV->bytes;
|
||||
|
||||
// // bool is_reliable = *(bool*)(dgram.data() + offset);
|
||||
|
||||
// // uint64_t packet_number = 0;
|
||||
// // if(is_reliable) {
|
||||
// // packet_number = VarInt::decode(dgram.subspan(offset))->value;
|
||||
// // offset += VarInt::decode(dgram.subspan(offset))->bytes;
|
||||
// // }
|
||||
|
||||
// if (t == FrameType::Padding) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// else if (t == FrameType::KeepAlive) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// else if (t == FrameType::Hello) {
|
||||
// spdlog::info("processing hello");
|
||||
// process_hello(dgram, offset);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// else if (t == FrameType::HelloAck) {
|
||||
// if (!process_hello_ack_frame(dgram, offset)) return;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// else if (t == FrameType::HandshakeDone) {
|
||||
// if (!process_handshake_done(dgram, offset)) return;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// else if (t >= FrameType::StreamBase && t <= (FrameType::StreamBase | 0x07)) {
|
||||
// if (!process_stream_frame(t, dgram, offset)) return;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// spdlog::warn("Unknown frame on {} 0x{:x}, dropping rest of datagram", self_id(), t);
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
|
||||
// void QuicrConnection::drain_socket() {
|
||||
// while (true) {
|
||||
// auto r = m_stream.read_into(m_recv_buffer);
|
||||
// if (!r || *r == 0) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
// m_last_heartbeat_received = Clock::now();
|
||||
|
||||
// auto dgram = std::span(m_recv_buffer.data(), *r);
|
||||
|
||||
// size_t offset = 0;
|
||||
// auto peer_connection_id_v = VarInt::decode(dgram.subspan(offset));
|
||||
// if (!peer_connection_id_v) {
|
||||
// spdlog::warn("Failed to decode peer connection ID, dropping datagram");
|
||||
// return;
|
||||
// }
|
||||
// uint64_t peer_connection_id = peer_connection_id_v->value;
|
||||
// offset += peer_connection_id_v->bytes;
|
||||
|
||||
// if(peer_connection_id != peer_id()) {
|
||||
// spdlog::warn("Received datagram with wrong peer connection ID: {}, expected {}, dropping datagram", peer_connection_id, peer_id());
|
||||
// return;
|
||||
// }
|
||||
|
||||
// process_datagram(dgram.subspan(offset));
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
tl::expected<size_t, NetworkError> QuicrConnection::read_into(std::span<std::byte> target) {
|
||||
if(m_messages.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto& msg = m_messages.front();
|
||||
size_t msg_len = msg.size();
|
||||
size_t to_copy = std::min(msg_len, target.size());
|
||||
|
||||
std::memcpy(target.data(), msg.data(), to_copy);
|
||||
m_messages.pop_front();
|
||||
|
||||
if (to_copy < msg_len) {
|
||||
spdlog::warn("Message truncated: {} bytes into {} byte buffer",
|
||||
msg_len, target.size());
|
||||
}
|
||||
|
||||
return msg_len; // return full message size so caller knows if truncated
|
||||
}
|
||||
|
||||
|
||||
void QuicrConnection::on_tick(std::chrono::steady_clock::time_point now) {
|
||||
// if (now - m_last_heartbeat_sent > std::chrono::milliseconds(TW_NET_HEARTBEAT_INTERVAL_IN_MILLIS)) {
|
||||
// auto keep_alive_r = send_keep_alive();
|
||||
// }
|
||||
|
||||
if(m_last_heartbeat_received < now - std::chrono::milliseconds(TW_NET_HEARTBEAT_INTERVAL_IN_MILLIS * 2)) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool QuicrConnection::has_next_datagram() {
|
||||
if(m_reliability_unit->has_reliable_frames_to_resend()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(m_reliability_unit->has_acks_to_send()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!m_outbound_messages.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::byte> QuicrConnection::pop_datagram() {
|
||||
|
||||
std::vector<std::byte> datagram(64*1024);
|
||||
|
||||
QuicrPacketType type = QuicrPacketType::Initial;
|
||||
size_t offset = 0;
|
||||
uint32_t packet_number = m_packet_number++;
|
||||
QuicrPacketEncoder encoder(datagram, offset, type, packet_number, *this);
|
||||
|
||||
|
||||
// encode ACK frame
|
||||
{
|
||||
auto acks = m_reliability_unit->pop_acks_to_send();
|
||||
|
||||
encoder.encode_ack_frame(acks);
|
||||
}
|
||||
|
||||
// re-send frames
|
||||
{
|
||||
// pop already encoded frames
|
||||
auto frames_to_resend = m_reliability_unit->pop_frames_to_resend(packet_number);
|
||||
for(auto& frame : frames_to_resend) {
|
||||
frame.frame_number = packet_number;
|
||||
encoder.encode_frame(frame);
|
||||
|
||||
// auto deadline = Clock::now() + std::chrono::milliseconds(TW_NET_HELLO_RETRY_INTERVAL_IN_MILLIS);
|
||||
// m_reliability_unit->push_reliable_frame_to_send(deadline, std::move(frame));
|
||||
}
|
||||
}
|
||||
|
||||
while(true) {
|
||||
if(m_outbound_messages.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto outbound = m_outbound_messages.front();
|
||||
m_outbound_messages.pop_front();
|
||||
|
||||
encoder.encode_stream_frame(outbound, true);
|
||||
}
|
||||
|
||||
m_last_heartbeat_sent = Clock::now();
|
||||
|
||||
return std::vector<std::byte>(datagram.begin(), datagram.begin() + encoder.size());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "protocol/quicr/QuicrConnectionListener.hpp"
|
||||
#include "protocol/quicr/QuicrEndpoint.hpp"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace tw::net::quicr {
|
||||
|
||||
QuicrConnectionListener::QuicrConnectionListener(QuicrEndpoint* endpoint)
|
||||
: m_listened_connections()
|
||||
{
|
||||
endpoint->assign_listener(this);
|
||||
}
|
||||
|
||||
tl::expected<std::unique_ptr<QuicrConnectionListener>, NetworkError> QuicrConnectionListener::listen(QuicrEndpoint* endpoint) {
|
||||
return std::unique_ptr<QuicrConnectionListener>(new QuicrConnectionListener(endpoint));
|
||||
};
|
||||
|
||||
QuicrConnection* QuicrConnectionListener::listen() {
|
||||
if(m_listened_connections.size() > 0) {
|
||||
QuicrConnection* connection = m_listened_connections.front();
|
||||
m_listened_connections.pop_front();
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
#include "protocol/quicr/QuicrEncoder.hpp"
|
||||
#include "protocol/quicr/QuicrConnection.hpp"
|
||||
#include "bytebuffer/ByteBufferReader.hpp"
|
||||
#include "frames/Frame.hpp"
|
||||
#include "protocol/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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#include "protocol/quicr/QuicrEndpoint.hpp"
|
||||
#include "protocol/quicr/QuicrConnection.hpp"
|
||||
#include "protocol/quicr/QuicrConnectionListener.hpp"
|
||||
#include "protocol/quicr/QuicrEncoder.hpp"
|
||||
#include "tl/expected.hpp"
|
||||
#include <chrono>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
namespace tw::net::quicr {
|
||||
|
||||
QuicrEndpoint::QuicrEndpoint(int socket_fd)
|
||||
: m_inbound_buffer(64 * 1024), m_socket_fd(socket_fd),
|
||||
m_new_connection_handler(nullptr) {
|
||||
|
||||
}
|
||||
|
||||
tl::expected<std::unique_ptr<QuicrEndpoint>, NetworkError> QuicrEndpoint::create_and_bind(int16_t port) {
|
||||
auto endpoint = QuicrEndpoint::create();
|
||||
if (!endpoint.has_value()) {
|
||||
return tl::make_unexpected(endpoint.error());
|
||||
}
|
||||
|
||||
auto bind_r = (*endpoint)->bind(port);
|
||||
if(!bind_r) {
|
||||
return tl::make_unexpected(bind_r.error());
|
||||
}
|
||||
|
||||
return std::move(*endpoint);
|
||||
}
|
||||
|
||||
tl::expected<std::unique_ptr<QuicrEndpoint>, NetworkError> QuicrEndpoint::create() {
|
||||
const int domain = AF_INET;
|
||||
int socket_fd = socket(domain, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if(socket_fd < 0) {
|
||||
spdlog::error("Failed to create socket: {}", strerror(errno));
|
||||
return tl::make_unexpected(NetworkError::from_errno(errno));
|
||||
}
|
||||
|
||||
if(fcntl(socket_fd, F_SETFL, fcntl(socket_fd, F_GETFL, 0) | O_NONBLOCK, 1) == -1) {
|
||||
spdlog::error("Failed to set non-blocking mode: {}", strerror(errno));
|
||||
return tl::make_unexpected(NetworkError::from_errno(errno));
|
||||
}
|
||||
|
||||
return std::unique_ptr<QuicrEndpoint>(new QuicrEndpoint(socket_fd));
|
||||
}
|
||||
|
||||
tl::expected<void, NetworkError> QuicrEndpoint::bind(int port) {
|
||||
const int domain = AF_INET;
|
||||
struct sockaddr_in addr = {};
|
||||
addr.sin_family = domain;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if(::bind(m_socket_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
spdlog::error("Failed to bind socket: {}", strerror(errno));
|
||||
return tl::make_unexpected(NetworkError::from_errno(errno));
|
||||
}
|
||||
|
||||
if(fcntl(m_socket_fd, F_SETFL, fcntl(m_socket_fd, F_GETFL, 0) | O_NONBLOCK, 1) == -1) {
|
||||
spdlog::error("Failed to set non-blocking mode: {}", strerror(errno));
|
||||
return tl::make_unexpected(NetworkError::from_errno(errno));
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new connection from current socket to the address.
|
||||
*/
|
||||
tl::expected<QuicrConnection*, NetworkError> QuicrEndpoint::connect(Address address) {
|
||||
auto connection = std::make_shared<QuicrConnection>(0, 0, address, this);
|
||||
auto inserted_r = m_connections.emplace(connection->self_id(), connection);
|
||||
|
||||
if(!inserted_r.second) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inserted_r.first->second->send_initial_hello();
|
||||
|
||||
return inserted_r.first->second.get();
|
||||
}
|
||||
|
||||
void QuicrEndpoint::process_datagram(std::span<std::byte> datagram, Address from) {
|
||||
ZoneScopedN("Process Datagram");
|
||||
|
||||
// parse first byte as packet type
|
||||
if(datagram.size() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t off = 0;
|
||||
|
||||
QuicrPacket packet = QuicrDecoder::decode_packet_header(datagram, off);
|
||||
|
||||
auto connection = m_connections.find(packet.destination_id);
|
||||
|
||||
if(connection == m_connections.end()) {
|
||||
spdlog::warn("New connection from: {}", from.to_string());
|
||||
auto conn = std::make_shared<QuicrConnection>(0, packet.local_id, from, this);
|
||||
auto emplaced = m_connections.emplace(conn->self_id(), conn);
|
||||
emplaced.first->second->set_peer_id(packet.local_id);
|
||||
|
||||
emplaced.first->second->process_datagram(datagram);
|
||||
m_connections.emplace(packet.destination_id, emplaced.first->second);
|
||||
return;
|
||||
}
|
||||
|
||||
auto prev_state = connection->second->state();
|
||||
|
||||
connection->second->process_datagram(datagram);
|
||||
|
||||
if(prev_state != QuicrConnectionState::Established && connection->second->state() == QuicrConnectionState::Established) {
|
||||
if(m_new_connection_handler != nullptr) {
|
||||
m_new_connection_handler->on_new_connection(connection->second.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tl::expected<size_t, NetworkError> QuicrEndpoint::send_to(std::span<std::byte> data, Address to) {
|
||||
size_t total = 0;
|
||||
|
||||
while(total < data.size_bytes()) {
|
||||
ssize_t t = ::sendto(m_socket_fd, data.data() + total, data.size() - total, MSG_NOSIGNAL | MSG_DONTWAIT, to.sockaddr(), to.socklen());
|
||||
if(t == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return tl::make_unexpected(NetworkError::from_errno(errno));
|
||||
}
|
||||
total += t;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
tl::expected<size_t, NetworkError> QuicrEndpoint::read_from_into(std::span<std::byte> data, Address* out_from) {
|
||||
struct sockaddr_storage sockaddr_from;
|
||||
socklen_t from_length = sizeof( sockaddr_from );
|
||||
|
||||
int read_len = ::recvfrom(m_socket_fd, data.data(), data.size(), 0, (struct sockaddr*)&sockaddr_from, &from_length);
|
||||
if(read_len == -1) {
|
||||
if(errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tl::make_unexpected(NetworkError::from_errno(errno));
|
||||
}
|
||||
|
||||
*out_from = std::move(Address(sockaddr_from));
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
void QuicrEndpoint::poll() {
|
||||
while(1) {
|
||||
ZoneScopedN("Reading");
|
||||
Address address({}, 0);
|
||||
auto r = read_from_into(std::span(m_inbound_buffer), &address);
|
||||
if(!r || *r == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
process_datagram(std::span(m_inbound_buffer).subspan(0, *r), address);
|
||||
}
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
|
||||
for(auto& connection : m_connections) {
|
||||
ZoneScopedN("Per Connection");
|
||||
|
||||
while(connection.second->has_next_datagram()) {
|
||||
auto datagram = connection.second->pop_datagram();
|
||||
auto send_r = send_to(datagram, connection.second->address());
|
||||
if(!send_r) {
|
||||
spdlog::error("Failed to send to {} datagram: {}", connection.second->address().to_string(), send_r.error().message());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
#include "protocol/quicr/QuicrReliability.hpp"
|
||||
#include "bytebuffer/ByteBuffer.hpp"
|
||||
#include "metrics/NetworkStatsLogger.hpp"
|
||||
#include "protocol/quicr/QuicrConnection.hpp"
|
||||
#include <chrono>
|
||||
#include <immintrin.h>
|
||||
|
||||
namespace tw::net::quicr {
|
||||
|
||||
// size_t QuicrReliabilityUnit::encode_packet_header(RingByteBuffer& target, const QuicrConnection* connection) {
|
||||
// size_t size = 0;
|
||||
|
||||
// target.write_bytes(&connection->peer_id());
|
||||
// target.write_bytes(&connection->self_id());
|
||||
|
||||
// return size;
|
||||
// }
|
||||
|
||||
// size_t QuicrReliabilityUnit::encode_frame_header(RingByteBuffer& buffer, const QuicrFrame& frame) {
|
||||
// size_t size = 0;
|
||||
|
||||
// buffer.write_bytes(&frame.type);
|
||||
|
||||
// if(frame.is_reliable) {
|
||||
// buffer.write_bytes(&frame.is_reliable);
|
||||
// buffer.write_bytes(&frame.frame_number);
|
||||
// }
|
||||
|
||||
// return size;
|
||||
// }
|
||||
|
||||
// size_t QuicrReliabilityUnit::encode_frame_body(RingByteBuffer& buffer, const QuicrFrame& frame) {
|
||||
// size_t size = 0;
|
||||
|
||||
|
||||
// return size;
|
||||
// }
|
||||
|
||||
// size_t QuicrReliabilityUnit::encode_frame(RingByteBuffer& buffer, const QuicrFrame& frame) {
|
||||
// size_t size = 0;
|
||||
|
||||
// size += encode_frame_header(frame);
|
||||
|
||||
// size += encode_frame_body(frame);
|
||||
|
||||
// return size;
|
||||
// }
|
||||
|
||||
// std::vector<std::byte> QuicrReliabilityUnit::pop_datagram() {
|
||||
// size_t size = 0;
|
||||
// std::vector<std::byte> datagram;
|
||||
// RingByteBuffer byte_buf(datagram);
|
||||
|
||||
// // write header
|
||||
// byte_buf.write_bytes(&connection->peer_id());
|
||||
// byte_buf.write_bytes(&connection->self_id());
|
||||
|
||||
// size_t last_end = byte_buf.remaining_read();
|
||||
|
||||
// size += encode_packet_header();
|
||||
|
||||
// // resend frames
|
||||
// for (const auto& [timestamp, frame] : awaiting_ack_frames) {
|
||||
// if(timestamp < std::chrono::steady_clock::now() - std::chrono::seconds(1)) {
|
||||
// size += encode_frame(byte_buf, frame);
|
||||
// last_end = byte_buf.remaining_read();
|
||||
// }
|
||||
// }
|
||||
|
||||
// // write body
|
||||
// while(size < 1100) {
|
||||
// auto frame = frames.front();
|
||||
|
||||
// if(frame.is_reliable) {
|
||||
// frame.frame_number = m_frame_number++;
|
||||
// }
|
||||
|
||||
// size += encode_frame(byte_buf, frame);
|
||||
// frames.pop_front();
|
||||
// }
|
||||
|
||||
// return datagram;
|
||||
// }
|
||||
|
||||
// void QuicrReliabilityUnit::process_frame(QuicrFrame frame) {
|
||||
// if(frame.is_reliable) {
|
||||
// if(m_largest_received == frame.frame_number) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if(m_largest_received < frame.frame_number) {
|
||||
// m_ack_bitfield <<= (frame.frame_number - m_largest_received);
|
||||
// m_largest_received = frame.frame_number;
|
||||
// } else if(m_largest_received > frame.frame_number) {
|
||||
// m_ack_bitfield |= (1ULL << (m_largest_received - frame.frame_number));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
bool QuicrReliabilityUnit::has_reliable_frames_to_resend() {
|
||||
return std::any_of(awaiting_ack_frames.begin(), awaiting_ack_frames.end(),
|
||||
[](const auto& t) { return t.second->deadline < std::chrono::steady_clock::now(); });
|
||||
}
|
||||
|
||||
void QuicrReliabilityUnit::push_ack(uint32_t packet_number) {
|
||||
m_acks_to_send.push_back(packet_number);
|
||||
}
|
||||
|
||||
void QuicrReliabilityUnit::on_ack_received(uint32_t packet_number) {
|
||||
auto packet = packets_in_flight.find(packet_number);
|
||||
if(packet != packets_in_flight.end()) {
|
||||
for(auto frame : packet->second.frame_numbers) {
|
||||
if(awaiting_ack_frames.erase(frame) == 0) {
|
||||
spdlog::error("Failed to erase frame {} from awaiting_ack_frames", frame);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::erase_if(packets_in_flight, [frame, packet_number](auto& packet) {
|
||||
// skip current packet
|
||||
if(packet.second.packet_number == packet_number) {
|
||||
return false;
|
||||
}
|
||||
|
||||
packet.second.frame_numbers.erase(frame);
|
||||
return packet.second.frame_numbers.empty();
|
||||
});
|
||||
}
|
||||
|
||||
packets_in_flight.erase(packet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// m_acks_to_send.push_back(frame_idx);
|
||||
// std::erase_if(awaiting_ack_frames,
|
||||
// [frame_idx](const auto& t) {
|
||||
// return t.second.frame_number == frame_idx;
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
std::vector<QuicrFrame> QuicrReliabilityUnit::pop_frames_to_resend(uint32_t new_packet_number) {
|
||||
std::vector<QuicrFrame> resend_frames;
|
||||
|
||||
auto packet = packets_in_flight.try_emplace(new_packet_number, QuicrReliablePacket{new_packet_number, {}});
|
||||
|
||||
for(auto frame : awaiting_ack_frames) {
|
||||
if(frame.second->deadline < Clock::now()) {
|
||||
resend_frames.push_back(std::move(frame.second->frame));
|
||||
packet.first->second.frame_numbers.insert(frame.first);
|
||||
frame.second->deadline = Clock::now() + std::chrono::milliseconds(TW_NET_HELLO_RETRY_INTERVAL_IN_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
// std::erase_if(awaiting_ack_frames, [&resend_frames](const auto& item) {
|
||||
// if(item.first < std::chrono::steady_clock::now()) {
|
||||
// resend_frames.push_back(item.second);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// });
|
||||
return resend_frames;
|
||||
}
|
||||
|
||||
void QuicrReliabilityUnit::push_reliable_frame(Clock::time_point deadline, QuicrFrame&& frame) {
|
||||
frame.is_reliable = true;
|
||||
frame.frame_number = next_frame_number();
|
||||
auto frame_number = frame.frame_number;
|
||||
awaiting_ack_frames[frame_number] = new QuicrReliableFrame{deadline, std::move(frame)};
|
||||
|
||||
// awaiting_ack_frames.emplace_back(deadline, frame);
|
||||
}
|
||||
|
||||
void QuicrReliabilityUnit::push_reliable_frame(Clock::time_point deadline, QuicrFrame& frame) {
|
||||
frame.is_reliable = true;
|
||||
frame.frame_number = next_frame_number();
|
||||
auto frame_number = frame.frame_number;
|
||||
awaiting_ack_frames[frame_number] = new QuicrReliableFrame{deadline, std::move(frame)};
|
||||
// awaiting_ack_frames.emplace_back(deadline, frame);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> QuicrReliabilityUnit::pop_acks_to_send() {
|
||||
auto acks = std::vector<uint32_t>(m_acks_to_send);
|
||||
|
||||
m_acks_to_send.clear();
|
||||
|
||||
return acks;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user