#include "socket.hpp" #include using namespace std::literals; namespace network { socket::socket(const int af) : address_family_(af) { initialize_wsa(); this->socket_ = ::socket(af, SOCK_DGRAM, IPPROTO_UDP); if (af == AF_INET6) { int i = 1; setsockopt(this->socket_, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&i), static_cast(sizeof(i))); } } socket::~socket() { this->release(); } socket::socket(socket&& obj) noexcept { this->operator=(std::move(obj)); } socket& socket::operator=(socket&& obj) noexcept { if (this != &obj) { this->release(); this->socket_ = obj.socket_; this->port_ = obj.port_; this->address_family_ = obj.address_family_; obj.socket_ = INVALID_SOCKET; obj.address_family_ = AF_UNSPEC; } return *this; } void socket::release() { if (this->socket_ != INVALID_SOCKET) { closesocket(this->socket_); this->socket_ = INVALID_SOCKET; } } bool socket::bind_port(const address& target) { const auto result = bind(this->socket_, &target.get_addr(), target.get_size()) == 0; if (result) { this->port_ = target.get_port(); } return result; } bool socket::send(const address& target, const void* data, const size_t size) const { const auto res = sendto(this->socket_, static_cast(data), static_cast(size), 0, &target.get_addr(), target.get_size()); return static_cast(res) == size; } bool socket::send(const address& target, const std::string& data) const { return this->send(target, data.data(), data.size()); } bool socket::receive(address& source, std::string& data) const { char buffer[0x2000]; auto len = source.get_max_size(); const auto result = recvfrom(this->socket_, buffer, static_cast(sizeof(buffer)), 0, &source.get_addr(), &len); if (result == SOCKET_ERROR) { return false; } data.assign(buffer, buffer + result); return true; } bool socket::set_blocking(const bool blocking) { return socket::set_blocking(this->socket_, blocking); } bool socket::set_blocking(SOCKET s, const bool blocking) { #ifdef _WIN32 unsigned long mode = blocking ? 0 : 1; return ioctlsocket(s, FIONBIO, &mode) == 0; #else int flags = fcntl(s, F_GETFL, 0); if (flags == -1) return false; flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); return fcntl(s, F_SETFL, flags) == 0; #endif } bool socket::sleep(const std::chrono::milliseconds timeout) const { /*fd_set fdr; FD_ZERO(&fdr); FD_SET(this->socket_, &fdr); const auto msec = timeout.count(); timeval tv{}; tv.tv_sec = static_cast(msec / 1000ll); tv.tv_usec = static_cast((msec % 1000) * 1000); const auto retval = select(static_cast(this->socket_) + 1, &fdr, nullptr, nullptr, &tv); if (retval == SOCKET_ERROR) { std::this_thread::sleep_for(1ms); return socket_is_ready; } if (retval > 0) { return socket_is_ready; } return !socket_is_ready;*/ std::vector sockets{}; sockets.push_back(this); return sleep_sockets(sockets, timeout); } bool socket::sleep_until(const std::chrono::high_resolution_clock::time_point time_point) const { const auto duration = time_point - std::chrono::high_resolution_clock::now(); return this->sleep(std::chrono::duration_cast(duration)); } SOCKET socket::get_socket() const { return this->socket_; } uint16_t socket::get_port() const { return this->port_; } int socket::get_address_family() const { return this->address_family_; } bool socket::sleep_sockets(const std::span& sockets, const std::chrono::milliseconds timeout) { std::vector pfds{}; pfds.resize(sockets.size()); for (size_t i = 0; i < sockets.size(); ++i) { auto& pfd = pfds.at(i); const auto& socket = sockets[i]; pfd.fd = socket->get_socket(); pfd.events = POLLIN; pfd.revents = 0; } const auto retval = poll(pfds.data(), static_cast(pfds.size()), static_cast(timeout.count())); if (retval == SOCKET_ERROR) { std::this_thread::sleep_for(1ms); return socket_is_ready; } if (retval > 0) { return socket_is_ready; } return !socket_is_ready; } bool socket::is_socket_ready(const SOCKET s, const bool in_poll) { pollfd pfd{}; pfd.fd = s; pfd.events = in_poll ? POLLIN : POLLOUT; pfd.revents = 0; const auto retval = poll(&pfd, 1, 0); if (retval == SOCKET_ERROR) { std::this_thread::sleep_for(1ms); return socket_is_ready; } if (retval > 0) { return socket_is_ready; } return !socket_is_ready; } bool socket::sleep_sockets_until(const std::span& sockets, const std::chrono::high_resolution_clock::time_point time_point) { const auto duration = time_point - std::chrono::high_resolution_clock::now(); return sleep_sockets(sockets, std::chrono::duration_cast(duration)); } }