#include "IO/Socket/UDP_BSD.h" #include "Log.h" #include #include #include #include #include #include #include #include namespace lwe { UDP::~UDP() { if (hdl == LWE_INVALID_SOCKET) return; Int_32 code = close(hdl); if (code == -1) LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + "."); } UDP::UDP() : hdl(LWE_INVALID_SOCKET) { } UDP::UDP(const AddrType addrType) : BaseUDP(addrType), hdl(LWE_INVALID_SOCKET) { if (addrType == AddrType::IPV6) hdl = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); else if (addrType == AddrType::IPV4) hdl = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); else return; if (hdl == LWE_INVALID_SOCKET) { UInt_32 code = errno; LWE_LOG_INT("Error", 1, "Failed to create socket with error #" + Str_8::FromNum(code) + "."); return; } } UDP::UDP(UDP&& udp) noexcept : BaseUDP(std::move(udp)), hdl(udp.hdl) { udp.hdl = LWE_INVALID_SOCKET; } UDP::UDP(const UDP& udp) : BaseUDP(udp), hdl(LWE_INVALID_SOCKET) { } UDP& UDP::operator=(UDP&& udp) noexcept { if (this == &udp) return *this; BaseUDP::operator=(std::move(udp)); hdl = udp.hdl; udp.hdl = LWE_INVALID_SOCKET; return *this; } UDP& UDP::operator=(const UDP& udp) { if (this == &udp) return *this; BaseUDP::operator=(udp); hdl = LWE_INVALID_SOCKET; return *this; } void UDP::Release() { if (!IsValid()) return; Int_32 code = close(hdl); if (code == -1) LWE_LOG_INT("Error", 0, "Failed to close socket with error #" + Str_8::FromNum(errno) + "."); hdl = LWE_INVALID_SOCKET; bound = false; } void UDP::Bind(const Str_8& address, const UInt_16 port) { if (!IsValid() || bound) return; if (addrType == AddrType::IPV6) Bind_v6(address, port); else if (addrType == AddrType::IPV4) Bind_v4(address, port); this->address = address; this->port = port; bound = true; } UInt_64 UDP::Send(const Str_8& address, const UInt_16 port, const Byte *const data, const UInt_64 size) { if (addrType == AddrType::IPV6) return Send_v6(address, port, data, size); else if (addrType == AddrType::IPV4) return Send_v4(address, port, data, size); return 0; } UInt_64 UDP::Receive(Str_8* const address, UInt_16* const port, Byte* const data, const UInt_64 size) { if (!IsValid()) { LWE_LOG_INT("Error", 0, "Attempted to receive while socket is not initialized."); return 0; } sockaddr_in6 remote = {}; UInt_32 addrLen = sizeof(sockaddr_in); SInt_64 received = 0; received = recvfrom(hdl, data, size, 0, (sockaddr*)&remote, &addrLen); if (received == -1) { int code = errno; if (code != ECONNRESET && code != EWOULDBLOCK) { Release(); LWE_LOG_INT("Error", 1, "Failed to receive with error #" + Str_8::FromNum(code) + "."); } return 0; } if (addrLen == sizeof(sockaddr_in6)) { char tmpAddr[INET6_ADDRSTRLEN]; if (!inet_ntop(remote.sin6_family, &remote.sin6_addr, tmpAddr, INET6_ADDRSTRLEN)) { Int_32 code = errno; LWE_LOG_INT("Error", 2, "Failed to convert IPv6 address with error #" + Str_8::FromNum(code) + "."); return received; } *address = tmpAddr; *port = ntohs(remote.sin6_port); } else if (addrLen == sizeof(sockaddr_in)) { char tmpAddr[INET_ADDRSTRLEN]; if (!inet_ntop(((sockaddr_in*)&remote)->sin_family, &((sockaddr_in*)&remote)->sin_addr, tmpAddr, INET_ADDRSTRLEN)) { Int_32 code = errno; LWE_LOG_INT("Error", 2, "Failed to convert IPv4 address with error #" + Str_8::FromNum(code) + "."); return received; } *address = tmpAddr; *port = ntohs(((sockaddr_in*)&remote)->sin_port); } return received; } void UDP::SetBlocking(const bool blocking) { if (!IsValid()) { LWE_LOG_INT("Error", 0, "Attempted to toggle blocking while socket is not initialized."); return; } if (fcntl(hdl, F_SETFL, O_NONBLOCK, blocking) == -1) LWE_LOG_INT("Error", 1, "Failed to toggle non-blocking mode with error #" + Str_8::FromNum(errno) + "."); } bool UDP::IsBlocking() const { return (bool)fcntl(hdl, F_GETFL, O_NONBLOCK); } bool UDP::IsValid() const { return hdl != LWE_INVALID_SOCKET; } void UDP::Bind_v6(const Str_8& address, const UInt_16 port) { sockaddr_in6 result = {}; result.sin6_family = AF_INET6; result.sin6_port = htons(port); if (address.Size()) { Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr); if (!code) { LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid."); return; } else if (code == -1) { Int_32 dCode = errno; LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + "."); return; } } else { result.sin6_addr = in6addr_any; } int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in6)); if (code == -1) { LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + "."); return; } } void UDP::Bind_v4(const Str_8& address, const UInt_16 port) { sockaddr_in result = {}; result.sin_family = AF_INET; result.sin_port = htons(port); if (address.Size()) { int code = inet_pton(AF_INET, address, &result.sin_addr); if (!code) { LWE_LOG_INT("Error", 0, "The given address, \"" + address + "\" is not valid."); return; } else if (code == -1) { Int_32 dCode = errno; LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + "."); return; } } else { result.sin_addr.s_addr = INADDR_ANY; } int code = bind(hdl, (sockaddr*)&result, sizeof(sockaddr_in)); if (code == -1) { LWE_LOG_INT("Error", 2, "Failed to bind socket with error #" + Str_8::FromNum(errno) + "."); return; } } UInt_64 UDP::Send_v6(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size) { if (!IsValid()) { LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized."); return 0; } sockaddr_in6 result = {}; result.sin6_family = AF_INET6; result.sin6_port = htons(port); Int_32 code = inet_pton(AF_INET6, address, &result.sin6_addr); if (!code) { LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid."); return 0; } else if (code == -1) { Int_32 dCode = errno; LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + "."); return 0; } Int_32 sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in6)); if (sent == -1) { Int_32 dCode = errno; LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + "."); Release(); return 0; } return sent; } UInt_64 UDP::Send_v4(const Str_8& addr, const UInt_16 port, const Byte* const data, const UInt_64 size) { if (!IsValid()) { LWE_LOG_INT("Info", 0, "Attempted to send while socket is not initialized."); return 0; } sockaddr_in result = {}; result.sin_family = AF_INET; result.sin_port = htons(port); int code = inet_pton(AF_INET, address, &result.sin_addr); if (!code) { LWE_LOG_INT("Error", 1, "The given address, \"" + address + "\" is not valid."); return 0; } else if (code == -1) { Int_32 dCode = errno; LWE_LOG_INT("Error", 1, "Failed to convert address with error #" + Str_8::FromNum(dCode) + "."); return 0; } int sent = sendto(hdl, (char*)&data[0], (int)size, 0, (sockaddr*)&result, sizeof(sockaddr_in)); if (sent == -1) { Int_32 dCode = errno; LWE_LOG_INT("Error", 3, "Failed to send with error #" + Str_8::FromNum(dCode) + "."); Release(); return 0; } return sent; } };