// Copyright (C) 2015 Jérôme Leclercq // This file is part of the "Nazara Engine - Network module" // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include #include #if defined(NAZARA_PLATFORM_WINDOWS) #include #elif defined(NAZARA_PLATFORM_POSIX) #include #else #error Missing implementation: Network #endif #include namespace Nz { bool IpAddress::BuildFromAddress(const char* address) { m_isValid = false; bool isIPv6; UInt8 result[16]; if (!ParseIPAddress(address, result, &m_port, &isIPv6, nullptr)) return false; m_isValid = true; if (isIPv6) { m_protocol = NetProtocol_IPv6; for (unsigned int i = 0; i < 8; ++i) m_ipv6[i] = UInt32(result[i*2]) << 8 | result[i*2 + 1]; } else { m_protocol = NetProtocol_IPv4; for (unsigned int i = 0; i < 4; ++i) m_ipv4[i] = result[i]; } return true; } bool IpAddress::IsLoopback() const { if (!m_isValid) return false; NazaraAssert(m_protocol <= NetProtocol_Max, "Protocol has value out of enum"); switch (m_protocol) { case NetProtocol_Any: case NetProtocol_Unknown: break; case NetProtocol_IPv4: return m_ipv4[0] == 127; case NetProtocol_IPv6: return m_ipv6 == LoopbackIpV6.m_ipv6; // Only compare the ip value } NazaraInternalError("Invalid protocol for IpAddress (0x" + String::Number(m_protocol) + ')'); return false; } String IpAddress::ToString() const { StringStream stream; if (m_isValid) { NazaraAssert(m_protocol <= NetProtocol_Max, "Protocol has value out of enum"); switch (m_protocol) { case NetProtocol_Any: case NetProtocol_Unknown: break; case NetProtocol_IPv4: for (unsigned int i = 0; i < 4; ++i) { stream << int(m_ipv4[i]); if (i != 3) stream << '.'; } break; case NetProtocol_IPv6: // Canonical representation of an IPv6 // https://tools.ietf.org/html/rfc5952 // Find the longest zero sequence unsigned int f0 = std::numeric_limits::max(); unsigned int l0 = std::numeric_limits::max(); for (unsigned int i = 0; i < 8; ++i) { if (m_ipv6[i] == 0) { unsigned int j; for (j = i + 1; j < 8; ++j) { if (m_ipv6[j] != 0) break; } if (j - i > std::max(l0 - f0, 1)) { f0 = i; l0 = j; } } } // We need brackets around our IPv6 address if we have a port if (m_port != 0) stream << '['; for (unsigned int i = 0; i < 8; ++i) { if (i == f0) { stream << "::"; i = l0; if (i >= 8) break; } else if (i != 0) stream << ':'; stream << String::Number(m_ipv6[i], 16).ToLower(); } if (m_port != 0) stream << ']'; break; } if (m_port != 0) stream << ':' << m_port; } return stream; } String IpAddress::ResolveAddress(const IpAddress& address, String* service, ResolveError* error) { NazaraAssert(address.IsValid(), "Invalid address"); String hostname; IpAddressImpl::ResolveAddress(address, &hostname, service, error); return hostname; } std::vector IpAddress::ResolveHostname(NetProtocol protocol, const String& hostname, const String& service, ResolveError* error) { NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); return IpAddressImpl::ResolveHostname(protocol, hostname, service, error); } IpAddress IpAddress::AnyIpV4(0, 0, 0, 0); IpAddress IpAddress::AnyIpV6(0, 0, 0, 0, 0, 0, 0, 0, 0); IpAddress IpAddress::BroadcastIpV4(255, 255, 255, 255); IpAddress IpAddress::Invalid; IpAddress IpAddress::LoopbackIpV4(127, 0, 0, 1); IpAddress IpAddress::LoopbackIpV6(0, 0, 0, 0, 0, 0, 0, 1); }