Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
udp_server_adapter.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
8
9#include <sstream>
10
12
13// =========================================================================
14// udp_endpoint_session implementation
15// =========================================================================
16
18 std::string_view session_id,
19 std::string_view address,
20 uint16_t port,
21 std::weak_ptr<core::messaging_udp_server> server)
22 : session_id_(session_id)
23 , address_(address)
24 , port_(port)
25 , server_(std::move(server))
26{
27}
28
29auto udp_endpoint_session::id() const -> std::string_view
30{
31 return session_id_;
32}
33
35{
36 // UDP is connectionless, so we consider the session "connected"
37 // as long as the server is still running
38 auto server = server_.lock();
39 return server && server->is_running();
40}
41
42auto udp_endpoint_session::send(std::vector<uint8_t>&& data) -> VoidResult
43{
44 auto server = server_.lock();
45 if (!server)
46 {
47 return error_void(
49 "Server no longer available",
50 "udp_endpoint_session::send"
51 );
52 }
53
54 interfaces::i_udp_server::endpoint_info endpoint{address_, port_};
55 return server->send_to(endpoint, std::move(data));
56}
57
59{
60 // UDP is connectionless, so close is a no-op
61 // The session will be removed from tracking when server stops
62}
63
64// =========================================================================
65// udp_server_adapter implementation
66// =========================================================================
67
68udp_server_adapter::udp_server_adapter(std::string_view server_id)
69 : server_id_(server_id)
70 , server_(std::make_shared<core::messaging_udp_server>(std::string(server_id)))
71{
73}
74
76{
77 if (server_ && server_->is_running())
78 {
79 (void)server_->stop();
80 }
81}
82
83// =========================================================================
84// i_network_component interface implementation
85// =========================================================================
86
88{
89 return server_ && server_->is_running();
90}
91
93{
94 if (server_)
95 {
96 server_->wait_for_stop();
97 }
98}
99
100// =========================================================================
101// i_protocol_server interface implementation
102// =========================================================================
103
105{
106 if (!server_)
107 {
108 return error_void(
110 "Server not initialized",
111 "udp_server_adapter::start"
112 );
113 }
114 return server_->start(port);
115}
116
118{
119 if (!server_)
120 {
121 return error_void(
123 "Server not initialized",
124 "udp_server_adapter::stop"
125 );
126 }
127
128 auto result = server_->stop();
129
130 // Clear tracked sessions on stop
131 {
132 std::lock_guard<std::mutex> lock(sessions_mutex_);
133 sessions_.clear();
134 }
135
136 return result;
137}
138
140{
141 std::lock_guard<std::mutex> lock(sessions_mutex_);
142 return sessions_.size();
143}
144
146{
147 std::lock_guard<std::mutex> lock(callbacks_mutex_);
148 connection_callback_ = std::move(callback);
149}
150
152{
153 std::lock_guard<std::mutex> lock(callbacks_mutex_);
154 disconnection_callback_ = std::move(callback);
155}
156
158{
159 std::lock_guard<std::mutex> lock(callbacks_mutex_);
160 receive_callback_ = std::move(callback);
161}
162
164{
165 std::lock_guard<std::mutex> lock(callbacks_mutex_);
166 error_callback_ = std::move(callback);
167}
168
169// =========================================================================
170// Internal methods
171// =========================================================================
172
174{
175 if (!server_)
176 {
177 return;
178 }
179
180 // Bridge UDP receive callback to i_protocol_server callback
181 // Create virtual sessions for each unique endpoint
182 server_->set_receive_callback(
183 [this](const std::vector<uint8_t>& data,
185 {
186 // Get or create session for this endpoint
187 auto session = get_or_create_session(endpoint.address, endpoint.port);
188 std::string session_id(session->id());
189
190 // Invoke the receive callback
191 receive_callback_t callback_copy;
192 {
193 std::lock_guard<std::mutex> lock(callbacks_mutex_);
194 callback_copy = receive_callback_;
195 }
196 if (callback_copy)
197 {
198 callback_copy(session_id, data);
199 }
200 });
201
202 // Bridge UDP error callback
203 server_->set_error_callback(
204 [this](std::error_code ec)
205 {
206 // Server-level error, use empty session_id
207 error_callback_t callback_copy;
208 {
209 std::lock_guard<std::mutex> lock(callbacks_mutex_);
210 callback_copy = error_callback_;
211 }
212 if (callback_copy)
213 {
214 callback_copy("", ec);
215 }
216 });
217}
218
219auto udp_server_adapter::make_session_id(const std::string& address, uint16_t port) -> std::string
220{
221 std::ostringstream oss;
222 oss << address << ":" << port;
223 return oss.str();
224}
225
226auto udp_server_adapter::get_or_create_session(const std::string& address, uint16_t port)
227 -> std::shared_ptr<interfaces::i_session>
228{
229 std::string session_id = make_session_id(address, port);
230
231 {
232 std::lock_guard<std::mutex> lock(sessions_mutex_);
233
234 auto it = sessions_.find(session_id);
235 if (it != sessions_.end())
236 {
237 return it->second;
238 }
239
240 // Create new session
241 auto session = std::make_shared<udp_endpoint_session>(
242 session_id, address, port, server_);
243 sessions_[session_id] = session;
244
245 // Invoke connection callback for new session (outside of lock)
246 connection_callback_t callback_copy;
247 {
248 std::lock_guard<std::mutex> cb_lock(callbacks_mutex_);
249 callback_copy = connection_callback_;
250 }
251
252 if (callback_copy)
253 {
254 callback_copy(session);
255 }
256
257 return session;
258 }
259}
260
261} // namespace kcenon::network::internal::adapters
std::function< void(std::string_view)> disconnection_callback_t
Callback type for disconnections (session_id)
std::function< void(std::string_view, const std::vector< uint8_t > &)> receive_callback_t
Callback type for received 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_session >)> connection_callback_t
Callback type for new connections.
auto id() const -> std::string_view override
Gets the unique identifier for this session.
std::weak_ptr< core::messaging_udp_server > server_
auto send(std::vector< uint8_t > &&data) -> VoidResult override
Sends data to the client.
auto is_connected() const -> bool override
Checks if the session is currently connected.
udp_endpoint_session(std::string_view session_id, std::string_view address, uint16_t port, std::weak_ptr< core::messaging_udp_server > server)
static auto make_session_id(const std::string &address, uint16_t port) -> std::string
Creates a unique session ID from endpoint info.
std::unordered_map< std::string, std::shared_ptr< udp_endpoint_session > > sessions_
auto set_connection_callback(connection_callback_t callback) -> void override
Sets the callback for new connections.
auto wait_for_stop() -> void override
Blocks until the component has stopped.
std::shared_ptr< core::messaging_udp_server > server_
~udp_server_adapter() override
Destructor ensures proper cleanup.
auto connection_count() const -> size_t override
Gets the number of active client connections.
auto setup_internal_callbacks() -> void
Sets up internal callbacks to bridge UDP callbacks to i_protocol_server callbacks.
auto is_running() const -> bool override
Checks if the component is currently running.
auto set_receive_callback(receive_callback_t callback) -> void override
Sets the callback for received data.
auto set_disconnection_callback(disconnection_callback_t callback) -> void override
Sets the callback for disconnections.
auto start(uint16_t port) -> VoidResult override
Starts the server and begins listening for connections.
udp_server_adapter(std::string_view server_id)
Constructs an adapter with a unique server ID.
auto set_error_callback(error_callback_t callback) -> void override
Sets the callback for errors.
auto stop() -> VoidResult override
Stops the server and closes all connections.
auto get_or_create_session(const std::string &address, uint16_t port) -> std::shared_ptr< interfaces::i_session >
Gets or creates a session for the given endpoint.
UDP server class.
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
Endpoint information for UDP datagrams.