65 const auto ipAddress = asio::ip::make_address_v4(address, ec);
69 throw std::system_error(ec,
"Invalid IPv4 address: " + address);
74 socket.open(asio::ip::udp::v4(), ec);
77 throw std::system_error(ec,
"Failed to open UDP socket");
81 socket.set_option(asio::ip::udp::socket::reuse_address(
true), ec);
85 const asio::ip::udp::endpoint listenEndpoint(ipAddress, port);
86 socket.bind(listenEndpoint, ec);
90 throw std::system_error(ec,
"Failed to bind UDP socket to port " + std::to_string(port));
98 endpoint = asio::ip::udp::endpoint(ipAddress, port);
141 throw std::system_error(asio::error::not_connected,
142 "UDP socket is not open");
145 if (timeout <= std::chrono::milliseconds::zero())
147 throw std::system_error(asio::error::invalid_argument,
148 "UDP receive timeout must be greater than zero");
151 auto operation = std::make_shared<ReceiveOperation>(
ioContext);
152 auto completion = operation->completion.get_future();
154 asio::post(
ioContext, [&, operation, timeout]
156 operation->timer.expires_after(timeout);
158 socket.async_receive_from(asio::buffer(operation->buffer),
159 operation->remoteEndpoint,
160 [operation](
const asio::error_code& ec, std::size_t bytesReceived)
162 operation->error = ec;
163 operation->receivedBytes = bytesReceived;
165 if (!operation->timedOut.load())
167 asio::error_code timerError;
168 operation->timer.cancel(timerError);
169 operation->Complete();
173 operation->timer.async_wait([&, operation](
const asio::error_code& ec)
180 operation->timedOut =
true;
182 asio::error_code cancelError;
183 socket.cancel(cancelError);
185 operation->Complete();
191 if (operation->timedOut)
196 if (operation->error)
198 throw std::system_error(operation->error,
199 "Failed to receive UDP datagram");
204 operation->buffer.resize(operation->receivedBytes);
206 return std::move(operation->buffer);
240 throw std::system_error(asio::error::not_connected,
241 "UDP socket is not open");
244 if (timeout <= std::chrono::milliseconds::zero())
246 throw std::system_error(asio::error::invalid_argument,
247 "UDP receive timeout must be greater than zero");
250 auto operation = std::make_shared<ReceiveOperation>(
ioContext);
251 auto completion = operation->completion.get_future();
253 const auto targetEndpoint =
endpoint;
255 asio::post(
ioContext, [&, operation, data, timeout, targetEndpoint]
257 asio::error_code sendError;
259 socket.send_to(asio::buffer(data), targetEndpoint, 0, sendError);
263 operation->error = sendError;
264 operation->Complete();
268 operation->timer.expires_after(timeout);
270 socket.async_receive_from(asio::buffer(operation->buffer),
271 operation->remoteEndpoint,
272 [operation](
const asio::error_code& ec, std::size_t bytesReceived)
274 operation->error = ec;
275 operation->receivedBytes = bytesReceived;
277 if (!operation->timedOut.load())
279 asio::error_code timerError;
280 operation->timer.cancel(timerError);
281 operation->Complete();
285 operation->timer.async_wait([&, operation](
const asio::error_code& ec)
292 operation->timedOut =
true;
294 asio::error_code cancelError;
295 socket.cancel(cancelError);
297 operation->Complete();
303 if (operation->timedOut)
308 if (operation->error)
310 throw std::system_error(operation->error,
311 "Failed to send/receive UDP datagram");
314 operation->buffer.resize(operation->receivedBytes);
316 return std::move(operation->buffer);