Network: Fix posix implementation

This commit is contained in:
Jérôme Leclercq 2022-02-24 18:28:41 +01:00
parent d827477de2
commit cb1bc956b2
3 changed files with 39 additions and 101 deletions

View File

@ -13,64 +13,6 @@
namespace Nz namespace Nz
{ {
namespace Detail
{
using addrinfoImpl = addrinfo;
int GetAddressInfo(const std::string& hostname, const std::string& service, const addrinfoImpl* hints, addrinfoImpl** results)
{
return getaddrinfo(hostname.c_str(), service.c_str(), hints, results);
}
int GetHostnameInfo(sockaddr* socketAddress, socklen_t socketLen, std::string* hostname, std::string* service, int flags)
{
std::array<char, NI_MAXHOST> hostnameBuffer;
std::array<char, NI_MAXSERV> serviceBuffer;
int result = getnameinfo(socketAddress, socketLen, hostnameBuffer.data(), hostnameBuffer.size(), serviceBuffer.data(), serviceBuffer.size(), flags);
if (result == 0)
{
if (hostname)
hostname->assign(hostnameBuffer.data());
if (service)
service->assign(serviceBuffer.data());
}
return result;
}
void FreeAddressInfo(addrinfoImpl* results)
{
freeaddrinfo(results);
}
IpAddress::IPv4 convertSockaddrToIPv4(const in_addr& addr)
{
union byteToInt
{
UInt8 b[sizeof(uint32_t)];
uint32_t i;
};
byteToInt hostOrder;
hostOrder.i = ntohl(addr.s_addr);
return { {hostOrder.b[3], hostOrder.b[2], hostOrder.b[1], hostOrder.b[0]} };
}
IpAddress::IPv6 convertSockaddr6ToIPv6(const in6_addr& addr)
{
auto& rawIpV6 = addr.s6_addr;
IpAddress::IPv6 ipv6;
for (unsigned int i = 0; i < 8; ++i)
ipv6[i] = Nz::UInt16(rawIpV6[i * 2]) << 8 | rawIpV6[i * 2 + 1];
return ipv6;
}
}
IpAddress IpAddressImpl::FromAddrinfo(const addrinfo* info) IpAddress IpAddressImpl::FromAddrinfo(const addrinfo* info)
{ {
switch (info->ai_family) switch (info->ai_family)
@ -109,14 +51,21 @@ namespace Nz
IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in* addressv4) IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in* addressv4)
{ {
IpAddress::IPv4 ip4Address = Detail::convertSockaddrToIPv4(addressv4->sin_addr); IpAddress::IPv4 ipv4;
return IpAddress(ip4Address, ntohs(addressv4->sin_port)); std::memcpy(&ipv4[0], &addressv4->sin_addr.s_addr, sizeof(uint32_t)); //< addr.s_addr is in big-endian so its already correctly ordered
return IpAddress(ipv4, ntohs(addressv4->sin_port));
} }
IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in6* addressv6) IpAddress IpAddressImpl::FromSockAddr(const sockaddr_in6* addressv6)
{ {
IpAddress::IPv6 ip6Address = Detail::convertSockaddr6ToIPv6(addressv6->sin6_addr); auto& rawIpV6 = addressv6->sin6_addr.s6_addr;
return IpAddress(ip6Address, ntohs(addressv6->sin6_port));
IpAddress::IPv6 ipv6;
for (unsigned int i = 0; i < 8; ++i)
ipv6[i] = UInt16(rawIpV6[i * 2]) << 8 | rawIpV6[i * 2 + 1];
return IpAddress(ipv6, ntohs(addressv6->sin6_port));
} }
bool IpAddressImpl::ResolveAddress(const IpAddress& ipAddress, std::string* hostname, std::string* service, ResolveError* error) bool IpAddressImpl::ResolveAddress(const IpAddress& ipAddress, std::string* hostname, std::string* service, ResolveError* error)
@ -124,7 +73,10 @@ namespace Nz
SockAddrBuffer socketAddress; SockAddrBuffer socketAddress;
socklen_t socketAddressLen = ToSockAddr(ipAddress, socketAddress.data()); socklen_t socketAddressLen = ToSockAddr(ipAddress, socketAddress.data());
if (Detail::GetHostnameInfo(reinterpret_cast<sockaddr*>(socketAddress.data()), socketAddressLen, hostname, service, NI_NUMERICSERV) != 0) std::array<char, NI_MAXHOST> hostnameBuffer;
std::array<char, NI_MAXSERV> serviceBuffer;
if (getnameinfo(reinterpret_cast<sockaddr*>(socketAddress.data()), socketAddressLen, hostnameBuffer.data(), hostnameBuffer.size(), serviceBuffer.data(), serviceBuffer.size(), NI_NUMERICSERV) != 0)
{ {
if (error) if (error)
*error = TranslateEAIErrorToResolveError(errno); *error = TranslateEAIErrorToResolveError(errno);
@ -132,6 +84,12 @@ namespace Nz
return false; return false;
} }
if (hostname)
hostname->assign(hostnameBuffer.data());
if (service)
service->assign(serviceBuffer.data());
if (error) if (error)
*error = ResolveError::NoError; *error = ResolveError::NoError;
@ -142,14 +100,14 @@ namespace Nz
{ {
std::vector<HostnameInfo> results; std::vector<HostnameInfo> results;
Detail::addrinfoImpl hints; addrinfo hints;
std::memset(&hints, 0, sizeof(Detail::addrinfoImpl)); std::memset(&hints, 0, sizeof(addrinfo));
hints.ai_family = SocketImpl::TranslateNetProtocolToAF(procol); hints.ai_family = SocketImpl::TranslateNetProtocolToAF(procol);
hints.ai_flags = AI_CANONNAME; hints.ai_flags = AI_CANONNAME;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
Detail::addrinfoImpl* servinfo; addrinfo* servinfo;
if (Detail::GetAddressInfo(hostname, service, &hints, &servinfo) != 0) if (getaddrinfo(hostname.c_str(), service.c_str(), &hints, &servinfo) != 0)
{ {
if (error) if (error)
*error = TranslateEAIErrorToResolveError(errno); *error = TranslateEAIErrorToResolveError(errno);
@ -159,18 +117,20 @@ namespace Nz
CallOnExit onExit([servinfo]() CallOnExit onExit([servinfo]()
{ {
Detail::FreeAddressInfo(servinfo); freeaddrinfo(servinfo);
}); });
// loop through all the results and connect to the first we can // loop through all the results and connect to the first we can
for (Detail::addrinfoImpl* p = servinfo; p != nullptr; p = p->ai_next) for (addrinfo* p = servinfo; p != nullptr; p = p->ai_next)
{ {
HostnameInfo result; HostnameInfo result;
result.address = FromAddrinfo(p); result.address = FromAddrinfo(p);
result.canonicalName = p->ai_canonname;
result.protocol = TranslatePFToNetProtocol(p->ai_family); result.protocol = TranslatePFToNetProtocol(p->ai_family);
result.socketType = TranslateSockToNetProtocol(p->ai_socktype); result.socketType = TranslateSockToNetProtocol(p->ai_socktype);
if (p->ai_canonname)
result.canonicalName = p->ai_canonname;
results.push_back(result); results.push_back(result);
} }

View File

@ -211,8 +211,8 @@ namespace Nz
{ {
NazaraAssert(handle != InvalidHandle, "Invalid handle"); NazaraAssert(handle != InvalidHandle, "Invalid handle");
u_long availableBytes; int availableBytes;
if (ioctl(handle, FIONREAD, &availableBytes) == -1) if (ioctl(handle, FIONREAD, &availableBytes) != 0)
{ {
if (error) if (error)
*error = TranslateErrorToSocketError(errno); *error = TranslateErrorToSocketError(errno);
@ -223,7 +223,7 @@ namespace Nz
if (error) if (error)
*error = SocketError::NoError; *error = SocketError::NoError;
return availableBytes; return SafeCast<std::size_t>(availableBytes);
} }
bool SocketImpl::QueryBroadcasting(SocketHandle handle, SocketError* error) bool SocketImpl::QueryBroadcasting(SocketHandle handle, SocketError* error)
@ -266,25 +266,9 @@ namespace Nz
std::size_t SocketImpl::QueryMaxDatagramSize(SocketHandle handle, SocketError* error) std::size_t SocketImpl::QueryMaxDatagramSize(SocketHandle handle, SocketError* error)
{ {
int code; // There's no SO_MAX_MSG_SIZE on POSIX
socklen_t codeLength = sizeof(code); // We could use IP_MTU but it requires a connected socket
return std::min<std::size_t>(QuerySendBufferSize(handle, error), 65507); //< Max IPv4 value (IPv6 is 65527)
#if defined(NAZARA_PLATFORM_MACOSX)
return 0; //No IP_MTU on macosx
#else
if (getsockopt(handle, IPPROTO_IP, IP_MTU, &code, &codeLength) == -1)
{
if (error)
*error = TranslateErrorToSocketError(errno);
return 0;
}
#endif
if (error)
*error = SocketError::NoError;
return code;
} }
bool SocketImpl::QueryNoDelay(SocketHandle handle, SocketError* error) bool SocketImpl::QueryNoDelay(SocketHandle handle, SocketError* error)

View File

@ -57,9 +57,6 @@ namespace Nz
std::string TranslateCanonicalName(const wchar_t* str) std::string TranslateCanonicalName(const wchar_t* str)
{ {
if (!str)
return {};
return FromWideString(str); return FromWideString(str);
} }
#else #else
@ -95,9 +92,6 @@ namespace Nz
std::string TranslateCanonicalName(const char* str) std::string TranslateCanonicalName(const char* str)
{ {
if (!str)
return {};
return str; return str;
} }
#endif #endif
@ -225,13 +219,13 @@ namespace Nz
for (Detail::addrinfoImpl* p = servinfo; p != nullptr; p = p->ai_next) for (Detail::addrinfoImpl* p = servinfo; p != nullptr; p = p->ai_next)
{ {
HostnameInfo result; HostnameInfo& result = results.emplace_back();
result.address = FromAddrinfo(p); result.address = FromAddrinfo(p);
result.canonicalName = Detail::TranslateCanonicalName(p->ai_canonname);
result.protocol = TranslatePFToNetProtocol(p->ai_family); result.protocol = TranslatePFToNetProtocol(p->ai_family);
result.socketType = TranslateSockToNetProtocol(p->ai_socktype); result.socketType = TranslateSockToNetProtocol(p->ai_socktype);
results.push_back(result); if (p->ai_canonname)
result.canonicalName = Detail::TranslateCanonicalName(p->ai_canonname);
} }
if (error) if (error)