Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
quic_server.cpp
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
6
7#define NETWORK_USE_EXPERIMENTAL
9
15
16#include <random>
17#include <sstream>
18
20{
21
23 : server_id_(server_id)
24{
25}
26
28{
30 {
31 (void)stop_server(); // Ignore result in destructor
32 }
33}
34
35auto messaging_quic_server::server_id() const -> const std::string&
36{
37 return server_id_;
38}
39
41{
42 return lifecycle_.is_running();
43}
44
46{
47 lifecycle_.wait_for_stop();
48}
49
51{
52 // Use default config with no TLS (for development/testing only)
53 return start_server(port, quic_server_config{});
54}
55
56auto messaging_quic_server::start_server(unsigned short port,
57 const quic_server_config& config)
58 -> VoidResult
59{
60 if (lifecycle_.is_running())
61 {
62 return error_void(
64 "QUIC server is already running",
65 "messaging_quic_server::start_server");
66 }
67
68 config_ = config;
69 lifecycle_.set_running();
70
71 auto result = do_start_impl(port);
72 if (result.is_err())
73 {
74 lifecycle_.mark_stopped();
75 }
76
77 return result;
78}
79
81{
82 if (!lifecycle_.is_running())
83 {
84 return error_void(
86 "QUIC server is not running",
87 "messaging_quic_server::stop_server");
88 }
89
90 if (!lifecycle_.prepare_stop())
91 {
92 return error_void(
94 "QUIC server is already stopping",
95 "messaging_quic_server::stop_server");
96 }
97
98 auto result = do_stop_impl();
99 lifecycle_.mark_stopped();
100
101 return result;
102}
103
105{
106 return start_server(port);
107}
108
110{
111 return stop_server();
112}
113
115{
116 return session_count();
117}
118
120{
121 try
122 {
123 // A previous bind failure can leave a work guard tied to the old
124 // context. Destroy every dependent object before replacing it.
125 if (io_context_)
126 {
127 auto cleanup = do_stop_impl();
128 if (cleanup.is_err()) return cleanup;
129 }
130 // Create io_context
131 io_context_ = std::make_unique<asio::io_context>();
132 work_guard_ = std::make_unique<
133 asio::executor_work_guard<asio::io_context::executor_type>>(
134 asio::make_work_guard(*io_context_));
135
136 // Create UDP socket
137 udp_socket_ = std::make_unique<asio::ip::udp::socket>(
138 *io_context_,
139 asio::ip::udp::endpoint(asio::ip::udp::v4(), port));
140
141 // Create cleanup timer
142 cleanup_timer_ = std::make_unique<asio::steady_timer>(*io_context_);
143
144 // Start receiving packets
145 start_receive();
146
147 // Start periodic cleanup timer
148 start_cleanup_timer();
149
150 // Get thread pool from network context
152 if (!thread_pool_)
153 {
154 thread_pool_ = std::make_shared<integration::basic_thread_pool>(2);
155 }
156
157 // Submit io_context run task to thread pool
158 io_context_future_ = thread_pool_->submit(
159 [this]()
160 {
161 try
162 {
164 "[messaging_quic_server] Starting io_context on thread pool");
165 io_context_->run();
167 "[messaging_quic_server] io_context stopped");
168 }
169 catch (const std::exception& e)
170 {
172 "[messaging_quic_server] Exception in io_context: "
173 + std::string(e.what()));
174 }
175 });
176
177 NETWORK_LOG_INFO("[messaging_quic_server] Started listening on port "
178 + std::to_string(port));
179 return ok();
180 }
181 catch (const std::system_error& e)
182 {
183 if (e.code() == asio::error::address_in_use ||
184 e.code() == std::errc::address_in_use)
185 {
187 "Failed to bind to port: address already in use",
188 "messaging_quic_server::do_start_impl",
189 "Port: " + std::to_string(port));
190 }
191 else if (e.code() == asio::error::access_denied ||
192 e.code() == std::errc::permission_denied)
193 {
195 "Failed to bind to port: permission denied",
196 "messaging_quic_server::do_start_impl",
197 "Port: " + std::to_string(port));
198 }
199
201 "Failed to start server: " + std::string(e.what()),
202 "messaging_quic_server::do_start_impl",
203 "Port: " + std::to_string(port));
204 }
205 catch (const std::exception& e)
206 {
208 "Failed to start server: " + std::string(e.what()),
209 "messaging_quic_server::do_start_impl",
210 "Port: " + std::to_string(port));
211 }
212}
213
215{
216 try
217 {
218 // Release work guard
219 if (work_guard_)
220 {
221 work_guard_.reset();
222 }
223
224 // Stop io_context
225 if (io_context_)
226 {
227 io_context_->stop();
228 }
229
230 // Wait for io_context task
231 if (io_context_future_.valid())
232 {
233 io_context_future_.wait();
234 }
235
236 // The worker may rearm receives or the cleanup timer until run() exits.
237 // Cancel and close their ASIO objects only after it has stopped.
238 if (cleanup_timer_)
239 {
240 cleanup_timer_->cancel();
241 }
242
243 // Close UDP socket
244 if (udp_socket_)
245 {
246 asio::error_code ec;
247 udp_socket_->cancel(ec);
248 if (udp_socket_->is_open())
249 {
250 udp_socket_->close(ec);
251 }
252 }
253
254 // No receive handler can add another session after this point.
255 // Close sessions while their socket and timer context still exists.
256 disconnect_all(0);
257
258 // Release resources
259 udp_socket_.reset();
260 cleanup_timer_.reset();
261 thread_pool_.reset();
262 io_context_.reset();
263
264 NETWORK_LOG_INFO("[messaging_quic_server] Stopped.");
265 return ok();
266 }
267 catch (const std::exception& e)
268 {
270 "Failed to stop server: " + std::string(e.what()),
271 "messaging_quic_server::do_stop_impl",
272 "Server ID: " + server_id_);
273 }
274}
275
277 -> std::vector<std::shared_ptr<session::quic_session>>
278{
279 std::shared_lock<std::shared_mutex> lock(sessions_mutex_);
280 std::vector<std::shared_ptr<session::quic_session>> result;
281 result.reserve(sessions_.size());
282 for (const auto& [id, session] : sessions_)
283 {
284 result.push_back(session);
285 }
286 return result;
287}
288
289auto messaging_quic_server::get_session(const std::string& session_id)
290 -> std::shared_ptr<session::quic_session>
291{
292 std::shared_lock<std::shared_mutex> lock(sessions_mutex_);
293 auto it = sessions_.find(session_id);
294 if (it != sessions_.end())
295 {
296 return it->second;
297 }
298 return nullptr;
299}
300
302{
303 std::shared_lock<std::shared_mutex> lock(sessions_mutex_);
304 return sessions_.size();
305}
306
307auto messaging_quic_server::disconnect_session(const std::string& session_id,
308 uint64_t error_code)
309 -> VoidResult
310{
311 std::shared_ptr<session::quic_session> session;
312 {
313 std::unique_lock<std::shared_mutex> lock(sessions_mutex_);
314 auto it = sessions_.find(session_id);
315 if (it == sessions_.end())
316 {
318 "Session not found",
319 "messaging_quic_server::disconnect_session",
320 "Session ID: " + session_id);
321 }
322 session = it->second;
323 sessions_.erase(it);
324 }
325
326 if (session)
327 {
328 return session->close(error_code);
329 }
330 return ok();
331}
332
333auto messaging_quic_server::disconnect_all(uint64_t error_code) -> void
334{
335 std::vector<std::shared_ptr<session::quic_session>> sessions_to_close;
336 {
337 std::unique_lock<std::shared_mutex> lock(sessions_mutex_);
338 sessions_to_close.reserve(sessions_.size());
339 for (auto& [id, session] : sessions_)
340 {
341 sessions_to_close.push_back(session);
342 }
343 sessions_.clear();
344 }
345
346 for (auto& session : sessions_to_close)
347 {
348 if (session)
349 {
350 auto result = session->close(error_code);
351 (void)result;
352 }
353 }
354}
355
356auto messaging_quic_server::broadcast(std::vector<uint8_t>&& data)
357 -> VoidResult
358{
359 auto sessions_list = sessions();
360 for (auto& session : sessions_list)
361 {
362 if (session && session->is_active())
363 {
364 std::vector<uint8_t> data_copy(data);
365 auto result = session->send(std::move(data_copy));
366 if (result.is_err())
367 {
368 NETWORK_LOG_WARN("[messaging_quic_server] Failed to send to session "
369 + session->session_id() + ": "
370 + result.error().message);
371 }
372 }
373 }
374 return ok();
375}
376
378 const std::vector<std::string>& session_ids,
379 std::vector<uint8_t>&& data) -> VoidResult
380{
381 for (const auto& session_id : session_ids)
382 {
383 auto session = get_session(session_id);
384 if (session && session->is_active())
385 {
386 std::vector<uint8_t> data_copy(data);
387 auto result = session->send(std::move(data_copy));
388 if (result.is_err())
389 {
390 NETWORK_LOG_WARN("[messaging_quic_server] Failed to send to session "
391 + session_id + ": " + result.error().message);
392 }
393 }
394 }
395 return ok();
396}
397
398#if KCENON_WITH_COMMON_SYSTEM
399auto messaging_quic_server::set_monitor(
400 kcenon::common::interfaces::IMonitor* monitor) -> void
401{
402 monitor_ = monitor;
403}
404
405auto messaging_quic_server::get_monitor() const
406 -> kcenon::common::interfaces::IMonitor*
407{
408 return monitor_;
409}
410#endif
411
413{
414 if (!is_running() || !udp_socket_)
415 {
416 return;
417 }
418
419 auto self = shared_from_this();
420 udp_socket_->async_receive_from(
421 asio::buffer(recv_buffer_),
422 recv_endpoint_,
423 [this, self](std::error_code ec, std::size_t bytes_received)
424 {
425 if (!is_running())
426 {
427 return;
428 }
429
430 if (ec)
431 {
432 if (ec != asio::error::operation_aborted)
433 {
435 "[messaging_quic_server] Receive error: " + ec.message());
436
437 invoke_error_callback(ec);
438 }
439 return;
440 }
441
442 // Handle the received packet
443 std::span<const uint8_t> packet_data(recv_buffer_.data(),
444 bytes_received);
445 handle_packet(packet_data, recv_endpoint_);
446
447 // Continue receiving
448 start_receive();
449 });
450}
451
452auto messaging_quic_server::handle_packet(std::span<const uint8_t> data,
453 const asio::ip::udp::endpoint& from)
454 -> void
455{
456 if (data.empty())
457 {
458 return;
459 }
460
461 // Parse packet header to get destination connection ID
462 auto header_result = protocols::quic::packet_parser::parse_header(data);
463 if (header_result.is_err())
464 {
465 NETWORK_LOG_DEBUG("[messaging_quic_server] Invalid packet from "
466 + from.address().to_string());
467 return;
468 }
469
470 // Extract destination connection ID from header
472 std::visit(
473 [&dcid](auto&& hdr)
474 {
475 dcid = hdr.dest_conn_id;
476 },
477 header_result.value().first);
478
479 // Find or create session for this connection
480 auto session = find_or_create_session(dcid, from);
481 if (!session)
482 {
484 "[messaging_quic_server] Could not find or create session for packet");
485 return;
486 }
487
488 // Delegate packet handling to session
489 session->handle_packet(data);
490}
491
494 const asio::ip::udp::endpoint& endpoint)
495 -> std::shared_ptr<session::quic_session>
496{
497 // First, check existing sessions
498 {
499 std::shared_lock<std::shared_mutex> lock(sessions_mutex_);
500 for (const auto& [id, session] : sessions_)
501 {
502 if (session->matches_connection_id(dcid))
503 {
504 return session;
505 }
506 }
507 }
508
509 // Check connection limit
510 if (session_count() >= config_.max_connections)
511 {
513 "[messaging_quic_server] Connection limit reached, rejecting new connection");
514 return nullptr;
515 }
516
517 // Create new session for this connection
518 auto session_id = generate_session_id();
519
520 // Create QUIC socket for the new session
521 asio::ip::udp::socket session_socket(
522 *io_context_, asio::ip::udp::endpoint(asio::ip::udp::v4(), 0));
523 session_socket.connect(endpoint);
524
525 auto quic_socket = std::make_shared<internal::quic_socket>(
526 std::move(session_socket), internal::quic_role::server);
527
528 // Accept the connection with TLS config
529 if (!config_.cert_file.empty() && !config_.key_file.empty())
530 {
531 auto accept_result =
532 quic_socket->accept(config_.cert_file, config_.key_file);
533 if (accept_result.is_err())
534 {
536 "[messaging_quic_server] Failed to accept connection: "
537 + accept_result.error().message);
538 return nullptr;
539 }
540 }
541
542 auto session =
543 std::make_shared<session::quic_session>(quic_socket, session_id);
544
545 // Set up session callbacks
546 auto self = weak_from_this();
547
548 session->set_receive_callback(
549 [self, session_id](const std::vector<uint8_t>& data)
550 {
551 if (auto server = self.lock())
552 {
553 auto sess = server->get_session(session_id);
554 if (sess)
555 {
556 server->invoke_receive_callback(sess, data);
557 }
558 }
559 });
560
561 session->set_stream_receive_callback(
562 [self, session_id](uint64_t stream_id,
563 const std::vector<uint8_t>& data,
564 bool fin)
565 {
566 if (auto server = self.lock())
567 {
568 auto sess = server->get_session(session_id);
569 if (sess)
570 {
571 server->invoke_stream_receive_callback(sess, stream_id, data, fin);
572 }
573 }
574 });
575
576 session->set_close_callback(
577 [self, session_id]()
578 {
579 if (auto server = self.lock())
580 {
581 server->on_session_close(session_id);
582 }
583 });
584
585 // Add session to map
586 {
587 std::unique_lock<std::shared_mutex> lock(sessions_mutex_);
588 sessions_[session_id] = session;
589 }
590
591 // Start the session
592 session->start_session();
593
594 // Report metrics
597
598 // Invoke connection callback
599 invoke_connection_callback(session);
600
601#if KCENON_WITH_COMMON_SYSTEM
602 if (monitor_)
603 {
604 monitor_->record_metric("active_connections",
605 static_cast<double>(session_count()));
606 }
607#endif
608
609 NETWORK_LOG_INFO("[messaging_quic_server] New session created: "
610 + session_id + " from " + endpoint.address().to_string());
611
612 return session;
613}
614
616{
617 auto counter = session_counter_.fetch_add(1);
618 std::ostringstream oss;
619 oss << server_id_ << "-" << counter;
620 return oss.str();
621}
622
623auto messaging_quic_server::on_session_close(const std::string& session_id)
624 -> void
625{
626 std::shared_ptr<session::quic_session> session;
627 {
628 std::unique_lock<std::shared_mutex> lock(sessions_mutex_);
629 auto it = sessions_.find(session_id);
630 if (it != sessions_.end())
631 {
632 session = it->second;
633 sessions_.erase(it);
634 }
635 }
636
637 if (session)
638 {
639 // Report metrics
641
642 // Invoke disconnection callback
643 invoke_disconnection_callback(session);
644
645#if KCENON_WITH_COMMON_SYSTEM
646 if (monitor_)
647 {
648 monitor_->record_metric("active_connections",
649 static_cast<double>(session_count()));
650 }
651#endif
652
653 NETWORK_LOG_INFO("[messaging_quic_server] Session closed: "
654 + session_id);
655 }
656}
657
659{
660 if (!cleanup_timer_ || !is_running())
661 {
662 return;
663 }
664
665 // Schedule cleanup every 30 seconds
666 cleanup_timer_->expires_after(std::chrono::seconds(30));
667
668 auto self = shared_from_this();
669 cleanup_timer_->async_wait(
670 [this, self](const std::error_code& ec)
671 {
672 if (!ec && is_running())
673 {
674 cleanup_dead_sessions();
675 start_cleanup_timer(); // Reschedule
676 }
677 });
678}
679
681{
682 std::vector<std::string> dead_session_ids;
683
684 {
685 std::shared_lock<std::shared_mutex> lock(sessions_mutex_);
686 for (const auto& [id, session] : sessions_)
687 {
688 if (!session || !session->is_active())
689 {
690 dead_session_ids.push_back(id);
691 }
692 }
693 }
694
695 for (const auto& id : dead_session_ids)
696 {
697 on_session_close(id);
698 }
699
700 if (!dead_session_ids.empty())
701 {
703 "[messaging_quic_server] Cleaned up "
704 + std::to_string(dead_session_ids.size())
705 + " dead sessions. Active: " + std::to_string(session_count()));
706 }
707}
708
709// =============================================================================
710// Callback invocation helpers
711// =============================================================================
712
714 std::shared_ptr<session::quic_session> session) -> void
715{
716 callbacks_.invoke<to_index(callback_index::connection)>(session);
717}
718
720 std::shared_ptr<session::quic_session> session) -> void
721{
722 callbacks_.invoke<to_index(callback_index::disconnection)>(session);
723}
724
726 std::shared_ptr<session::quic_session> session,
727 const std::vector<uint8_t>& data) -> void
728{
729 callbacks_.invoke<to_index(callback_index::receive)>(session, data);
730}
731
733 std::shared_ptr<session::quic_session> session,
734 uint64_t stream_id,
735 const std::vector<uint8_t>& data,
736 bool fin) -> void
737{
738 callbacks_.invoke<to_index(callback_index::stream_receive)>(session, stream_id, data, fin);
739}
740
741auto messaging_quic_server::invoke_error_callback(std::error_code ec) -> void
742{
743 callbacks_.invoke<to_index(callback_index::error)>(ec);
744}
745
746// =============================================================================
747// Legacy callback setters
748// =============================================================================
749
751{
752 callbacks_.set<to_index(callback_index::connection)>(std::move(callback));
753}
754
756{
757 callbacks_.set<to_index(callback_index::disconnection)>(std::move(callback));
758}
759
761{
762 callbacks_.set<to_index(callback_index::receive)>(std::move(callback));
763}
764
766{
767 callbacks_.set<to_index(callback_index::stream_receive)>(std::move(callback));
768}
769
771{
772 callbacks_.set<to_index(callback_index::error)>(std::move(callback));
773}
774
775// =============================================================================
776// i_quic_server interface callback implementations
777// =============================================================================
778
781{
782 // Convert callback to internal type (quic_session to i_quic_session)
783 set_connection_callback(
784 [cb = std::move(callback)](std::shared_ptr<session::quic_session> session) {
785 if (cb && session)
786 {
787 // quic_session implements i_quic_session, so we can pass it directly
788 cb(session);
789 }
790 });
791}
792
795{
796 set_disconnection_callback(
797 [cb = std::move(callback)](std::shared_ptr<session::quic_session> session) {
798 if (cb && session)
799 {
800 cb(session->session_id());
801 }
802 });
803}
804
807{
808 set_receive_callback(
809 [cb = std::move(callback)](std::shared_ptr<session::quic_session> session,
810 const std::vector<uint8_t>& data) {
811 if (cb && session)
812 {
813 cb(session->session_id(), data);
814 }
815 });
816}
817
820{
821 set_stream_receive_callback(
822 [cb = std::move(callback)](std::shared_ptr<session::quic_session> session,
823 uint64_t stream_id,
824 const std::vector<uint8_t>& data,
825 bool fin) {
826 if (cb && session)
827 {
828 cb(session->session_id(), stream_id, data, fin);
829 }
830 });
831}
832
835{
836 // Store the interface callback and wrap it for base class
837 // Note: Base class error_callback_t only takes error_code, not session
838 // We need to store the interface callback separately and invoke it from
839 // the receive side where we have session context
840 interface_error_cb_ = std::move(callback);
841}
842
843} // namespace kcenon::network::core
auto invoke_error_callback(std::error_code ec) -> void
Invokes the error callback.
auto is_running() const -> bool override
Checks if the server is currently running.
std::function< void(std::error_code)> error_callback_t
Callback type for errors.
auto on_session_close(const std::string &session_id) -> void
auto stop_server() -> VoidResult
Stops the server and releases all resources.
auto disconnect_all(uint64_t error_code=0) -> void
Disconnect all active sessions.
messaging_quic_server(std::string_view server_id)
Constructs a QUIC server with a given identifier.
auto sessions() const -> std::vector< std::shared_ptr< session::quic_session > >
Get all active sessions.
auto stop() -> VoidResult override
Stops the QUIC server.
auto disconnect_session(const std::string &session_id, uint64_t error_code=0) -> VoidResult
Disconnect a specific session.
auto broadcast(std::vector< uint8_t > &&data) -> VoidResult
Send data to all connected clients.
auto handle_packet(std::span< const uint8_t > data, const asio::ip::udp::endpoint &from) -> void
auto invoke_connection_callback(std::shared_ptr< session::quic_session > session) -> void
Invokes the connection callback.
auto start(uint16_t port) -> VoidResult override
Starts the QUIC server on the specified port.
auto set_stream_receive_callback(stream_receive_callback_t callback) -> void
Sets the callback for stream data reception (legacy version).
auto set_receive_callback(interfaces::i_quic_server::receive_callback_t callback) -> void override
Sets the callback for received data on default stream (interface version).
auto set_connection_callback(interfaces::i_quic_server::connection_callback_t callback) -> void override
Sets the callback for new connections (interface version).
auto session_count() const -> size_t
Get the number of active sessions.
auto start_server(unsigned short port) -> VoidResult
Start the server with default configuration.
std::function< void(std::shared_ptr< session::quic_session >, uint64_t, const std::vector< uint8_t > &, bool)> stream_receive_callback_t
Callback type for stream data (session, stream_id, data, fin)
auto do_start_impl(unsigned short port) -> VoidResult
QUIC-specific implementation of server start.
auto invoke_receive_callback(std::shared_ptr< session::quic_session > session, const std::vector< uint8_t > &data) -> void
Invokes the receive callback.
std::function< void(std::shared_ptr< session::quic_session >, const std::vector< uint8_t > &)> receive_callback_t
Callback type for received data (session, data)
auto invoke_disconnection_callback(std::shared_ptr< session::quic_session > session) -> void
Invokes the disconnection callback.
std::function< void(std::shared_ptr< session::quic_session >)> disconnection_callback_t
Callback type for disconnections.
auto wait_for_stop() -> void override
Blocks until stop() is called.
std::map< std::string, std::shared_ptr< session::quic_session > > sessions_
auto get_session(const std::string &session_id) -> std::shared_ptr< session::quic_session >
Get a session by its ID.
~messaging_quic_server() noexcept override
Destructor; automatically calls stop_server() if running.
auto set_disconnection_callback(interfaces::i_quic_server::disconnection_callback_t callback) -> void override
Sets the callback for disconnections (interface version).
auto connection_count() const -> size_t override
Gets the number of active QUIC connections (interface version).
auto server_id() const -> const std::string &
Returns the server identifier.
auto do_stop_impl() -> VoidResult
QUIC-specific implementation of server stop.
auto find_or_create_session(const protocols::quic::connection_id &dcid, const asio::ip::udp::endpoint &endpoint) -> std::shared_ptr< session::quic_session >
auto invoke_stream_receive_callback(std::shared_ptr< session::quic_session > session, uint64_t stream_id, const std::vector< uint8_t > &data, bool fin) -> void
Invokes the stream receive callback.
auto set_stream_callback(interfaces::i_quic_server::stream_callback_t callback) -> void override
Sets the callback for stream data (interface version).
auto set_error_callback(interfaces::i_quic_server::error_callback_t callback) -> void override
Sets the callback for errors (interface version).
auto multicast(const std::vector< std::string > &session_ids, std::vector< uint8_t > &&data) -> VoidResult
Send data to specific sessions.
std::function< void(std::shared_ptr< session::quic_session >)> connection_callback_t
Callback type for new connections.
std::shared_ptr< kcenon::network::integration::thread_pool_interface > get_thread_pool()
Get current thread pool.
static network_context & instance()
Get the singleton instance.
virtual std::future< void > submit(std::function< void()> task)=0
Submit a task to the thread pool.
std::function< void( std::string_view, uint64_t, const std::vector< uint8_t > &, bool)> stream_callback_t
Callback type for stream data (session_id, stream_id, data, is_fin)
std::function< void(std::string_view, const std::vector< uint8_t > &)> receive_callback_t
Callback type for default stream data (session_id, data)
std::function< void(std::string_view, std::error_code)> error_callback_t
Callback type for errors (session_id, error)
std::function< void(std::shared_ptr< i_quic_session >)> connection_callback_t
Callback type for new connections.
std::function< void(std::string_view)> disconnection_callback_t
Callback type for disconnections (session_id)
static void report_connection_accepted()
Report a new connection accepted.
static void report_active_connections(size_t count)
Report active connections count.
QUIC Connection ID (RFC 9000 Section 5.1)
static auto parse_header(std::span< const uint8_t > data) -> Result< std::pair< packet_header, size_t > >
Parse a packet header (without header protection removal)
Definition packet.cpp:170
auto is_running() const -> bool
Checks if the component is currently running.
Feature flags for network_system.
tracing_config config
Definition exporters.cpp:29
Logger system integration interface for network_system.
#define NETWORK_LOG_WARN(msg)
#define NETWORK_LOG_INFO(msg)
#define NETWORK_LOG_ERROR(msg)
#define NETWORK_LOG_DEBUG(msg)
constexpr auto to_index(E e) noexcept -> std::size_t
Helper to convert enum to std::size_t for callback_manager access.
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
VoidResult ok()
Network system metrics definitions and reporting utilities.
QUIC-specific session with stream multiplexing.
Configuration options for QUIC server.
Definition quic_server.h:70