#include "ntptun/UdpSocket.hpp" #include #include "ntptun/Platform.hpp" namespace ntptun { UdpSocket::~UdpSocket() { close_fd(); } UdpSocket::UdpSocket(UdpSocket&& other) noexcept : fd_(other.fd_) { other.fd_ = kInvalidSocket; } UdpSocket& UdpSocket::operator=(UdpSocket&& other) noexcept { if (this != &other) { close_fd(); fd_ = other.fd_; other.fd_ = kInvalidSocket; } return *this; } void UdpSocket::close_fd() noexcept { if (fd_ != kInvalidSocket) { socket_close(fd_); fd_ = kInvalidSocket; } } UdpSocket UdpSocket::create(int family) { net_startup(); const socket_t fd = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); if (fd == kInvalidSocket) { socket_throw("socket"); } return UdpSocket(fd); } UdpSocket UdpSocket::bind(const Endpoint& local) { UdpSocket sock = create(local.family()); const int one = 1; ::setsockopt(sock.fd_, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&one), sizeof(one)); if (::bind(sock.fd_, local.sockaddr_ptr(), local.length()) != 0) { socket_throw("bind"); } return sock; } void UdpSocket::connect(const Endpoint& remote) { if (::connect(fd_, remote.sockaddr_ptr(), remote.length()) != 0) { socket_throw("connect"); } } void UdpSocket::set_nonblocking(bool enabled) { socket_set_nonblocking(fd_, enabled); } ssize_t UdpSocket::recv_from(Byte* buf, std::size_t len, Endpoint& from) { sockaddr_storage src{}; socklen_t src_len = sizeof(src); const ssize_t n = ::recvfrom(fd_, reinterpret_cast(buf), static_cast(len), 0, reinterpret_cast(&src), &src_len); if (n < 0) { if (socket_would_block()) { return -1; } socket_throw("recvfrom"); } std::memcpy(from.sockaddr_ptr(), &src, src_len); from.set_length(src_len); return n; } ssize_t UdpSocket::send_to(const Byte* buf, std::size_t len, const Endpoint& to) { const ssize_t n = ::sendto(fd_, reinterpret_cast(buf), static_cast(len), 0, to.sockaddr_ptr(), to.length()); if (n < 0) { if (socket_would_block()) { return -1; } socket_throw("sendto"); } return n; } ssize_t UdpSocket::recv(Byte* buf, std::size_t len) { const ssize_t n = ::recv(fd_, reinterpret_cast(buf), static_cast(len), 0); if (n < 0) { if (socket_would_block()) { return -1; } socket_throw("recv"); } return n; } ssize_t UdpSocket::send(const Byte* buf, std::size_t len) { const ssize_t n = ::send(fd_, reinterpret_cast(buf), static_cast(len), 0); if (n < 0) { if (socket_would_block()) { return -1; } socket_throw("send"); } return n; } } // namespace ntptun