Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
udp_socket.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
5#include "udp_socket.h"
6
7#include <type_traits>
8
10{
11
12 udp_socket::udp_socket(asio::ip::udp::socket socket)
13 : socket_(std::move(socket))
14 {
15 // constructor body empty
16 }
17
19 std::function<void(const std::vector<uint8_t>&,
20 const asio::ip::udp::endpoint&)> callback) -> void
21 {
22 std::lock_guard<std::mutex> lock(callback_mutex_);
23 receive_callback_ = std::move(callback);
24 }
25
27 std::function<void(std::error_code)> callback) -> void
28 {
29 std::lock_guard<std::mutex> lock(callback_mutex_);
30 error_callback_ = std::move(callback);
31 }
32
34 {
35 // Set receiving flag and kick off the initial receive loop
36 is_receiving_.store(true);
37 do_receive();
38 }
39
41 {
42 // Stop further receive operations
43 is_receiving_.store(false);
44 }
45
46 auto udp_socket::close() -> void
47 {
48 // Set closed flag first to prevent new operations
49 is_closed_.store(true);
50 stop_receive();
51
52 // Close the socket
53 std::error_code ec;
54 socket_.close(ec);
55 // Errors during close are intentionally ignored
56 }
57
58 auto udp_socket::is_closed() const -> bool
59 {
60 return is_closed_.load();
61 }
62
64 {
65 // Check if receiving has been stopped before initiating new async operation
66 if (!is_receiving_.load())
67 {
68 return;
69 }
70
71 auto self = shared_from_this();
72 socket_.async_receive_from(
73 asio::buffer(read_buffer_),
74 sender_endpoint_,
75 [this, self](std::error_code ec, std::size_t length)
76 {
77 // Check if receiving has been stopped at callback time
78 if (!is_receiving_.load())
79 {
80 return;
81 }
82
83 if (ec)
84 {
85 // On error, invoke the error callback
86 if constexpr (std::is_invocable_v<decltype(error_callback_),
87 std::error_code>)
88 {
89 std::lock_guard<std::mutex> lock(callback_mutex_);
90 if (error_callback_)
91 {
92 error_callback_(ec);
93 }
94 }
95 return;
96 }
97
98 // On success, if length > 0, build a vector and call receive_callback_
99 if (length > 0)
100 {
101 if constexpr (std::is_invocable_v<decltype(receive_callback_),
102 const std::vector<uint8_t>&,
103 const asio::ip::udp::endpoint&>)
104 {
105 std::vector<uint8_t> datagram(read_buffer_.begin(),
106 read_buffer_.begin() + length);
107 std::lock_guard<std::mutex> lock(callback_mutex_);
108 if (receive_callback_)
109 {
110 receive_callback_(datagram, sender_endpoint_);
111 }
112 }
113 }
114
115 // Continue receiving only if still active
116 if (is_receiving_.load())
117 {
118 do_receive();
119 }
120 });
121 }
122
124 std::vector<uint8_t>&& data,
125 const asio::ip::udp::endpoint& endpoint,
126 std::function<void(std::error_code, std::size_t)> handler) -> void
127 {
128 auto self = shared_from_this();
129 // Move data into shared_ptr for lifetime management
130 auto buffer = std::make_shared<std::vector<uint8_t>>(std::move(data));
131 socket_.async_send_to(
132 asio::buffer(*buffer),
133 endpoint,
134 [handler = std::move(handler), self, buffer](std::error_code ec,
135 std::size_t bytes_transferred)
136 {
137 if constexpr (std::is_invocable_v<decltype(handler),
138 std::error_code, std::size_t>)
139 {
140 if (handler)
141 {
142 handler(ec, bytes_transferred);
143 }
144 }
145 });
146 }
147
148} // namespace kcenon::network::internal
auto do_receive() -> void
Internal function to handle the receive logic with async_receive_from().
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) -> void
Initiates an asynchronous send of the given data to endpoint.
auto is_closed() const -> bool
Checks if the socket has been closed.
auto stop_receive() -> void
Stops the receive loop to prevent further async operations.
auto start_receive() -> void
Begins the continuous asynchronous receive loop.
udp_socket(asio::ip::udp::socket socket)
Constructs a udp_socket by taking ownership of a moved socket.
auto set_receive_callback(std::function< void(const std::vector< uint8_t > &, const asio::ip::udp::endpoint &)> callback) -> void
Sets a callback to receive inbound datagrams.
auto close() -> void
Safely closes the socket and stops all async operations.
auto set_error_callback(std::function< void(std::error_code)> callback) -> void
Sets a callback to handle socket errors (e.g., receive/send failures).