13#include <system_error>
23 : ioContext(ioContext),
28 const std::string& address,
33 const auto ipAddress = asio::ip::make_address_v4(address, ec);
37 throw std::system_error(ec,
"Invalid IPv4 address: " + address);
42 socket.open(asio::ip::udp::v4(), ec);
45 throw std::system_error(ec,
"Failed to open UDP socket");
49 socket.set_option(asio::ip::udp::socket::reuse_address(
true), ec);
54 asio::ip::udp::endpoint listenEndpoint(ipAddress, port);
55 socket.bind(listenEndpoint, ec);
58 throw std::system_error(ec,
"Failed to bind UDP socket to port " + std::to_string(port));
66 endpoint = asio::ip::udp::endpoint(ipAddress, port);
106 std::chrono::milliseconds timeout,
107 asio::ip::udp::endpoint& remoteEndpoint)
111 throw std::system_error(
112 asio::error::not_connected,
113 "UDP socket is not open");
116 if (timeout <= std::chrono::milliseconds::zero())
118 throw std::system_error(
119 asio::error::invalid_argument,
120 "UDP receive timeout must be greater than zero");
124 asio::error_code receiveError;
125 std::size_t receivedBytes = 0;
127 bool receiveCompleted =
false;
128 bool timedOut =
false;
132 socket.async_receive_from(
133 asio::buffer(receiveBuffer),
135 [&](
const asio::error_code& ec, std::size_t bytes)
138 receivedBytes = bytes;
139 receiveCompleted =
true;
141 asio::error_code timerError;
142 timer.cancel(timerError);
145 timer.expires_after(timeout);
148 [&](
const asio::error_code& ec)
154 asio::error_code cancelError;
155 socket.cancel(cancelError);
162 if (timedOut && !receiveCompleted)
169 if (receiveError == asio::error::operation_aborted && timedOut)
174 throw std::system_error(
176 "Failed to receive UDP datagram");
179 receiveBuffer.resize(receivedBytes);
180 return receiveBuffer;
185 const asio::ip::udp::endpoint& targetEndpoint)
189 throw std::system_error(
190 asio::error::not_connected,
191 "UDP socket is not open");
204 throw std::system_error(
206 "Failed to send UDP datagram");
212 std::chrono::milliseconds timeout)
216 throw std::system_error(
217 asio::error::not_connected,
218 "UDP socket is not open");
221 if (timeout <= std::chrono::milliseconds::zero())
223 throw std::system_error(
224 asio::error::invalid_argument,
225 "UDP receive timeout must be greater than zero");
228 asio::error_code sendError;
238 throw std::system_error(
240 "Failed to send UDP datagram");
245 asio::ip::udp::endpoint senderEndpoint;
247 asio::error_code receiveError;
248 std::size_t receivedBytes = 0;
250 bool receiveCompleted =
false;
251 bool timedOut =
false;
255 socket.async_receive_from(
256 asio::buffer(receiveBuffer),
258 [&](
const asio::error_code& ec, std::size_t bytes)
261 receivedBytes = bytes;
262 receiveCompleted =
true;
264 asio::error_code timerError;
265 timer.cancel(timerError);
268 timer.expires_after(timeout);
271 [&](
const asio::error_code& ec)
277 asio::error_code cancelError;
278 socket.cancel(cancelError);
285 if (timedOut && !receiveCompleted)
288 "UDP receive timed out");
293 if (receiveError == asio::error::operation_aborted &&
297 "UDP receive timed out");
300 throw std::system_error(
302 "Failed to receive UDP datagram");
305 receiveBuffer.resize(receivedBytes);
307 return receiveBuffer;
314 throw std::system_error(
315 asio::error::not_connected,
316 "UDP socket is not open");
329 throw std::system_error(
331 "Failed to send UDP datagram");
void Close() noexcept
Close the UDP socket.
bool IsOpen() const noexcept
Check whether the socket is open.
asio::io_context & ioContext
void Open(const std::string &address, std::uint16_t port, bool isListener=false)
Open the UDP socket and configure the remote endpoint.
Bytes Receive(std::chrono::milliseconds timeout, asio::ip::udp::endpoint &remoteEndpoint)
Wait for an incoming UDP datagram and capture the sender's endpoint.
void SendTo(const Bytes &data, const asio::ip::udp::endpoint &targetEndpoint)
Send a UDP datagram to a specific remote endpoint.
asio::ip::udp::socket socket
Bytes SendReceive(const Bytes &data, std::chrono::milliseconds timeout) override
Send a UDP datagram and wait for one response.
RpcTransport(asio::io_context &ioContext)
Create a transport using the supplied Asio execution context.
void Send(const Bytes &data) override
Send a UDP datagram without waiting for a response.
asio::ip::udp::endpoint endpoint
Declares exceptions and error types used by the PROFINET IO controller stack.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
constexpr std::size_t RECEIVE_BUFFER_LENGTH
Receive buffer length.
UDP transport abstraction for PROFINET DCE/RPC.