#include "UDP_Client.h" #include namespace Psc::asio_socket { void UDP_Client::create() { socket = std::make_unique(io_context); asio::error_code ec; socket->open(asio::ip::udp::v4(), ec); connected = false; connect_pending = false; read_pending = false; write_pending = false; recv_storage.assign(static_cast(read_chunk_size), 0); send_storage.assign(static_cast(read_chunk_size), 0); send_buffer.init(user_buffer_size); recv_buffer.init(user_buffer_size); state = Not_Set_Field; } bool UDP_Client::connect() { if (connected || connect_pending) return true; if (!socket) create(); if (dest_address.ip.empty() || dest_address.port == 0) { state = Not_Set_Field; return false; } asio::error_code ec; endpoint = asio::ip::udp::endpoint(asio::ip::make_address(dest_address.ip, ec), static_cast(dest_address.port)); if (ec) { state = Not_Set_Field; return false; } io_context.restart(); connect_pending = true; state = Connecting; socket->async_connect(endpoint, [this](const asio::error_code& connect_ec) { connect_pending = false; if (connect_ec == asio::error::operation_aborted) return; if (connect_ec) { connected = false; state = Not_Set_Field; return; } connected = true; state = Working; start_read(); start_write(); }); return true; } std::string UDP_Client::read() { std::string ret(static_cast(read_chunk_size), '\0'); std::size_t out_len = ret.size(); if (!recv_buffer.read(ret.data(), out_len)) return {}; ret.resize(out_len); return ret; } void UDP_Client::tick() { if (!connected && !connect_pending && !dest_address.ip.empty() && dest_address.port != 0) { connect(); } if (connected) { start_read(); start_write(); } io_context.restart(); io_context.poll(); if (connected) { start_read(); start_write(); } } void UDP_Client::send(std::string_view data) { if (data.empty()) return; send_buffer.write(data.data(), data.size()); if (!connected) connect(); if (connected) start_write(); } void UDP_Client::start_read() { if (read_pending || !connected || !socket || !socket->is_open()) return; if (recv_storage.empty()) recv_storage.assign(static_cast(read_chunk_size), 0); read_pending = true; socket->async_receive(asio::buffer(recv_storage.data(), recv_storage.size()), [this](const asio::error_code& ec, std::size_t n) { read_pending = false; if (!connected) return; if (ec == asio::error::operation_aborted) return; if (ec) { connected = false; state = Not_Set_Field; return; } recv_buffer.write(recv_storage.data(), n); start_read(); }); } void UDP_Client::start_write() { if (write_pending || !connected || !socket || !socket->is_open()) return; if (send_storage.empty()) send_storage.assign(static_cast(read_chunk_size), 0); std::size_t out_len = send_storage.size(); if (!send_buffer.peek(send_storage.data(), out_len)) return; send_storage.resize(out_len); write_pending = true; socket->async_send(asio::buffer(send_storage.data(), send_storage.size()), [this](const asio::error_code& ec, std::size_t) { write_pending = false; if (!connected) return; if (ec == asio::error::operation_aborted) return; if (ec) { connected = false; state = Not_Set_Field; return; } send_buffer.skip_one(); send_storage.assign(static_cast(read_chunk_size), 0); start_write(); }); } void UDP_Client::close() { connected = false; connect_pending = false; read_pending = false; write_pending = false; if (socket) { asio::error_code ec; socket->cancel(ec); socket->close(ec); } state = Not_Created; } std::string UDP_Client::to_string() { return "UDP_Client:[" + dest_address.to_string() + "]"; } } // namespace Psc::asio_socket