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
25{
30 enum class quic_role : uint8_t
31 {
32 client = 0,
33 server = 1
34 };
35
40 enum class quic_connection_state : uint8_t
41 {
42 idle = 0,
43 handshake_start = 1,
44 handshake = 2,
45 connected = 3,
46 closing = 4,
47 draining = 5,
48 closed = 6
49 };
50
72 class quic_socket : public std::enable_shared_from_this<quic_socket>
73 {
74 public:
81 using stream_data_callback = std::function<void(
82 uint64_t stream_id,
83 std::span<const uint8_t> data,
84 bool fin)>;
85
89 using connected_callback = std::function<void()>;
90
95 using error_callback = std::function<void(std::error_code)>;
96
102 using close_callback = std::function<void(uint64_t error_code, const std::string& reason)>;
103
109 quic_socket(asio::ip::udp::socket socket, quic_role role);
110
114 ~quic_socket();
115
116 // Non-copyable
117 quic_socket(const quic_socket&) = delete;
119
120 // Movable
121 quic_socket(quic_socket&& other) noexcept;
122 quic_socket& operator=(quic_socket&& other) noexcept;
123
124 // =====================================================================
125 // Callback Registration
126 // =====================================================================
127
133
139
144 auto set_error_callback(error_callback cb) -> void;
145
150 auto set_close_callback(close_callback cb) -> void;
151
152 // =====================================================================
153 // Connection Management
154 // =====================================================================
155
162 [[nodiscard]] auto connect(const asio::ip::udp::endpoint& endpoint,
163 const std::string& server_name = "") -> VoidResult;
164
171 [[nodiscard]] auto accept(const std::string& cert_file,
172 const std::string& key_file) -> VoidResult;
173
180 [[nodiscard]] auto close(uint64_t error_code = 0,
181 const std::string& reason = "") -> VoidResult;
182
183 // =====================================================================
184 // I/O Operations
185 // =====================================================================
186
193 auto start_receive() -> void;
194
198 auto stop_receive() -> void;
199
207 [[nodiscard]] auto send_stream_data(uint64_t stream_id,
208 std::vector<uint8_t>&& data,
209 bool fin = false) -> VoidResult;
210
211 // =====================================================================
212 // Stream Management
213 // =====================================================================
214
220 [[nodiscard]] auto create_stream(bool unidirectional = false) -> Result<uint64_t>;
221
227 [[nodiscard]] auto close_stream(uint64_t stream_id) -> VoidResult;
228
229 // =====================================================================
230 // State Queries
231 // =====================================================================
232
237 [[nodiscard]] auto is_connected() const noexcept -> bool;
238
243 [[nodiscard]] auto is_handshake_complete() const noexcept -> bool;
244
249 [[nodiscard]] auto state() const noexcept -> quic_connection_state;
250
255 [[nodiscard]] auto role() const noexcept -> quic_role;
256
261 [[nodiscard]] auto remote_endpoint() const -> asio::ip::udp::endpoint;
262
267 [[nodiscard]] auto local_connection_id() const
268 -> const protocols::quic::connection_id&;
269
274 [[nodiscard]] auto remote_connection_id() const
275 -> const protocols::quic::connection_id&;
276
277 // =====================================================================
278 // Socket Access
279 // =====================================================================
280
285 auto socket() -> asio::ip::udp::socket& { return udp_socket_; }
286
291 auto socket() const -> const asio::ip::udp::socket& { return udp_socket_; }
292
293 private:
294 // =====================================================================
295 // Internal Methods
296 // =====================================================================
297
301 auto do_receive() -> void;
302
307 auto handle_packet(std::span<const uint8_t> data) -> void;
308
313 auto process_frame(const protocols::quic::frame& f) -> void;
314
320
326
331 auto process_ack_frame(const protocols::quic::ack_frame& f) -> void;
332
339
343 auto process_handshake_done_frame() -> void;
344
348 auto send_pending_packets() -> void;
349
356 [[nodiscard]] auto send_packet(
358 std::vector<protocols::quic::frame>&& frames) -> VoidResult;
359
364 auto queue_crypto_data(std::vector<uint8_t>&& data) -> void;
365
371 [[nodiscard]] auto determine_encryption_level(
372 const protocols::quic::packet_header& header) const noexcept
374
379 [[nodiscard]] auto generate_connection_id()
381
385 auto on_retransmit_timeout() -> void;
386
391 auto transition_state(quic_connection_state new_state) -> void;
392
393 // =====================================================================
394 // Member Variables
395 // =====================================================================
396
398 asio::ip::udp::socket udp_socket_;
399
401 asio::ip::udp::endpoint remote_endpoint_;
402
404 std::array<uint8_t, 65536> recv_buffer_;
405
408
410 std::atomic<quic_connection_state> state_{quic_connection_state::idle};
411
414
417
420
422 std::array<uint64_t, 4> next_packet_number_{0, 0, 0, 0};
423
425 std::array<uint64_t, 4> largest_received_pn_{0, 0, 0, 0};
426
428 uint64_t next_stream_id_{0};
429
430 // =====================================================================
431 // Pending Data Queues
432 // =====================================================================
433
435 std::array<std::deque<std::vector<uint8_t>>, 4> pending_crypto_data_;
436
438 std::map<uint64_t, std::deque<std::pair<std::vector<uint8_t>, bool>>> pending_stream_data_;
439
440 // =====================================================================
441 // Callbacks
442 // =====================================================================
443
445 mutable std::mutex callback_mutex_;
446
449
452
455
458
459 // =====================================================================
460 // State Flags
461 // =====================================================================
462
464 std::atomic<bool> is_receiving_{false};
465
467 std::atomic<bool> handshake_complete_{false};
468
469 // =====================================================================
470 // Timers
471 // =====================================================================
472
474 asio::steady_timer retransmit_timer_;
475
477 asio::steady_timer idle_timer_;
478
480 mutable std::mutex state_mutex_;
481 };
482
483} // namespace kcenon::network::internal
A QUIC socket that wraps UDP and integrates QUIC packet protection.
Definition quic_socket.h:73
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:81
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)
asio::ip::udp::socket udp_socket_
Underlying UDP socket.
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.
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.
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.
Definition quic_socket.h:95
quic_role role_
Socket role (client/server)
uint64_t next_stream_id_
Next stream ID to allocate.
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:89
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.
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.
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:31
::kcenon::network::VoidResult VoidResult
quic_connection_state
QUIC connection state machine states.
Definition quic_socket.h:41
@ 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)