Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
quic_socket.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#pragma once
6
7#include <asio.hpp>
8#include <functional>
9#include <memory>
10#include <vector>
11#include <array>
12#include <system_error>
13#include <mutex>
14#include <atomic>
15#include <map>
16#include <deque>
17
23
24#if defined(NETWORK_ENABLE_TEST_INJECTION)
25namespace kcenon::network::tests::support
26{
27 class quic_socket_test_access;
28} // namespace kcenon::network::tests::support
29#endif
30
32{
37 enum class quic_role : uint8_t
38 {
39 client = 0,
40 server = 1
41 };
42
47 enum class quic_connection_state : uint8_t
48 {
49 idle = 0,
50 handshake_start = 1,
51 handshake = 2,
52 connected = 3,
53 closing = 4,
54 draining = 5,
55 closed = 6
56 };
57
79 class quic_socket : public std::enable_shared_from_this<quic_socket>
80 {
81 public:
88 using stream_data_callback = std::function<void(
89 uint64_t stream_id,
90 std::span<const uint8_t> data,
91 bool fin)>;
92
96 using connected_callback = std::function<void()>;
97
102 using error_callback = std::function<void(std::error_code)>;
103
109 using close_callback = std::function<void(uint64_t error_code, const std::string& reason)>;
110
116 quic_socket(asio::ip::udp::socket socket, quic_role role);
117
121 ~quic_socket();
122
123 // Non-copyable
124 quic_socket(const quic_socket&) = delete;
126
127 // Movable
128 quic_socket(quic_socket&& other) noexcept;
129 quic_socket& operator=(quic_socket&& other) noexcept;
130
131 // =====================================================================
132 // Callback Registration
133 // =====================================================================
134
140
146
151 auto set_error_callback(error_callback cb) -> void;
152
157 auto set_close_callback(close_callback cb) -> void;
158
159 // =====================================================================
160 // Connection Management
161 // =====================================================================
162
169 [[nodiscard]] auto connect(const asio::ip::udp::endpoint& endpoint,
170 const std::string& server_name = "") -> VoidResult;
171
178 [[nodiscard]] auto accept(const std::string& cert_file,
179 const std::string& key_file) -> VoidResult;
180
187 [[nodiscard]] auto close(uint64_t error_code = 0,
188 const std::string& reason = "") -> VoidResult;
189
190 // =====================================================================
191 // I/O Operations
192 // =====================================================================
193
200 auto start_receive() -> void;
201
205 auto stop_receive() -> void;
206
214 [[nodiscard]] auto send_stream_data(uint64_t stream_id,
215 std::vector<uint8_t>&& data,
216 bool fin = false) -> VoidResult;
217
218 // =====================================================================
219 // Stream Management
220 // =====================================================================
221
227 [[nodiscard]] auto create_stream(bool unidirectional = false) -> Result<uint64_t>;
228
234 [[nodiscard]] auto close_stream(uint64_t stream_id) -> VoidResult;
235
236 // =====================================================================
237 // State Queries
238 // =====================================================================
239
244 [[nodiscard]] auto is_connected() const noexcept -> bool;
245
250 [[nodiscard]] auto is_handshake_complete() const noexcept -> bool;
251
256 [[nodiscard]] auto state() const noexcept -> quic_connection_state;
257
262 [[nodiscard]] auto role() const noexcept -> quic_role;
263
268 [[nodiscard]] auto remote_endpoint() const -> asio::ip::udp::endpoint;
269
274 [[nodiscard]] auto local_connection_id() const
275 -> const protocols::quic::connection_id&;
276
281 [[nodiscard]] auto remote_connection_id() const
282 -> const protocols::quic::connection_id&;
283
284 // =====================================================================
285 // Socket Access
286 // =====================================================================
287
292 auto socket() -> asio::ip::udp::socket& { return udp_socket_; }
293
298 auto socket() const -> const asio::ip::udp::socket& { return udp_socket_; }
299
300 // =====================================================================
301 // Connection statistics
302 // =====================================================================
303
308 [[nodiscard]] auto negotiated_alpn() const -> std::string;
309
311 [[nodiscard]] auto packets_sent() const noexcept -> uint64_t
312 {
313 return packets_sent_.load(std::memory_order_relaxed);
314 }
315
317 [[nodiscard]] auto packets_received() const noexcept -> uint64_t
318 {
319 return packets_received_.load(std::memory_order_relaxed);
320 }
321
323 [[nodiscard]] auto bytes_sent() const noexcept -> uint64_t
324 {
325 return bytes_sent_.load(std::memory_order_relaxed);
326 }
327
329 [[nodiscard]] auto bytes_received() const noexcept -> uint64_t
330 {
331 return bytes_received_.load(std::memory_order_relaxed);
332 }
333
334 private:
335 // =====================================================================
336 // Internal Methods
337 // =====================================================================
338
342 auto do_receive() -> void;
343
348 auto handle_packet(std::span<const uint8_t> data) -> void;
349
354 auto process_frame(const protocols::quic::frame& f) -> void;
355
361
367
372 auto process_ack_frame(const protocols::quic::ack_frame& f) -> void;
373
380
384 auto process_handshake_done_frame() -> void;
385
389 auto send_pending_packets() -> void;
390
397 [[nodiscard]] auto send_packet(
399 std::vector<protocols::quic::frame>&& frames) -> VoidResult;
400
405 auto queue_crypto_data(std::vector<uint8_t>&& data) -> void;
406
412 [[nodiscard]] auto determine_encryption_level(
413 const protocols::quic::packet_header& header) const noexcept
415
420 [[nodiscard]] auto generate_connection_id()
422
426 auto on_retransmit_timeout() -> void;
427
432 auto transition_state(quic_connection_state new_state) -> void;
433
434 // =====================================================================
435 // Member Variables
436 // =====================================================================
437
439 asio::ip::udp::socket udp_socket_;
440
442 asio::ip::udp::endpoint remote_endpoint_;
443
445 std::array<uint8_t, 65536> recv_buffer_;
446
449
451 std::atomic<quic_connection_state> state_{quic_connection_state::idle};
452
454 std::atomic<uint64_t> packets_sent_{0};
455 std::atomic<uint64_t> packets_received_{0};
456 std::atomic<uint64_t> bytes_sent_{0};
457 std::atomic<uint64_t> bytes_received_{0};
458
461
464
467
469 std::array<uint64_t, 4> next_packet_number_{0, 0, 0, 0};
470
472 std::array<uint64_t, 4> largest_received_pn_{0, 0, 0, 0};
473
475 uint64_t next_stream_id_{0};
476
477 // =====================================================================
478 // Pending Data Queues
479 // =====================================================================
480
482 std::array<std::deque<std::vector<uint8_t>>, 4> pending_crypto_data_;
483
485 std::map<uint64_t, std::deque<std::pair<std::vector<uint8_t>, bool>>> pending_stream_data_;
486
487 // =====================================================================
488 // Callbacks
489 // =====================================================================
490
492 mutable std::mutex callback_mutex_;
493
496
499
502
505
506 // =====================================================================
507 // State Flags
508 // =====================================================================
509
511 std::atomic<bool> is_receiving_{false};
512
514 std::atomic<bool> handshake_complete_{false};
515
516 // =====================================================================
517 // Timers
518 // =====================================================================
519
521 asio::steady_timer retransmit_timer_;
522
524 asio::steady_timer idle_timer_;
525
527 mutable std::mutex state_mutex_;
528
529#if defined(NETWORK_ENABLE_TEST_INJECTION)
530 // Test-only: grants tests/support/quic_socket_test_access access to
531 // the private dispatcher entry points (process_frame, process_*_frame,
532 // determine_encryption_level, queue_crypto_data, transition_state,
533 // send_pending_packets, on_retransmit_timeout) and selected state
534 // members so tests/unit/quic_socket_dispatcher_branch_test.cpp can
535 // drive frame-dispatch branches without a live UDP peer + TLS-1.3
536 // handshake (Issue #1122).
537 friend class kcenon::network::tests::support::quic_socket_test_access;
538#endif
539 };
540
541} // namespace kcenon::network::internal
A QUIC socket that wraps UDP and integrates QUIC packet protection.
Definition quic_socket.h:80
auto local_connection_id() const -> const protocols::quic::connection_id &
Get the local connection ID.
auto determine_encryption_level(const protocols::quic::packet_header &header) const noexcept -> protocols::quic::encryption_level
Determine encryption level from packet header.
std::function< void( uint64_t stream_id, std::span< const uint8_t > data, bool fin)> stream_data_callback
Callback for receiving stream data.
Definition quic_socket.h:88
auto on_retransmit_timeout() -> void
Retransmission timeout handler.
auto remote_connection_id() const -> const protocols::quic::connection_id &
Get the remote connection ID.
stream_data_callback stream_data_cb_
Stream data callback.
std::function< void(uint64_t error_code, const std::string &reason)> close_callback
Callback when connection is closed.
std::atomic< quic_connection_state > state_
Connection state.
auto process_frame(const protocols::quic::frame &f) -> void
Process a parsed frame.
auto connect(const asio::ip::udp::endpoint &endpoint, const std::string &server_name="") -> VoidResult
Connect to a remote server (client only)
auto process_connection_close_frame(const protocols::quic::connection_close_frame &f) -> void
Process CONNECTION_CLOSE frame.
auto transition_state(quic_connection_state new_state) -> void
Transition to a new connection state.
auto socket() const -> const asio::ip::udp::socket &
Access the underlying UDP socket (const)
auto packets_received() const noexcept -> uint64_t
Total QUIC packets received on this socket.
asio::ip::udp::socket udp_socket_
Underlying UDP socket.
auto bytes_sent() const noexcept -> uint64_t
Total bytes sent on this socket (protected packet sizes).
std::array< uint64_t, 4 > next_packet_number_
Packet number for each encryption level.
std::mutex callback_mutex_
Mutex for callback protection.
std::atomic< bool > is_receiving_
Is receive loop running.
auto state() const noexcept -> quic_connection_state
Get the current connection state.
protocols::quic::connection_id remote_conn_id_
Remote connection ID.
std::atomic< uint64_t > packets_received_
auto send_stream_data(uint64_t stream_id, std::vector< uint8_t > &&data, bool fin=false) -> VoidResult
Send data on a stream.
std::map< uint64_t, std::deque< std::pair< std::vector< uint8_t >, bool > > > pending_stream_data_
Pending stream data to send (stream_id -> data queue)
connected_callback connected_cb_
Connected callback.
auto process_handshake_done_frame() -> void
Process HANDSHAKE_DONE frame.
auto is_handshake_complete() const noexcept -> bool
Check if the TLS handshake is complete.
auto create_stream(bool unidirectional=false) -> Result< uint64_t >
Create a new stream.
auto queue_crypto_data(std::vector< uint8_t > &&data) -> void
Queue crypto data for sending.
std::atomic< bool > handshake_complete_
Is handshake complete.
std::array< uint8_t, 65536 > recv_buffer_
Receive buffer (max UDP datagram size)
auto socket() -> asio::ip::udp::socket &
Access the underlying UDP socket.
auto process_ack_frame(const protocols::quic::ack_frame &f) -> void
Process ACK frame.
std::atomic< uint64_t > bytes_sent_
auto packets_sent() const noexcept -> uint64_t
Total QUIC packets sent on this socket.
auto send_pending_packets() -> void
Send pending outgoing packets.
auto process_stream_frame(const protocols::quic::stream_frame &f) -> void
Process STREAM frame data.
auto send_packet(protocols::quic::encryption_level level, std::vector< protocols::quic::frame > &&frames) -> VoidResult
Build and send a packet with frames.
auto role() const noexcept -> quic_role
Get the role (client or server)
quic_socket(asio::ip::udp::socket socket, quic_role role)
Constructs a QUIC socket.
error_callback error_cb_
Error callback.
auto remote_endpoint() const -> asio::ip::udp::endpoint
Get the remote endpoint.
quic_socket(const quic_socket &)=delete
auto handle_packet(std::span< const uint8_t > data) -> void
Handle received packet data.
auto do_receive() -> void
Internal receive loop implementation.
std::array< std::deque< std::vector< uint8_t > >, 4 > pending_crypto_data_
Pending crypto data to send per encryption level.
auto is_connected() const noexcept -> bool
Check if the connection is established.
std::function< void(std::error_code)> error_callback
Callback for error handling.
quic_role role_
Socket role (client/server)
uint64_t next_stream_id_
Next stream ID to allocate.
std::atomic< uint64_t > bytes_received_
auto generate_connection_id() -> protocols::quic::connection_id
Generate a new connection ID.
protocols::quic::quic_crypto crypto_
QUIC crypto handler.
std::function< void()> connected_callback
Callback when connection is established.
Definition quic_socket.h:96
auto bytes_received() const noexcept -> uint64_t
Total bytes received on this socket (datagram sizes).
auto close_stream(uint64_t stream_id) -> VoidResult
Close a stream.
protocols::quic::connection_id local_conn_id_
Local connection ID.
auto stop_receive() -> void
Stop the receive loop.
asio::ip::udp::endpoint remote_endpoint_
Remote endpoint.
auto set_stream_data_callback(stream_data_callback cb) -> void
Set callback for stream data reception.
asio::steady_timer retransmit_timer_
Retransmission timer.
auto start_receive() -> void
Start the receive loop.
asio::steady_timer idle_timer_
Idle timeout timer.
auto accept(const std::string &cert_file, const std::string &key_file) -> VoidResult
Accept an incoming connection (server only)
auto set_close_callback(close_callback cb) -> void
Set callback for connection close.
auto negotiated_alpn() const -> std::string
Get the ALPN protocol negotiated during the handshake.
std::array< uint64_t, 4 > largest_received_pn_
Largest received packet number for each level.
std::mutex state_mutex_
Mutex for state protection.
quic_socket & operator=(const quic_socket &)=delete
auto set_connected_callback(connected_callback cb) -> void
Set callback for connection establishment.
std::atomic< uint64_t > packets_sent_
Live transport counters surfaced through quic_connection_stats.
auto process_crypto_frame(const protocols::quic::crypto_frame &f) -> void
Process CRYPTO frame data.
close_callback close_cb_
Close callback.
auto set_error_callback(error_callback cb) -> void
Set callback for errors.
QUIC Connection ID (RFC 9000 Section 5.1)
QUIC-TLS integration handler (RFC 9001)
Definition crypto.h:245
quic_role
Role of the QUIC endpoint (client or server)
Definition quic_socket.h:38
::kcenon::network::VoidResult VoidResult
quic_connection_state
QUIC connection state machine states.
Definition quic_socket.h:48
@ close
Connection close frame.
@ connected
Handshake complete, can send/receive data.
@ closing
CONNECTION_CLOSE sent, waiting for timeout.
@ draining
CONNECTION_CLOSE received, draining period.
encryption_level
QUIC encryption levels (RFC 9001 Section 4)
Definition keys.h:54
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.
std::variant< long_header, short_header > packet_header
Variant type for packet headers.
Definition packet.h:160
Network-specific error and result type definitions.
ACK frame (RFC 9000 Section 19.3)
CONNECTION_CLOSE frame (RFC 9000 Section 19.19)
CRYPTO frame (RFC 9000 Section 19.6)
STREAM frame (RFC 9000 Section 19.8)