Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
udp_transport.h
Go to the documentation of this file.
1#pragma once
2
3// BSD 3-Clause License
4// Copyright (c) 2025, 🍀☀🌕🌥 🌊
5// See the LICENSE file in the project root for full license information.
6
7
17#include "../core/error_codes.h"
18#include <string>
19#include <vector>
20#include <cstdint>
21#include <chrono>
22#include <memory>
23#include <atomic>
24#include <span>
25
26namespace kcenon { namespace monitoring {
27
33 std::size_t bytes_sent{0};
34 std::chrono::milliseconds elapsed{0};
35};
36
42 std::size_t packets_sent{0};
43 std::size_t bytes_sent{0};
44 std::size_t send_failures{0};
45};
46
56public:
57 virtual ~udp_transport() = default;
58
65 virtual common::VoidResult connect(const std::string& host, uint16_t port) = 0;
66
72 virtual common::VoidResult send(std::span<const uint8_t> data) = 0;
73
79 common::VoidResult send(const std::string& data) {
80 return send(std::span<const uint8_t>(
81 reinterpret_cast<const uint8_t*>(data.data()),
82 data.size()));
83 }
84
89 virtual bool is_connected() const = 0;
90
94 virtual void disconnect() = 0;
95
100 virtual bool is_available() const = 0;
101
106 virtual std::string name() const = 0;
107
112 virtual udp_statistics get_statistics() const = 0;
113
117 virtual void reset_statistics() = 0;
118};
119
128private:
129 std::string host_;
130 uint16_t port_{0};
131 bool connected_{false};
133 mutable std::atomic<std::size_t> packets_sent_{0};
134 mutable std::atomic<std::size_t> bytes_sent_{0};
135 mutable std::atomic<std::size_t> send_failures_{0};
136
137public:
139
140 // Bring base class send method into scope
142
149
150 common::VoidResult connect(const std::string& host, uint16_t port) override {
151 if (!simulate_success_) {
152 return common::VoidResult::err(error_info(
154 "Simulated connection failure",
155 "stub_udp_transport"
156 ).to_common_error());
157 }
158 host_ = host;
159 port_ = port;
160 connected_ = true;
161 return common::ok();
162 }
163
164 common::VoidResult send(std::span<const uint8_t> data) override {
165 if (!connected_) {
166 send_failures_.fetch_add(1, std::memory_order_relaxed);
167 return common::VoidResult::err(error_info(
169 "Not connected",
170 "stub_udp_transport"
171 ).to_common_error());
172 }
173
174 if (!simulate_success_) {
175 send_failures_.fetch_add(1, std::memory_order_relaxed);
176 return common::VoidResult::err(error_info(
178 "Simulated send failure",
179 "stub_udp_transport"
180 ).to_common_error());
181 }
182
183 packets_sent_.fetch_add(1, std::memory_order_relaxed);
184 bytes_sent_.fetch_add(data.size(), std::memory_order_relaxed);
185 return common::ok();
186 }
187
188 bool is_connected() const override {
189 return connected_;
190 }
191
192 void disconnect() override {
193 connected_ = false;
194 host_.clear();
195 port_ = 0;
196 }
197
198 bool is_available() const override {
199 return true;
200 }
201
202 std::string name() const override {
203 return "stub";
204 }
205
207 return {
208 packets_sent_.load(std::memory_order_relaxed),
209 bytes_sent_.load(std::memory_order_relaxed),
210 send_failures_.load(std::memory_order_relaxed)
211 };
212 }
213
214 void reset_statistics() override {
215 packets_sent_.store(0, std::memory_order_relaxed);
216 bytes_sent_.store(0, std::memory_order_relaxed);
217 send_failures_.store(0, std::memory_order_relaxed);
218 }
219
220 // Test helpers
221 std::string get_host() const { return host_; }
222 uint16_t get_port() const { return port_; }
223};
224
225} } // namespace kcenon::monitoring
226
227#ifdef MONITORING_HAS_COMMON_TRANSPORT_INTERFACES
228#include <kcenon/common/interfaces/transport.h>
229
230namespace kcenon { namespace monitoring {
231
239class common_udp_transport : public udp_transport {
240private:
241 std::shared_ptr<::kcenon::common::interfaces::IUdpClient> client_;
242 mutable std::atomic<std::size_t> packets_sent_{0};
243 mutable std::atomic<std::size_t> bytes_sent_{0};
244 mutable std::atomic<std::size_t> send_failures_{0};
245
246public:
247 explicit common_udp_transport(std::shared_ptr<::kcenon::common::interfaces::IUdpClient> client)
248 : client_(std::move(client)) {}
249
250 common::VoidResult connect(const std::string& host, uint16_t port) override {
251 if (!client_) {
252 return common::VoidResult::err(error_info(
253 monitoring_error_code::dependency_missing,
254 "UDP client not available",
255 "common_udp_transport"
256 ).to_common_error());
257 }
258
259 auto result = client_->connect(host, port);
260 if (result.is_err()) {
261 return common::VoidResult::err(error_info(
262 monitoring_error_code::network_error,
263 "Connection failed: " + result.error().message,
264 "common_udp_transport"
265 ).to_common_error());
266 }
267 return common::ok();
268 }
269
270 common::VoidResult send(std::span<const uint8_t> data) override {
271 if (!client_) {
272 send_failures_.fetch_add(1, std::memory_order_relaxed);
273 return common::VoidResult::err(error_info(
274 monitoring_error_code::dependency_missing,
275 "UDP client not available",
276 "common_udp_transport"
277 ).to_common_error());
278 }
279
280 if (!client_->is_connected()) {
281 send_failures_.fetch_add(1, std::memory_order_relaxed);
282 return common::VoidResult::err(error_info(
283 monitoring_error_code::network_error,
284 "Not connected",
285 "common_udp_transport"
286 ).to_common_error());
287 }
288
289 auto result = client_->send(data);
290 if (result.is_err()) {
291 send_failures_.fetch_add(1, std::memory_order_relaxed);
292 return common::VoidResult::err(error_info(
293 monitoring_error_code::network_error,
294 "Send failed: " + result.error().message,
295 "common_udp_transport"
296 ).to_common_error());
297 }
298
299 packets_sent_.fetch_add(1, std::memory_order_relaxed);
300 bytes_sent_.fetch_add(data.size(), std::memory_order_relaxed);
301 return common::ok();
302 }
303
304 bool is_connected() const override {
305 return client_ && client_->is_connected();
306 }
307
308 void disconnect() override {
309 if (client_) {
310 client_->disconnect();
311 }
312 }
313
314 bool is_available() const override {
315 return client_ != nullptr;
316 }
317
318 std::string name() const override {
319 if (client_) {
320 return "common:" + client_->get_implementation_name();
321 }
322 return "common:unavailable";
323 }
324
325 udp_statistics get_statistics() const override {
326 return {
327 packets_sent_.load(std::memory_order_relaxed),
328 bytes_sent_.load(std::memory_order_relaxed),
329 send_failures_.load(std::memory_order_relaxed)
330 };
331 }
332
333 void reset_statistics() override {
334 packets_sent_.store(0, std::memory_order_relaxed);
335 bytes_sent_.store(0, std::memory_order_relaxed);
336 send_failures_.store(0, std::memory_order_relaxed);
337 }
338};
339
340} } // namespace kcenon::monitoring
341
342#endif // MONITORING_HAS_COMMON_TRANSPORT_INTERFACES
343
344#ifdef MONITORING_HAS_NETWORK_SYSTEM
345#include <kcenon/network/udp/udp_client.h>
346
347namespace kcenon { namespace monitoring {
348
356class network_udp_transport : public udp_transport {
357private:
358 std::unique_ptr<network_system::udp::udp_client> client_;
359 std::string host_;
360 uint16_t port_{0};
361 bool connected_{false};
362 mutable std::atomic<std::size_t> packets_sent_{0};
363 mutable std::atomic<std::size_t> bytes_sent_{0};
364 mutable std::atomic<std::size_t> send_failures_{0};
365
366public:
367 network_udp_transport() = default;
368
369 common::VoidResult connect(const std::string& host, uint16_t port) override {
370 try {
371 client_ = std::make_unique<network_system::udp::udp_client>(host, port);
372 host_ = host;
373 port_ = port;
374 connected_ = true;
375 return common::ok();
376 } catch (const std::exception& e) {
377 return common::VoidResult::err(error_info(
378 monitoring_error_code::network_error,
379 std::string("Connection failed: ") + e.what(),
380 "network_udp_transport"
381 ).to_common_error());
382 }
383 }
384
385 common::VoidResult send(std::span<const uint8_t> data) override {
386 if (!connected_ || !client_) {
387 send_failures_.fetch_add(1, std::memory_order_relaxed);
388 return common::VoidResult::err(error_info(
389 monitoring_error_code::network_error,
390 "Not connected",
391 "network_udp_transport"
392 ).to_common_error());
393 }
394
395 try {
396 auto result = client_->send(data);
397 if (!result) {
398 send_failures_.fetch_add(1, std::memory_order_relaxed);
399 return common::VoidResult::err(error_info(
400 monitoring_error_code::network_error,
401 "Send failed: " + result.error().message,
402 "network_udp_transport"
403 ).to_common_error());
404 }
405
406 packets_sent_.fetch_add(1, std::memory_order_relaxed);
407 bytes_sent_.fetch_add(data.size(), std::memory_order_relaxed);
408 return common::ok();
409 } catch (const std::exception& e) {
410 send_failures_.fetch_add(1, std::memory_order_relaxed);
411 return common::VoidResult::err(error_info(
412 monitoring_error_code::network_error,
413 std::string("Send failed: ") + e.what(),
414 "network_udp_transport"
415 ).to_common_error());
416 }
417 }
418
419 bool is_connected() const override {
420 return connected_ && client_ != nullptr;
421 }
422
423 void disconnect() override {
424 client_.reset();
425 connected_ = false;
426 host_.clear();
427 port_ = 0;
428 }
429
430 bool is_available() const override {
431 return true;
432 }
433
434 std::string name() const override {
435 return "network_system";
436 }
437
438 udp_statistics get_statistics() const override {
439 return {
440 packets_sent_.load(std::memory_order_relaxed),
441 bytes_sent_.load(std::memory_order_relaxed),
442 send_failures_.load(std::memory_order_relaxed)
443 };
444 }
445
446 void reset_statistics() override {
447 packets_sent_.store(0, std::memory_order_relaxed);
448 bytes_sent_.store(0, std::memory_order_relaxed);
449 send_failures_.store(0, std::memory_order_relaxed);
450 }
451};
452
453} } // namespace kcenon::monitoring
454
455#endif // MONITORING_HAS_NETWORK_SYSTEM
456
457namespace kcenon { namespace monitoring {
458
466inline std::unique_ptr<udp_transport> create_default_udp_transport() {
467#ifdef MONITORING_HAS_NETWORK_SYSTEM
468 return std::make_unique<network_udp_transport>();
469#else
470 return std::make_unique<stub_udp_transport>();
471#endif
472}
473
477inline std::unique_ptr<stub_udp_transport> create_stub_udp_transport() {
478 return std::make_unique<stub_udp_transport>();
479}
480
481#ifdef MONITORING_HAS_COMMON_TRANSPORT_INTERFACES
486inline std::unique_ptr<common_udp_transport> create_common_udp_transport(
487 std::shared_ptr<::kcenon::common::interfaces::IUdpClient> client) {
488 return std::make_unique<common_udp_transport>(std::move(client));
489}
490#endif
491
492#ifdef MONITORING_HAS_NETWORK_SYSTEM
496inline std::unique_ptr<network_udp_transport> create_network_udp_transport() {
497 return std::make_unique<network_udp_transport>();
498}
499#endif
500
501} } // namespace kcenon::monitoring
Stub UDP transport for testing.
bool is_available() const override
Check if transport is available.
bool is_connected() const override
Check if connected to an endpoint.
void disconnect() override
Disconnect from the current endpoint.
std::string name() const override
Get transport name.
std::atomic< std::size_t > packets_sent_
void set_simulate_success(bool success)
Set whether to simulate success or failure.
std::atomic< std::size_t > bytes_sent_
udp_statistics get_statistics() const override
Get transport statistics.
void reset_statistics() override
Reset statistics.
std::atomic< std::size_t > send_failures_
common::VoidResult connect(const std::string &host, uint16_t port) override
Connect to a remote UDP endpoint.
common::VoidResult send(std::span< const uint8_t > data) override
Send data to the connected endpoint.
Abstract UDP transport interface.
virtual bool is_connected() const =0
Check if connected to an endpoint.
virtual common::VoidResult connect(const std::string &host, uint16_t port)=0
Connect to a remote UDP endpoint.
virtual udp_statistics get_statistics() const =0
Get transport statistics.
virtual bool is_available() const =0
Check if transport is available.
common::VoidResult send(const std::string &data)
Send string data to the connected endpoint.
virtual common::VoidResult send(std::span< const uint8_t > data)=0
Send data to the connected endpoint.
virtual void reset_statistics()=0
Reset statistics.
virtual std::string name() const =0
Get transport name.
virtual void disconnect()=0
Disconnect from the current endpoint.
Monitoring system specific error codes.
std::unique_ptr< stub_udp_transport > create_stub_udp_transport()
Create stub UDP transport for testing.
std::unique_ptr< udp_transport > create_default_udp_transport()
Create default UDP transport.
Result pattern type definitions for monitoring system.
Extended error information with context.
Result of a UDP send operation.
std::chrono::milliseconds elapsed
Statistics for UDP transport operations.