15 : server_id_(server_id)
35 cert_file_ = file_path;
42 key_file_ = file_path;
49 ssl_ctx_ = SSL_CTX_new(DTLS_server_method());
53 "Failed to create DTLS context",
54 "secure_messaging_udp_server::init_ssl_context");
58 SSL_CTX_set_options(ssl_ctx_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
61 if (!cert_file_.empty())
63 if (SSL_CTX_use_certificate_chain_file(ssl_ctx_, cert_file_.c_str()) != 1)
65 SSL_CTX_free(ssl_ctx_);
68 "Failed to load certificate: " + cert_file_,
69 "secure_messaging_udp_server::init_ssl_context");
74 if (!key_file_.empty())
76 if (SSL_CTX_use_PrivateKey_file(ssl_ctx_, key_file_.c_str(), SSL_FILETYPE_PEM) != 1)
78 SSL_CTX_free(ssl_ctx_);
81 "Failed to load private key: " + key_file_,
82 "secure_messaging_udp_server::init_ssl_context");
86 if (SSL_CTX_check_private_key(ssl_ctx_) != 1)
88 SSL_CTX_free(ssl_ctx_);
91 "Private key does not match certificate",
92 "secure_messaging_udp_server::init_ssl_context");
97 SSL_CTX_set_verify(ssl_ctx_, SSL_VERIFY_NONE,
nullptr);
104 if (is_running_.load(std::memory_order_acquire))
107 "Server already running",
108 "secure_messaging_udp_server::start_server");
112 if (cert_file_.empty() || key_file_.empty())
115 "Certificate and private key files must be set",
116 "secure_messaging_udp_server::start_server");
120 auto ssl_result = init_ssl_context();
121 if (!ssl_result.is_ok())
127 io_context_ = std::make_unique<asio::io_context>();
132 socket_ = std::make_unique<asio::ip::udp::socket>(
134 asio::ip::udp::endpoint(asio::ip::udp::v4(), port));
136 catch (
const std::exception& e)
138 SSL_CTX_free(ssl_ctx_);
141 std::string(
"Failed to bind port: ") + e.what(),
142 "secure_messaging_udp_server::start_server");
149 thread_pool_ = std::make_shared<integration::basic_thread_pool>(std::thread::hardware_concurrency());
153 stop_promise_.emplace();
154 stop_future_ = stop_promise_->get_future();
157 io_context_future_ = thread_pool_->
submit(
160 auto work_guard = asio::make_work_guard(*io_context_);
164 is_running_.store(
true, std::memory_order_release);
174 if (!is_running_.exchange(
false, std::memory_order_acq_rel))
179 SSL_CTX_free(ssl_ctx_);
187 std::lock_guard<std::mutex> lock(sessions_mutex_);
188 for (
auto& [endpoint, session] : sessions_)
190 if (session && session->socket)
192 session->socket->stop_receive();
213 if (io_context_future_.valid())
215 io_context_future_.wait();
221 SSL_CTX_free(ssl_ctx_);
226 if (stop_promise_.has_value())
230 stop_promise_->set_value();
232 catch (
const std::future_error&)
236 stop_promise_.reset();
244 if (stop_future_.valid())
252 if (!is_running_.load(std::memory_order_acquire) || !socket_)
257 auto self = shared_from_this();
258 socket_->async_receive_from(
259 asio::buffer(read_buffer_),
261 [
this, self](std::error_code ec, std::size_t length)
263 if (!is_running_.load(std::memory_order_acquire))
270 if (ec != asio::error::operation_aborted)
272 std::function<void(std::error_code)> callback;
274 std::lock_guard<std::mutex> lock(callback_mutex_);
275 callback = error_callback_;
287 std::vector<uint8_t> data(read_buffer_.begin(),
288 read_buffer_.begin() + length);
289 process_session_data(data, sender_endpoint_);
293 if (is_running_.load(std::memory_order_acquire))
301 [[maybe_unused]]
const std::vector<uint8_t>& data,
302 const asio::ip::udp::endpoint& sender) ->
void
304 std::shared_ptr<dtls_session> session;
308 std::lock_guard<std::mutex> lock(sessions_mutex_);
309 auto it = sessions_.find(sender);
310 if (it != sessions_.end())
312 session = it->second;
319 session = create_session(sender);
340 const asio::ip::udp::endpoint& client_endpoint) -> std::shared_ptr<dtls_session>
349 asio::ip::udp::socket client_socket(*io_context_, asio::ip::udp::v4());
351 auto session = std::make_shared<dtls_session>();
352 session->socket = std::make_shared<internal::dtls_socket>(
353 std::move(client_socket), ssl_ctx_);
354 session->socket->set_peer_endpoint(client_endpoint);
357 session->socket->set_receive_callback(
358 [
this, client_endpoint](
const std::vector<uint8_t>& data,
359 const asio::ip::udp::endpoint& )
361 std::function<void(
const std::vector<uint8_t>&,
const asio::ip::udp::endpoint&)> callback;
363 std::lock_guard<std::mutex> lock(callback_mutex_);
364 callback = receive_callback_;
368 callback(data, client_endpoint);
373 session->socket->async_handshake(
375 [
this, session, client_endpoint](std::error_code ec)
381 std::lock_guard<std::mutex> lock(sessions_mutex_);
382 sessions_.erase(client_endpoint);
387 session->handshake_complete =
true;
390 std::function<void(
const asio::ip::udp::endpoint&)> callback;
392 std::lock_guard<std::mutex> lock(callback_mutex_);
393 callback = client_connected_callback_;
397 callback(client_endpoint);
403 std::lock_guard<std::mutex> lock(sessions_mutex_);
404 sessions_[client_endpoint] = session;
409 catch (
const std::exception& )
416 std::vector<uint8_t>&& data,
417 const asio::ip::udp::endpoint& endpoint,
418 std::function<
void(std::error_code, std::size_t)> handler) ->
void
420 std::shared_ptr<dtls_session> session;
423 std::lock_guard<std::mutex> lock(sessions_mutex_);
424 auto it = sessions_.find(endpoint);
425 if (it != sessions_.end())
427 session = it->second;
431 if (!session || !session->socket || !session->handshake_complete)
435 handler(std::make_error_code(std::errc::not_connected), 0);
440 session->socket->async_send_to(std::move(data), endpoint, std::move(handler));
444 std::function<
void(
const std::vector<uint8_t>&,
445 const asio::ip::udp::endpoint&)> callback) ->
void
447 std::lock_guard<std::mutex> lock(callback_mutex_);
448 receive_callback_ = std::move(callback);
452 std::function<
void(std::error_code)> callback) ->
void
454 std::lock_guard<std::mutex> lock(callback_mutex_);
455 error_callback_ = std::move(callback);
459 std::function<
void(
const asio::ip::udp::endpoint&)> callback) ->
void
461 std::lock_guard<std::mutex> lock(callback_mutex_);
462 client_connected_callback_ = std::move(callback);
466 std::function<
void(
const asio::ip::udp::endpoint&)> callback) ->
void
468 std::lock_guard<std::mutex> lock(callback_mutex_);
469 client_disconnected_callback_ = std::move(callback);
std::shared_ptr< kcenon::network::integration::thread_pool_interface > get_thread_pool()
Get current thread pool.
static network_context & instance()
Get the singleton instance.
auto async_send_to(std::vector< uint8_t > &&data, const asio::ip::udp::endpoint &endpoint, std::function< void(std::error_code, std::size_t)> handler=nullptr) -> void
Sends an encrypted datagram to a specific client.
auto set_receive_callback(udp_receive_callback_t callback) -> void
Sets a UDP-specific callback to handle received decrypted datagrams.
auto wait_for_stop() -> void
Blocks the calling thread until the server is stopped.
auto create_session(const asio::ip::udp::endpoint &client_endpoint) -> std::shared_ptr< dtls_session >
Creates a new DTLS session for a client.
auto start_server(uint16_t port) -> VoidResult
Starts the server and begins listening for DTLS connections.
auto stop_server() -> VoidResult
Stops the server and releases all resources.
auto set_private_key_file(const std::string &file_path) -> VoidResult
Sets the private key file for TLS.
auto init_ssl_context() -> VoidResult
Initializes the SSL context for DTLS server.
auto set_client_disconnected_callback(udp_client_callback_t callback) -> void
Sets a UDP-specific callback for client disconnection.
auto set_error_callback(std::function< void(std::error_code)> callback) -> void
Sets a callback to handle errors.
auto set_certificate_chain_file(const std::string &file_path) -> VoidResult
Sets the certificate chain file for TLS.
secure_messaging_udp_server(std::string_view server_id)
Constructs a secure_messaging_udp_server with an identifier.
auto set_client_connected_callback(udp_client_callback_t callback) -> void
Sets a UDP-specific callback for new client connection.
~secure_messaging_udp_server() noexcept
Destructor. Automatically calls stop_server() if still running.
auto do_receive() -> void
Handles incoming datagrams and routes them to appropriate sessions.
auto process_session_data(const std::vector< uint8_t > &data, const asio::ip::udp::endpoint &sender) -> void
Processes received data for an existing session.
virtual std::future< void > submit(std::function< void()> task)=0
Submit a task to the thread pool.
constexpr int invalid_argument
constexpr int internal_error
constexpr int bind_failed
constexpr int server_already_running
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
Global context for shared network system resources.
DTLS server class for encrypted UDP communication.