diff --git a/include/Nazara/Network/Enums.hpp b/include/Nazara/Network/Enums.hpp index b2184ab64..87eab41ae 100644 --- a/include/Nazara/Network/Enums.hpp +++ b/include/Nazara/Network/Enums.hpp @@ -9,6 +9,22 @@ namespace Nz { + enum ResolveError + { + ResolveError_NoError, + + ResolveError_Internal, //< An internal error occured + ResolveError_ResourceError, //< The operating system lacks the resources to proceed (insufficient memory) + ResolveError_NonRecoverable, //< An nonrecoverable error occured + ResolveError_NotFound, //< No such host is known + ResolveError_NotInitialized, //< Nazara network has not been initialized + ResolveError_ProtocolNotSupported, //< A specified protocol is not supported by the server + ResolveError_TemporaryFailure, //< A temporary failure occured, try again + ResolveError_Unknown, //< The last operation failed with an unlisted error code + + ResolveError_Max = ResolveError_TemporaryFailure + }; + enum NetProtocol { NetProtocol_Any, diff --git a/include/Nazara/Network/IpAddress.hpp b/include/Nazara/Network/IpAddress.hpp index b426f1c16..e7ae9bd23 100644 --- a/include/Nazara/Network/IpAddress.hpp +++ b/include/Nazara/Network/IpAddress.hpp @@ -55,8 +55,8 @@ namespace Nz IpAddress& operator=(const IpAddress&) = default; IpAddress& operator=(IpAddress&&) = default; - static String ResolveAddress(const IpAddress& address, String* service = nullptr); - static std::vector ResolveHostname(NetProtocol procol, const String& hostname, const String& protocol = "http"); + static String ResolveAddress(const IpAddress& address, String* service = nullptr, ResolveError* error = nullptr); + static std::vector ResolveHostname(NetProtocol procol, const String& hostname, const String& protocol = "http", ResolveError* error = nullptr); inline friend std::ostream& operator<<(std::ostream& out, const IpAddress& address); diff --git a/src/Nazara/Network/IpAddress.cpp b/src/Nazara/Network/IpAddress.cpp index 41654eb4e..7dfe07056 100644 --- a/src/Nazara/Network/IpAddress.cpp +++ b/src/Nazara/Network/IpAddress.cpp @@ -142,17 +142,17 @@ namespace Nz return stream; } - String IpAddress::ResolveAddress(const IpAddress& address, String* service) + String IpAddress::ResolveAddress(const IpAddress& address, String* service, ResolveError* error) { String hostname; - IpAddressImpl::ResolveAddress(address, &hostname, service); + IpAddressImpl::ResolveAddress(address, &hostname, service, error); return hostname; } - std::vector IpAddress::ResolveHostname(NetProtocol protocol, const String& hostname, const String& service) + std::vector IpAddress::ResolveHostname(NetProtocol protocol, const String& hostname, const String& service, ResolveError* error) { - return IpAddressImpl::ResolveHostname(protocol, hostname, service); + return IpAddressImpl::ResolveHostname(protocol, hostname, service, error); } IpAddress IpAddress::AnyIpV4(0, 0, 0, 0); diff --git a/src/Nazara/Network/Win32/IpAddressImpl.cpp b/src/Nazara/Network/Win32/IpAddressImpl.cpp index 0ded6dbdc..360513ff5 100644 --- a/src/Nazara/Network/Win32/IpAddressImpl.cpp +++ b/src/Nazara/Network/Win32/IpAddressImpl.cpp @@ -147,15 +147,26 @@ namespace Nz return IpAddress(rawIpV6[0], rawIpV6[1], rawIpV6[2], rawIpV6[3], rawIpV6[4], rawIpV6[5], rawIpV6[6], rawIpV6[7], ntohs(addressv6->sin6_port)); } - bool IpAddressImpl::ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service) + bool IpAddressImpl::ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service, ResolveError* error) { SockAddrBuffer socketAddress; socklen_t socketAddressLen = ToSockAddr(ipAddress, socketAddress.data()); - return Detail::GetHostnameInfo(reinterpret_cast(socketAddress.data()), socketAddressLen, hostname, service) == 0; + if (Detail::GetHostnameInfo(reinterpret_cast(socketAddress.data()), socketAddressLen, hostname, service) != 0) + { + if (error) + *error = TranslateWSAErrorToResolveError(WSAGetLastError()); + + return false; + } + + if (error) + *error = ResolveError_NoError; + + return true; } - std::vector IpAddressImpl::ResolveHostname(NetProtocol procol, const String& hostname, const String& service) + std::vector IpAddressImpl::ResolveHostname(NetProtocol procol, const String& hostname, const String& service, ResolveError* error) { std::vector results; @@ -165,10 +176,11 @@ namespace Nz hints.ai_socktype = SOCK_STREAM; Detail::addrinfoImpl* servinfo; - int rv; - if ((rv = Detail::GetAddressInfo(hostname, service, &hints, &servinfo)) != 0) + if (Detail::GetAddressInfo(hostname, service, &hints, &servinfo) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + if (error) + *error = TranslateWSAErrorToResolveError(WSAGetLastError()); + return results; } @@ -190,6 +202,9 @@ namespace Nz results.push_back(result); } + if (error) + *error = ResolveError_NoError; + return results; } @@ -237,4 +252,41 @@ namespace Nz NazaraError("Invalid ip address"); return 0; } + + ResolveError IpAddressImpl::TranslateWSAErrorToResolveError(int error) + { + switch (error) + { + case 0: + return ResolveError_NoError; + + // Engine error + case WSAEFAULT: + case WSAEINVAL: + return ResolveError_Internal; + + case WSAEAFNOSUPPORT: + case WSAESOCKTNOSUPPORT: + case WSASERVICE_NOT_FOUND: + return ResolveError_ProtocolNotSupported; + + case WSAHOST_NOT_FOUND: + return ResolveError_NotFound; + + case WSANO_RECOVERY: + return ResolveError_NonRecoverable; + + case WSANOTINITIALISED: + return ResolveError_NotInitialized; + + case WSA_NOT_ENOUGH_MEMORY: + return ResolveError_ResourceError; + + case WSATRY_AGAIN: + return ResolveError_TemporaryFailure; + } + + NazaraWarning("Unhandled WinSock error: " + Error::GetLastSystemError(error) + " (" + String::Number(error) + ')'); + return ResolveError_Unknown; + } } diff --git a/src/Nazara/Network/Win32/IpAddressImpl.hpp b/src/Nazara/Network/Win32/IpAddressImpl.hpp index 57e6bbcc5..ad3ca6689 100644 --- a/src/Nazara/Network/Win32/IpAddressImpl.hpp +++ b/src/Nazara/Network/Win32/IpAddressImpl.hpp @@ -22,9 +22,10 @@ namespace Nz static IpAddress FromSockAddr(const sockaddr_in* addressv4); static IpAddress FromSockAddr(const sockaddr_in6* addressv6); - static bool ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service); - static std::vector ResolveHostname(NetProtocol procol, const String& hostname, const String& service); + static bool ResolveAddress(const IpAddress& ipAddress, String* hostname, String* service, ResolveError* error); + static std::vector ResolveHostname(NetProtocol procol, const String& hostname, const String& service, ResolveError* error); static socklen_t ToSockAddr(const IpAddress& ipAddress, void* buffer); + static ResolveError TranslateWSAErrorToResolveError(int error); }; }