49 return "waiting_server_hello";
51 return "waiting_finished";
64 : is_server_(is_server)
65 , initial_dcid_(initial_dcid)
66 , peer_cid_manager_(8)
67 , stream_mgr_(is_server)
69 , loss_detector_(rtt_estimator_)
112 for (
const auto& [seq, existing_cid] : local_cids_)
117 "Duplicate connection ID sequence",
122 local_cids_.emplace_back(sequence, cid);
128 auto it = std::find_if(local_cids_.begin(), local_cids_.end(),
129 [sequence](
const auto& p) { return p.first == sequence; });
131 if (it == local_cids_.end())
134 "Connection ID not found",
139 if (local_cids_.size() <= 1)
142 "Cannot retire last connection ID",
146 local_cids_.erase(it);
190 std::chrono::milliseconds(timeout);
207 span->set_attribute(
"quic.role",
"client")
208 .set_attribute(
"quic.server_name", server_name)
209 .set_attribute(
"net.transport",
"udp")
210 .set_attribute(
"quic.version",
"1");
217 span->set_error(
"Server cannot start handshake");
220 "Server cannot start handshake",
228 span->set_error(
"Connection already started");
231 "Connection already started",
236 auto init_result = crypto_.init_client(server_name);
237 if (init_result.is_err())
241 span->set_error(init_result.error().message);
244 "Failed to initialize crypto",
250 auto derive_result = crypto_.derive_initial_secrets(initial_dcid_);
251 if (derive_result.is_err())
255 span->set_error(derive_result.error().message);
258 "Failed to derive initial secrets",
260 derive_result.error().
message);
264 auto hs_result = crypto_.start_handshake();
265 if (hs_result.is_err())
269 span->set_error(hs_result.error().message);
272 "Failed to start TLS handshake",
278 if (!hs_result.value().empty())
280 pending_crypto_initial_.push_back(std::move(hs_result.value()));
289 span->set_attribute(
"quic.state",
"handshaking");
292 return ok(std::vector<uint8_t>{});
303 span->set_attribute(
"quic.role",
"server")
304 .set_attribute(
"net.transport",
"udp")
305 .set_attribute(
"quic.version",
"1");
312 span->set_error(
"Not a server connection");
315 "Not a server connection",
319 auto result = crypto_.init_server(cert_file, key_file);
324 span->set_error(result.error().message);
327 "Failed to initialize server crypto",
329 result.error().message);
333 auto derive_result = crypto_.derive_initial_secrets(initial_dcid_);
334 if (derive_result.is_err())
338 span->set_error(derive_result.error().message);
341 "Failed to derive initial secrets",
343 derive_result.error().message);
349 span->set_attribute(
"quic.state",
"handshaking");
365 span->set_attribute(
"quic.packet.size",
static_cast<int64_t
>(data.size()))
366 .set_attribute(
"quic.role", is_server_ ?
"server" :
"client")
374 span->set_error(
"Empty packet");
381 if (is_draining() || is_closed())
385 bytes_received_ += data.size();
388 span->set_attribute(
"quic.packet.ignored",
true);
393 bytes_received_ += data.size();
401 if (parse_result.is_err())
404 "Failed to parse long header",
406 parse_result.error().message);
409 auto [header, header_len] = parse_result.value();
410 return process_long_header_packet(header, data.subspan(header_len));
415 if (parse_result.is_err())
418 "Failed to parse short header",
420 parse_result.error().message);
423 auto [header, header_len] = parse_result.value();
424 return process_short_header_packet(header, data.subspan(header_len));
429 std::span<const uint8_t> payload)
437 pending_ack_initial_ =
true;
441 pending_ack_handshake_ =
true;
451 "Unknown packet type",
456 if (remote_cid_.length() == 0)
458 remote_cid_ = hdr.src_conn_id;
459 peer_cid_manager_.set_initial_peer_cid(hdr.src_conn_id);
463 if (is_server_ && !local_params_.original_destination_connection_id)
465 local_params_.original_destination_connection_id = hdr.dest_conn_id;
469 auto keys_result = crypto_.get_read_keys(level);
470 if (keys_result.is_err())
477 auto& space = get_pn_space(level);
478 if (hdr.packet_number > space.largest_received)
480 space.largest_received = hdr.packet_number;
481 space.largest_received_time = std::chrono::steady_clock::now();
483 space.ack_needed =
true;
485 return process_frames(payload, level);
489 std::span<const uint8_t> payload)
496 "Received 1-RTT packet before handshake complete",
500 pending_ack_app_ =
true;
504 if (keys_result.is_err())
507 "1-RTT keys not available",
512 auto& space = app_space_;
513 if (hdr.packet_number > space.largest_received)
515 space.largest_received = hdr.packet_number;
516 space.largest_received_time = std::chrono::steady_clock::now();
518 space.ack_needed =
true;
528 if (frames_result.is_err())
531 "Failed to parse frames",
533 frames_result.error().message);
537 for (
const auto& f : frames_result.value())
539 auto result = handle_frame(f, level);
556 using T = std::decay_t<
decltype(f)>;
558 if constexpr (std::is_same_v<T, padding_frame>)
563 else if constexpr (std::is_same_v<T, ping_frame>)
568 else if constexpr (std::is_same_v<T, ack_frame>)
571 auto recv_time = std::chrono::steady_clock::now();
572 auto result = loss_detector_.on_ack_received(f, level, recv_time);
575 handle_loss_detection_result(result);
578 loss_detector_.reset_pto_count();
581 if (crypto_.is_handshake_complete())
583 loss_detector_.set_handshake_confirmed(
true);
587 auto& space = get_pn_space(level);
588 if (f.largest_acknowledged > space.largest_acked)
590 space.largest_acked = f.largest_acknowledged;
594 for (
auto it = space.sent_packets.begin();
595 it != space.sent_packets.end();)
597 if (it->first <= f.largest_acknowledged)
599 it = space.sent_packets.erase(it);
608 else if constexpr (std::is_same_v<T, crypto_frame>)
611 auto result = crypto_.process_crypto_data(level,
612 std::span<const uint8_t>(f.data.data(), f.data.size()));
616 "Failed to process crypto data",
618 result.error().message);
622 if (!result.value().empty())
627 pending_crypto_initial_.push_back(std::move(result.value()));
630 pending_crypto_handshake_.push_back(std::move(result.value()));
633 pending_crypto_app_.push_back(std::move(result.value()));
640 else if constexpr (std::is_same_v<T, stream_frame>)
643 auto stream_result = stream_mgr_.get_or_create_stream(f.stream_id);
644 if (stream_result.is_err())
647 "Failed to get stream",
649 stream_result.error().message);
653 auto recv_result = stream_result.value()->receive_data(
655 std::span<const uint8_t>(f.data.data(), f.data.size()),
657 if (recv_result.is_err())
663 auto recv_flow = flow_ctrl_.record_received(f.data.size());
664 if (recv_flow.is_err())
670 else if constexpr (std::is_same_v<T, max_data_frame>)
672 flow_ctrl_.update_send_limit(f.maximum_data);
675 else if constexpr (std::is_same_v<T, max_stream_data_frame>)
677 auto* s = stream_mgr_.get_stream(f.stream_id);
680 s->set_max_send_data(f.maximum_stream_data);
684 else if constexpr (std::is_same_v<T, max_streams_frame>)
688 stream_mgr_.set_peer_max_streams_bidi(f.maximum_streams);
692 stream_mgr_.set_peer_max_streams_uni(f.maximum_streams);
696 else if constexpr (std::is_same_v<T, connection_close_frame>)
698 close_error_code_ = f.error_code;
699 close_reason_ = f.reason_phrase;
700 close_received_ =
true;
701 application_close_ = f.is_application_error;
705 else if constexpr (std::is_same_v<T, handshake_done_frame>)
714 else if constexpr (std::is_same_v<T, reset_stream_frame>)
716 auto* s = stream_mgr_.get_stream(f.stream_id);
719 return s->receive_reset(f.application_error_code, f.final_size);
723 else if constexpr (std::is_same_v<T, stop_sending_frame>)
725 auto* s = stream_mgr_.get_stream(f.stream_id);
728 return s->receive_stop_sending(f.application_error_code);
732 else if constexpr (std::is_same_v<T, new_connection_id_frame>)
737 f.connection_id.data(), f.connection_id.size()));
739 auto result = peer_cid_manager_.add_peer_cid(
743 f.stateless_reset_token);
748 "Failed to process NEW_CONNECTION_ID",
750 result.error().message);
754 else if constexpr (std::is_same_v<T, retire_connection_id_frame>)
756 return retire_cid(f.sequence_number);
758 else if constexpr (std::is_same_v<T, data_blocked_frame> ||
759 std::is_same_v<T, stream_data_blocked_frame> ||
760 std::is_same_v<T, streams_blocked_frame> ||
761 std::is_same_v<T, path_challenge_frame> ||
762 std::is_same_v<T, path_response_frame> ||
763 std::is_same_v<T, new_token_frame>)
782 std::vector<std::vector<uint8_t>> packets;
790 if (close_sent_ && !close_received_)
795 packets.push_back(std::move(pkt));
801 if (!pending_crypto_initial_.empty() || pending_ack_initial_)
806 packets.push_back(std::move(pkt));
807 pending_ack_initial_ =
false;
812 if (!pending_crypto_handshake_.empty() || pending_ack_handshake_)
817 packets.push_back(std::move(pkt));
818 pending_ack_handshake_ =
false;
832 if (has_pending_data() || pending_ack_app_)
837 packets.push_back(std::move(pkt));
838 pending_ack_app_ =
false;
848 std::vector<uint8_t> packet;
851 auto keys_result = crypto_.get_write_keys(level);
852 if (keys_result.is_err())
857 auto& space = get_pn_space(level);
858 uint64_t pn = space.next_pn++;
861 std::vector<uint8_t> header;
866 remote_cid_, local_cid_, {}, pn);
870 remote_cid_, local_cid_, pn);
874 remote_cid_, pn, crypto_.key_phase());
881 std::vector<uint8_t> payload;
884 if (space.ack_needed)
886 auto ack = generate_ack_frame(space);
890 payload.insert(payload.end(), encoded.begin(), encoded.end());
891 space.ack_needed =
false;
896 std::deque<std::vector<uint8_t>>* crypto_queue =
nullptr;
900 crypto_queue = &pending_crypto_initial_;
903 crypto_queue = &pending_crypto_handshake_;
906 crypto_queue = &pending_crypto_app_;
910 uint64_t crypto_offset = 0;
911 while (!crypto_queue->empty())
913 auto& data = crypto_queue->front();
915 cf.
offset = crypto_offset;
916 cf.
data = std::move(data);
917 crypto_offset += cf.
data.size();
920 payload.insert(payload.end(), encoded.begin(), encoded.end());
921 crypto_queue->pop_front();
930 payload.insert(payload.end(), encoded.begin(), encoded.end());
937 ccf.
error_code = close_error_code_.value_or(0);
941 payload.insert(payload.end(), encoded.begin(), encoded.end());
947 auto retire_frames = peer_cid_manager_.get_pending_retire_frames();
948 for (
const auto& rf : retire_frames)
951 payload.insert(payload.end(), encoded.begin(), encoded.end());
953 if (!retire_frames.empty())
955 peer_cid_manager_.clear_pending_retire_frames();
962 while (!pending_frames_.empty())
964 const auto& f = pending_frames_.front();
966 payload.insert(payload.end(), encoded.begin(), encoded.end());
967 pending_frames_.pop_front();
974 auto streams = stream_mgr_.streams_with_pending_data();
975 for (
auto* s : streams)
977 if (
auto sf = s->next_stream_frame(1200))
980 payload.insert(payload.end(), encoded.begin(), encoded.end());
993 size_t min_size = 1200;
994 size_t current_size = header.size() + payload.size() + 16;
995 if (current_size < min_size)
998 payload.insert(payload.end(), encoded.begin(), encoded.end());
1004 keys_result.value(),
1005 std::span<const uint8_t>(header.data(), header.size()),
1006 std::span<const uint8_t>(payload.data(), payload.size()),
1009 if (protect_result.is_err())
1014 packet = std::move(protect_result.value());
1018 info.packet_number = pn;
1019 info.sent_time = std::chrono::steady_clock::now();
1020 info.sent_bytes = packet.size();
1021 info.ack_eliciting = !payload.empty();
1022 info.in_flight =
true;
1036 sent_pkt.
level = info.level;
1037 loss_detector_.on_packet_sent(sent_pkt);
1042 congestion_controller_.on_packet_sent(info.sent_bytes);
1045 space.sent_packets[pn] = std::move(info);
1047 bytes_sent_ += packet.size();
1093 return initial_space_;
1095 return handshake_space_;
1108 return initial_space_;
1110 return handshake_space_;
1144 span->set_attribute(
"quic.close.error_code",
static_cast<int64_t
>(error_code))
1145 .set_attribute(
"quic.close.reason", reason)
1146 .set_attribute(
"quic.close.type",
"transport")
1147 .set_attribute(
"quic.role", is_server_ ?
"server" :
"client");
1151 if (is_closed() || is_draining())
1155 span->set_attribute(
"quic.close.already_closing",
true);
1160 close_error_code_ = error_code;
1161 close_reason_ = reason;
1163 application_close_ =
false;
1168 span->set_attribute(
"quic.state",
"closing");
1182 span->set_attribute(
"quic.close.error_code",
static_cast<int64_t
>(error_code))
1183 .set_attribute(
"quic.close.reason", reason)
1184 .set_attribute(
"quic.close.type",
"application")
1185 .set_attribute(
"quic.role", is_server_ ?
"server" :
"client");
1189 if (is_closed() || is_draining())
1193 span->set_attribute(
"quic.close.already_closing",
true);
1198 close_error_code_ = error_code;
1199 close_reason_ = reason;
1201 application_close_ =
true;
1206 span->set_attribute(
"quic.state",
"closing");
1222 auto pto = std::chrono::milliseconds(100);
1236 auto pto = std::chrono::milliseconds(100);
1255 std::chrono::milliseconds(timeout);
1260 -> std::optional<std::chrono::steady_clock::time_point>
1264 return std::nullopt;
1274 if (loss_timeout.has_value())
1284 auto now = std::chrono::steady_clock::now();
1304 if (loss_timeout.has_value() && now >= *loss_timeout)
1316 -> std::optional<ack_frame>
1318 if (space.largest_received == 0 && !space.ack_needed)
1320 return std::nullopt;
1325 ack.ack_delay = std::chrono::duration_cast<std::chrono::microseconds>(
1326 std::chrono::steady_clock::now() - space.largest_received_time)
1341 switch (result.
event)
1363 auto ack_time = std::chrono::steady_clock::now();
1407 switch (probe_level)
1437 const auto level = lost_packet.
level;
1439 for (
const auto& f : lost_packet.
frames)
1442 [
this, level](
const auto& frm)
1444 using T = std::decay_t<
decltype(frm)>;
1447 if constexpr (std::is_same_v<T, padding_frame> ||
1448 std::is_same_v<T, ack_frame>)
1452 else if constexpr (std::is_same_v<T, crypto_frame>)
1469 else if constexpr (std::is_same_v<T, stream_frame>)
1478 else if constexpr (std::is_same_v<T, ping_frame> ||
1479 std::is_same_v<T, new_token_frame> ||
1480 std::is_same_v<T, handshake_done_frame>)
1485 else if constexpr (std::is_same_v<T, max_data_frame> ||
1486 std::is_same_v<T, max_stream_data_frame> ||
1487 std::is_same_v<T, max_streams_frame> ||
1488 std::is_same_v<T, data_blocked_frame> ||
1489 std::is_same_v<T, stream_data_blocked_frame> ||
1490 std::is_same_v<T, streams_blocked_frame>)
1495 else if constexpr (std::is_same_v<T, reset_stream_frame> ||
1496 std::is_same_v<T, stop_sending_frame>)
1501 else if constexpr (std::is_same_v<T, new_connection_id_frame> ||
1502 std::is_same_v<T, retire_connection_id_frame>)
1507 else if constexpr (std::is_same_v<T, path_challenge_frame> ||
1508 std::is_same_v<T, path_response_frame>)
1513 else if constexpr (std::is_same_v<T, connection_close_frame>)
1531 pkt.
level = info.level;
1532 pkt.
frames = info.frames;
1553 return peer_cid_manager_.rotate_peer_cid();
auto on_packet_acked(const sent_packet &packet, std::chrono::steady_clock::time_point ack_time) -> void
Handle packet acknowledgment (RFC 9002 Section 7.3)
auto set_max_datagram_size(size_t size) -> void
Set max datagram size.
auto on_packet_lost(const sent_packet &packet) -> void
Handle packet loss (RFC 9002 Section 7.3.2)
auto on_ecn_congestion(std::chrono::steady_clock::time_point sent_time) -> void
Handle ECN congestion signal (RFC 9002 Section 7.1)
auto peer_cid_count() const -> size_t
Get the current number of peer CIDs (including retired)
void set_active_cid_limit(uint64_t limit)
Set the active connection ID limit.
auto get_active_peer_cid() const -> const connection_id &
Get the currently active peer connection ID.
void set_initial_peer_cid(const connection_id &cid)
Set the initial peer connection ID (from Initial packet)
QUIC Connection ID (RFC 9000 Section 5.1)
static auto generate(size_t length=8) -> connection_id
Generate a random connection ID.
std::chrono::steady_clock::time_point idle_deadline_
void generate_probe_packets()
Generate probe packets for PTO (RFC 9002 Section 6.2.4) Sends one or two ack-eliciting packets to pro...
void enable_pmtud()
Enable Path MTU Discovery.
std::deque< std::vector< uint8_t > > pending_crypto_app_
auto handle_frame(const frame &frame, encryption_level level) -> VoidResult
Handle a specific frame.
void disable_pmtud()
Disable Path MTU Discovery.
loss_detector loss_detector_
connection_id_manager peer_cid_manager_
std::deque< std::vector< uint8_t > > pending_crypto_initial_
pmtud_controller pmtud_controller_
void update_state()
Update connection state based on handshake progress.
auto next_timeout() const -> std::optional< std::chrono::steady_clock::time_point >
Get the next timeout deadline.
auto is_draining() const noexcept -> bool
Check if connection is draining or closing.
std::string close_reason_
auto init_server_handshake(const std::string &cert_file, const std::string &key_file) -> VoidResult
Initialize server handshake.
auto rotate_peer_cid() -> VoidResult
Rotate to a new peer connection ID.
auto receive_packet(std::span< const uint8_t > data) -> VoidResult
Receive and process a packet.
void enter_draining()
Transition to draining state.
auto initial_dcid() const -> const connection_id &
Get initial Destination Connection ID (for key derivation)
void apply_remote_params()
Apply remote transport parameters.
std::chrono::steady_clock::time_point drain_deadline_
auto get_pn_space(encryption_level level) -> packet_number_space &
Get packet number space for an encryption level.
congestion_controller congestion_controller_
bool pending_ack_initial_
auto is_server() const noexcept -> bool
Check if this is a server-side connection.
flow_controller flow_ctrl_
void set_local_params(const transport_parameters ¶ms)
Set local transport parameters.
auto generate_ack_frame(const packet_number_space &space) -> std::optional< ack_frame >
Generate ACK frame for a packet number space.
auto generate_packets() -> std::vector< std::vector< uint8_t > >
Generate packets to send.
void enter_closing()
Transition to closing state.
auto path_mtu() const noexcept -> size_t
Get current path MTU.
std::optional< uint64_t > close_error_code_
std::deque< std::vector< uint8_t > > pending_crypto_handshake_
auto has_pending_data() const -> bool
Check if there are packets to send.
transport_parameters remote_params_
auto retire_cid(uint64_t sequence) -> VoidResult
Retire a Connection ID.
void on_timeout()
Handle timeout event.
auto is_closed() const noexcept -> bool
Check if connection is closed.
void queue_frames_for_retransmission(const sent_packet &lost_packet)
Queue frames from lost packet for retransmission.
auto close(uint64_t error_code, const std::string &reason="") -> VoidResult
Close the connection.
auto process_frames(std::span< const uint8_t > payload, encryption_level level) -> VoidResult
Process frames from a decrypted packet.
auto build_packet(encryption_level level) -> std::vector< uint8_t >
Build a packet at the given encryption level.
bool pending_ack_handshake_
void handle_loss_detection_result(const loss_detection_result &result)
Handle loss detection result (RFC 9002)
auto start_handshake(const std::string &server_name) -> Result< std::vector< uint8_t > >
Start the handshake (client only)
void reset_idle_timer()
Reset idle timer.
connection_id remote_cid_
auto streams() -> stream_manager &
Get the stream manager.
connection(bool is_server, const connection_id &initial_dcid)
Construct a connection.
auto add_local_cid(const connection_id &cid, uint64_t sequence) -> VoidResult
Add a new local Connection ID.
std::vector< std::pair< uint64_t, connection_id > > local_cids_
auto process_short_header_packet(const short_header &hdr, std::span< const uint8_t > payload) -> VoidResult
Process a short header packet.
transport_parameters local_params_
auto close_application(uint64_t error_code, const std::string &reason="") -> VoidResult
Close connection due to application error.
void set_remote_params(const transport_parameters ¶ms)
Set remote transport parameters.
auto process_long_header_packet(const long_header &hdr, std::span< const uint8_t > payload) -> VoidResult
Process a long header packet.
auto active_peer_cid() const -> const connection_id &
Get the currently active peer connection ID.
auto to_sent_packet(const sent_packet_info &info) const -> sent_packet
Convert sent_packet_info to sent_packet for loss detector.
auto pmtud_enabled() const noexcept -> bool
Check if PMTUD is enabled.
stream_manager stream_mgr_
std::deque< frame > pending_frames_
void update_send_limit(uint64_t max_data)
Update the send limit (from peer's MAX_DATA)
static auto build_stream(const stream_frame &f, bool include_length=true) -> std::vector< uint8_t >
Build STREAM frame.
static auto build_ack(const ack_frame &f) -> std::vector< uint8_t >
Build ACK frame.
static auto build_padding(size_t count=1) -> std::vector< uint8_t >
Build PADDING frame.
static auto build_crypto(const crypto_frame &f) -> std::vector< uint8_t >
Build CRYPTO frame.
static auto build(const frame &f) -> std::vector< uint8_t >
Build any frame from variant.
static auto parse_all(std::span< const uint8_t > data) -> Result< std::vector< frame > >
Parse all frames from buffer.
auto on_timeout() -> loss_detection_result
Handle timeout expiry (RFC 9002 Section 6.2)
auto next_timeout() const -> std::optional< std::chrono::steady_clock::time_point >
Get the time of the next scheduled timeout.
static auto build_handshake(const connection_id &dest_cid, const connection_id &src_cid, uint64_t packet_number, uint32_t version=quic_version::version_1) -> std::vector< uint8_t >
Build a Handshake packet header.
static auto build_short(const connection_id &dest_cid, uint64_t packet_number, bool key_phase=false, bool spin_bit=false) -> std::vector< uint8_t >
Build a Short Header (1-RTT) packet.
static auto build_initial(const connection_id &dest_cid, const connection_id &src_cid, const std::vector< uint8_t > &token, uint64_t packet_number, uint32_t version=quic_version::version_1) -> std::vector< uint8_t >
Build an Initial packet header.
static constexpr auto is_long_header(uint8_t first_byte) noexcept -> bool
Check if a packet has a long header.
static auto parse_long_header(std::span< const uint8_t > data) -> Result< std::pair< long_header, size_t > >
Parse a long header packet.
static auto parse_short_header(std::span< const uint8_t > data, size_t conn_id_length) -> Result< std::pair< short_header, size_t > >
Parse a short header packet.
static auto protect(const quic_keys &keys, std::span< const uint8_t > header, std::span< const uint8_t > payload, uint64_t packet_number) -> Result< std::vector< uint8_t > >
Protect (encrypt) a QUIC packet.
auto is_enabled() const noexcept -> bool
Check if PMTUD is enabled.
void enable()
Enable PMTUD and start probing.
auto min_mtu() const noexcept -> size_t
Get minimum MTU.
auto current_mtu() const noexcept -> size_t
Get current validated MTU.
void disable()
Disable PMTUD.
auto get_write_keys(encryption_level level) const -> Result< quic_keys >
Get write keys for an encryption level.
auto is_handshake_complete() const noexcept -> bool
Check if the handshake is complete.
Manages QUIC streams within a connection.
auto streams_with_pending_data() -> std::vector< stream * >
Get streams with pending data to send.
void set_peer_max_streams_uni(uint64_t max)
Set maximum unidirectional streams peer can initiate.
void set_local_max_streams_uni(uint64_t max)
Set our maximum unidirectional streams (advertised to peer)
void set_local_max_streams_bidi(uint64_t max)
Set our maximum bidirectional streams (advertised to peer)
void set_peer_max_streams_bidi(uint64_t max)
Set maximum bidirectional streams peer can initiate.
static auto create_span(std::string_view name) -> span
Create a new root span with a new trace context.
constexpr int not_established
constexpr int invalid_state
constexpr int protocol_violation
constexpr int handshake_failed
@ error
Black hole detected, reset to base.
connection_state
QUIC connection state (RFC 9000 Section 5)
@ connected
Handshake complete, can send/receive data.
@ handshaking
TLS handshake in progress.
@ closed
Connection terminated.
@ closing
CONNECTION_CLOSE sent, waiting for timeout.
@ draining
CONNECTION_CLOSE received, draining period.
@ idle
Connection not yet started.
auto make_default_client_params() -> transport_parameters
Create default client transport parameters.
encryption_level
QUIC encryption levels (RFC 9001 Section 4)
@ application
1-RTT application data encryption
@ handshake
Handshake encryption.
@ initial
Initial encryption (derived from DCID)
@ zero_rtt
0-RTT early data encryption
std::variant< padding_frame, ping_frame, ack_frame, reset_stream_frame, stop_sending_frame, crypto_frame, new_token_frame, stream_frame, max_data_frame, max_stream_data_frame, max_streams_frame, data_blocked_frame, stream_data_blocked_frame, streams_blocked_frame, new_connection_id_frame, retire_connection_id_frame, path_challenge_frame, path_response_frame, connection_close_frame, handshake_done_frame > frame
Variant type holding any QUIC frame.
auto handshake_state_to_string(handshake_state state) -> const char *
Convert handshake state to string.
@ ecn_failure
ECN validation failed, should disable ECN.
@ congestion_signal
ECN-CE increased (congestion experienced)
auto make_default_server_params() -> transport_parameters
Create default server transport parameters.
handshake_state
TLS handshake state.
@ waiting_server_hello
Client waiting for ServerHello.
@ waiting_finished
Waiting for peer's Finished.
@ complete
Handshake complete.
auto connection_state_to_string(connection_state state) -> const char *
Convert connection state to string.
@ packet_lost
Packet(s) declared lost.
@ pto_expired
Probe timeout expired.
auto is_tracing_enabled() -> bool
Check if tracing is enabled.
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
RAII span implementation for distributed tracing.
ACK frame (RFC 9000 Section 19.3)
uint64_t largest_acknowledged
Largest packet number acknowledged.
CONNECTION_CLOSE frame (RFC 9000 Section 19.19)
uint64_t error_code
Error code indicating reason.
std::string reason_phrase
Human-readable reason.
bool is_application_error
True if application-level error.
CRYPTO frame (RFC 9000 Section 19.6)
uint64_t offset
Byte offset in crypto stream.
std::vector< uint8_t > data
Cryptographic handshake data.
HANDSHAKE_DONE frame (RFC 9000 Section 19.20)
Result of loss detection operations.
loss_detection_event event
Event that occurred.
ecn_result ecn_signal
ECN signal from ACK_ECN frame processing.
std::chrono::steady_clock::time_point ecn_congestion_sent_time
Sent time of the packet that triggered ECN congestion signal (used for congestion recovery tracking)
std::vector< sent_packet > acked_packets
Packets that were acknowledged.
std::vector< sent_packet > lost_packets
Packets that were declared lost.
State for each packet number space (Initial, Handshake, Application)
PING frame (RFC 9000 Section 19.2)
Information about a sent packet for loss detection.
Information about a sent packet for loss detection (RFC 9002 Section A.1.1)
encryption_level level
Encryption level of the packet.
std::chrono::steady_clock::time_point sent_time
Time the packet was sent.
size_t sent_bytes
Number of bytes in the packet.
bool in_flight
True if the packet is in flight (counted for congestion control)
bool ack_eliciting
True if this packet is ack-eliciting.
std::vector< frame > frames
Frames included in this packet (for retransmission)
uint64_t packet_number
Packet number.
QUIC transport parameters (RFC 9000 Section 18)
uint64_t max_idle_timeout
Maximum idle timeout in milliseconds (0 = disabled)
uint64_t initial_max_data
Initial maximum data for connection (default: 0)
uint64_t initial_max_streams_uni
Initial maximum unidirectional streams.
uint64_t initial_max_streams_bidi
Initial maximum bidirectional streams.
std::optional< connection_id > initial_source_connection_id
Initial Source Connection ID.
uint64_t active_connection_id_limit
Maximum number of connection IDs from the peer.
Distributed tracing context for OpenTelemetry-compatible tracing.
Configuration structures for OpenTelemetry tracing.