Add IPv6 support and sfDns

- Grow sfIpAddress to hold IPv6 addresses and add address types

- Make sfIpAddress_fromString not resolve network names anymore, matching sf::IpAddress::fromString, and add the deprecated sfIpAddress_resolve

- Add sfDns for resolving hostnames and querying NS, MX, SRV and TXT records
This commit is contained in:
Lukas Dürrenberger committed 2026-10-04 22:12:01 +02:00
1 parent 523c48cf98
commit 917e811888
16 files changed
+1112 -48

No files matched your search

+1
View File
@@ -28,6 +28,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/Dns.h>
#include <CSFML/Network/Ftp.h>
#include <CSFML/Network/Http.h>
#include <CSFML/Network/IpAddress.h>
+288
View File
@@ -0,0 +1,288 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2026 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/Export.h>
#include <CSFML/Network/IpAddress.h>
#include <CSFML/Network/Types.h>
#include <CSFML/System/Time.h>
#include <stddef.h>
#include <stdint.h>
////////////////////////////////////////////////////////////
/// \brief A DNS MX record
///
////////////////////////////////////////////////////////////
typedef struct
{
const char* exchange; ///< Host willing to act as mail exchange
uint16_t preference; ///< Preference of this record among others, lower values are preferred
} sfDnsMxRecord;
////////////////////////////////////////////////////////////
/// \brief A DNS SRV record
///
////////////////////////////////////////////////////////////
typedef struct
{
const char* target; ///< The domain name of the target host
uint16_t port; ///< The port on the target host of the service
uint16_t weight; ///< Server selection mechanism, larger weights should be given a proportionately higher probability of being selected
uint16_t priority; ///< The priority of the target host, a client must attempt to contact the target host with the lowest-numbered priority it can reach
} sfDnsSrvRecord;
////////////////////////////////////////////////////////////
/// \brief Resolve a hostname into a list of IP addresses
///
/// The returned array must be freed with sfFree.
///
/// \param hostname Hostname to resolve, encoded in UTF-8
/// \param servers The list of servers to query, NULL to use the default servers
/// \param serverCount Number of servers in \a servers
/// \param timeout Query timeout if using a provided list of servers, use 0 to wait forever
/// \param count Pointer to a variable that will be filled with the number of addresses
///
/// \return Array of IP addresses the given hostname resolves to, NULL if name resolution fails or no address was found
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress* sfDns_resolve(
const char* hostname,
const sfIpAddress* servers,
size_t serverCount,
sfTime timeout,
size_t* count);
////////////////////////////////////////////////////////////
/// \brief Query NS records for a hostname
///
/// \param hostname Hostname to query NS records for, encoded in UTF-8
/// \param servers The list of servers to query, NULL to use the default servers
/// \param serverCount Number of servers in \a servers
/// \param timeout Query timeout if using a provided list of servers, use 0 to wait forever
///
/// \return New list of NS records, which can be empty
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfDnsNsRecords* sfDns_queryNs(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout);
////////////////////////////////////////////////////////////
/// \brief Query MX records for a hostname
///
/// \param hostname Hostname to query MX records for, encoded in UTF-8
/// \param servers The list of servers to query, NULL to use the default servers
/// \param serverCount Number of servers in \a servers
/// \param timeout Query timeout if using a provided list of servers, use 0 to wait forever
///
/// \return New list of MX records, which can be empty
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfDnsMxRecords* sfDns_queryMx(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout);
////////////////////////////////////////////////////////////
/// \brief Query SRV records for a hostname
///
/// \param hostname Hostname to query SRV records for, encoded in UTF-8
/// \param servers The list of servers to query, NULL to use the default servers
/// \param serverCount Number of servers in \a servers
/// \param timeout Query timeout if using a provided list of servers, use 0 to wait forever
///
/// \return New list of SRV records, which can be empty
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfDnsSrvRecords* sfDns_querySrv(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout);
////////////////////////////////////////////////////////////
/// \brief Query TXT records for a hostname
///
/// \param hostname Hostname to query TXT records for, encoded in UTF-8
/// \param servers The list of servers to query, NULL to use the default servers
/// \param serverCount Number of servers in \a servers
/// \param timeout Query timeout if using a provided list of servers, use 0 to wait forever
///
/// \return New list of TXT records, which can be empty
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfDnsTxtRecords* sfDns_queryTxt(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout);
////////////////////////////////////////////////////////////
/// \brief Get the computer's public address via DNS
///
/// The public address is the address of the computer from the
/// point of view of the internet, i.e. something like 89.54.1.169
/// or 2600:1901:0:13e0::1 as opposed to a private or local address
/// like 192.168.1.56 or fe80::1234:5678:9abc.
///
/// This function depends on both your network connection and
/// the server, and may be very slow. You should try to use it
/// as little as possible.
///
/// \param timeout Maximum time to wait, use 0 to wait forever
/// \param type The type of public address to get
///
/// \return Public IP address of the computer on success, sfIpAddress_None otherwise
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfDns_getPublicAddress(sfTime timeout, sfIpAddressType type);
////////////////////////////////////////////////////////////
/// \brief Destroy a list of NS records
///
/// \param records List of NS records to destroy
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API void sfDnsNsRecords_destroy(const sfDnsNsRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get the number of NS records in a list
///
/// \param records List of NS records
///
/// \return Number of NS records
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API size_t sfDnsNsRecords_getCount(const sfDnsNsRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get a NS record of a list
///
/// \param records List of NS records
/// \param index Index of the NS record to get
///
/// \return The NS record, encoded in UTF-8
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const char* sfDnsNsRecords_getRecord(const sfDnsNsRecords* records, size_t index);
////////////////////////////////////////////////////////////
/// \brief Destroy a list of MX records
///
/// \param records List of MX records to destroy
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API void sfDnsMxRecords_destroy(const sfDnsMxRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get the number of MX records in a list
///
/// \param records List of MX records
///
/// \return Number of MX records
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API size_t sfDnsMxRecords_getCount(const sfDnsMxRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get a MX record of a list
///
/// The strings of the record stay valid until the list
/// is destroyed.
///
/// \param records List of MX records
/// \param index Index of the MX record to get
///
/// \return The MX record
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfDnsMxRecord sfDnsMxRecords_getRecord(const sfDnsMxRecords* records, size_t index);
////////////////////////////////////////////////////////////
/// \brief Destroy a list of SRV records
///
/// \param records List of SRV records to destroy
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API void sfDnsSrvRecords_destroy(const sfDnsSrvRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get the number of SRV records in a list
///
/// \param records List of SRV records
///
/// \return Number of SRV records
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API size_t sfDnsSrvRecords_getCount(const sfDnsSrvRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get a SRV record of a list
///
/// The strings of the record stay valid until the list
/// is destroyed.
///
/// \param records List of SRV records
/// \param index Index of the SRV record to get
///
/// \return The SRV record
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfDnsSrvRecord sfDnsSrvRecords_getRecord(const sfDnsSrvRecords* records, size_t index);
////////////////////////////////////////////////////////////
/// \brief Destroy a list of TXT records
///
/// \param records List of TXT records to destroy
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API void sfDnsTxtRecords_destroy(const sfDnsTxtRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get the number of TXT records in a list
///
/// \param records List of TXT records
///
/// \return Number of TXT records
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API size_t sfDnsTxtRecords_getCount(const sfDnsTxtRecords* records);
////////////////////////////////////////////////////////////
/// \brief Get the number of strings in a TXT record
///
/// \param records List of TXT records
/// \param index Index of the TXT record
///
/// \return Number of strings in the TXT record
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API size_t sfDnsTxtRecords_getStringCount(const sfDnsTxtRecords* records, size_t index);
////////////////////////////////////////////////////////////
/// \brief Get a string of a TXT record
///
/// \param records List of TXT records
/// \param index Index of the TXT record
/// \param stringIndex Index of the string within the TXT record
///
/// \return The string, encoded in UTF-8
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const char* sfDnsTxtRecords_getString(const sfDnsTxtRecords* records, size_t index, size_t stringIndex);
+176 -12
View File
@@ -31,17 +31,34 @@
#include <CSFML/System/Time.h>
#include <stdbool.h>
#include <stdint.h>
////////////////////////////////////////////////////////////
/// \brief Encapsulate an IPv4 network address
/// \brief Encapsulate an IPv4 or IPv6 network address
///
/// The address is stored as its string representation,
/// which is large enough to hold any IPv6 address.
///
////////////////////////////////////////////////////////////
typedef struct
{
char address[16];
char address[46];
} sfIpAddress;
////////////////////////////////////////////////////////////
/// \brief Type of an IP address
///
////////////////////////////////////////////////////////////
typedef enum
{
sfIpAddressV4, ///< IPv4 address
sfIpAddressV6 ///< IPv6 address
} sfIpAddressType;
////////////////////////////////////////////////////////////
/// \brief Empty object that represents invalid addresses
///
@@ -49,36 +66,85 @@ typedef struct
CSFML_NETWORK_API const sfIpAddress sfIpAddress_None;
////////////////////////////////////////////////////////////
/// \brief Value representing any address (0.0.0.0)
/// \brief The same as sfIpAddress_AnyV4
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_Any;
////////////////////////////////////////////////////////////
/// \brief Local host IP address (127.0.0.1, or "localhost")
/// \brief The same as sfIpAddress_LocalHostV4
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_LocalHost;
////////////////////////////////////////////////////////////
/// \brief UDP broadcast address (255.255.255.255)
/// \brief The same as sfIpAddress_BroadcastV4
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_Broadcast;
////////////////////////////////////////////////////////////
/// \brief Create an address from a string
/// \brief Value representing any IPv4 address (0.0.0.0)
///
/// Here \a address can be either a decimal address
/// (ex: "192.168.1.56") or a network name (ex: "localhost").
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_AnyV4;
////////////////////////////////////////////////////////////
/// \brief Local host IPv4 address (127.0.0.1)
///
/// \param address IP address or network name
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_LocalHostV4;
////////////////////////////////////////////////////////////
/// \brief UDP broadcast IPv4 address (255.255.255.255)
///
/// \return Resulting address
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_BroadcastV4;
////////////////////////////////////////////////////////////
/// \brief Value representing any IPv6 address (::)
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_AnyV6;
////////////////////////////////////////////////////////////
/// \brief Local host IPv6 address (::1)
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API const sfIpAddress sfIpAddress_LocalHostV6;
////////////////////////////////////////////////////////////
/// \brief Create an address from a string representation
///
/// Here \a address can be either an IPv4 address in
/// dotted-decimal notation (ex: "192.168.1.56") or an IPv6
/// address in standard notation (ex: "2606:4700:4700::1111").
/// Network names are not resolved, use sfDns_resolve or
/// sfIpAddress_resolve for that.
///
/// \param address IP address string
///
/// \return Resulting address or sfIpAddress_None if the string is not a valid address
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfIpAddress_fromString(const char* address);
////////////////////////////////////////////////////////////
/// \brief Create an IPv4 address from a string or by resolving a network name
///
/// Here \a address can be either a decimal address
/// (ex: "192.168.1.56") or a network name (ex: "localhost").
/// Only IPv4 addresses are returned.
///
/// \param address IP address or network name
///
/// \return Resulting address or sfIpAddress_None if the address could not be resolved
///
/// \deprecated Use sfDns_resolve instead
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API CSFML_DEPRECATED sfIpAddress sfIpAddress_resolve(const char* address);
////////////////////////////////////////////////////////////
/// \brief Create an address from 4 bytes
///
@@ -112,12 +178,24 @@ CSFML_NETWORK_API sfIpAddress sfIpAddress_fromBytes(uint8_t byte0, uint8_t byte1
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfIpAddress_fromInteger(uint32_t address);
////////////////////////////////////////////////////////////
/// \brief Create an IPv6 address from 16 bytes
///
/// \param bytes Array of 16 bytes containing the address
///
/// \return Resulting address
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfIpAddress_fromV6Bytes(const uint8_t bytes[16]);
////////////////////////////////////////////////////////////
/// \brief Get a string representation of an address
///
/// The returned string is the decimal representation of the
/// IP address (like "192.168.1.56"), even if it was constructed
/// from a host name.
/// IPv4 address (like "192.168.1.56") or the standard
/// representation of the IPv6 address (like "2606:4700:4700::1111"),
/// even if it was constructed from a host name.
/// The string must be able to hold at least 46 characters.
///
/// \param address Address object
/// \param string String where the string representation will be stored
@@ -134,6 +212,9 @@ CSFML_NETWORK_API void sfIpAddress_toString(sfIpAddress address, char* string);
/// The integer produced by this function can then be converted
/// back to a sfIpAddress with sfIpAddress_fromInteger.
///
/// Only IPv4 addresses can be converted to an integer, 0 is
/// returned for IPv6 addresses.
///
/// \param address Address object
///
/// \return 32-bits unsigned integer representation of the address
@@ -141,6 +222,50 @@ CSFML_NETWORK_API void sfIpAddress_toString(sfIpAddress address, char* string);
////////////////////////////////////////////////////////////
CSFML_NETWORK_API uint32_t sfIpAddress_toInteger(sfIpAddress address);
////////////////////////////////////////////////////////////
/// \brief Get a 16-byte representation of an IPv6 address
///
/// The bytes produced by this function can then be converted
/// back to a sfIpAddress with sfIpAddress_fromV6Bytes.
///
/// \param address Address object
/// \param bytes Array of 16 bytes that will be filled with the address
///
/// \return True if the address is a valid IPv6 address and the bytes have been written, false otherwise
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API bool sfIpAddress_toV6Bytes(sfIpAddress address, uint8_t bytes[16]);
////////////////////////////////////////////////////////////
/// \brief Get the type of an address
///
/// \param address Address object
///
/// \return The type of the address, sfIpAddressV4 is returned for invalid addresses
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddressType sfIpAddress_getType(sfIpAddress address);
////////////////////////////////////////////////////////////
/// \brief Check if an address is a valid IPv4 address
///
/// \param address Address object
///
/// \return True if the address is a valid IPv4 address
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API bool sfIpAddress_isV4(sfIpAddress address);
////////////////////////////////////////////////////////////
/// \brief Check if an address is a valid IPv6 address
///
/// \param address Address object
///
/// \return True if the address is a valid IPv6 address
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API bool sfIpAddress_isV6(sfIpAddress address);
////////////////////////////////////////////////////////////
/// \brief Get the computer's local address
///
@@ -150,11 +275,28 @@ CSFML_NETWORK_API uint32_t sfIpAddress_toInteger(sfIpAddress address);
/// Unlike sfIpAddress_getPublicAddress, this function is fast
/// and may be used safely anywhere.
///
/// This returns the local IPv4 address.
///
/// \return Local IP address of the computer
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfIpAddress_getLocalAddress(void);
////////////////////////////////////////////////////////////
/// \brief Get the computer's local address of a given type
///
/// The local address is the address of the computer from the
/// LAN point of view, i.e. something like 192.168.1.56 or
/// fe80::1234:5678:9abc. It is meaningful only for
/// communications over the local network.
///
/// \param type The type of local address to get
///
/// \return Local IP address of the computer or sfIpAddress_None if there is none
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfIpAddress_getLocalAddressOfType(sfIpAddressType type);
////////////////////////////////////////////////////////////
/// \brief Get the computer's public address
///
@@ -170,9 +312,31 @@ CSFML_NETWORK_API sfIpAddress sfIpAddress_getLocalAddress(void);
/// to be possibly stuck waiting in case there is a problem; use
/// 0 to deactivate this limit.
///
/// This returns the public IPv4 address.
///
/// \param timeout Maximum time to wait
///
/// \return Public IP address of the computer
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfIpAddress_getPublicAddress(sfTime timeout);
////////////////////////////////////////////////////////////
/// \brief Get the computer's public address of a given type
///
/// The public address is the address of the computer from the
/// internet point of view, i.e. something like 89.54.1.169 or
/// 2600:1901:0:13e0::1. See sfIpAddress_getPublicAddress for
/// details.
///
/// If tamper resistance is required, setting \a secure to true
/// will make use of verified HTTPS connections to get the address.
///
/// \param timeout Maximum time to wait, use 0 to deactivate the limit
/// \param type The type of public address to get, NULL to specify no preference
/// \param secure True to retrieve the public address via a secure HTTPS connection, false to retrieve via DNS or an insecure connection
///
/// \return Public IP address of the computer or sfIpAddress_None on failure
///
////////////////////////////////////////////////////////////
CSFML_NETWORK_API sfIpAddress sfIpAddress_getPublicAddressOfType(sfTime timeout, const sfIpAddressType* type, bool secure);
+4
View File
@@ -25,6 +25,10 @@
#pragma once
typedef struct sfDnsMxRecords sfDnsMxRecords;
typedef struct sfDnsNsRecords sfDnsNsRecords;
typedef struct sfDnsSrvRecords sfDnsSrvRecords;
typedef struct sfDnsTxtRecords sfDnsTxtRecords;
typedef struct sfFtpDirectoryResponse sfFtpDirectoryResponse;
typedef struct sfFtpListingResponse sfFtpListingResponse;
typedef struct sfFtpResponse sfFtpResponse;
+4
View File
@@ -3,6 +3,10 @@ set(SRCROOT ${PROJECT_SOURCE_DIR}/src/CSFML/Network)
# all source files
set(SRC
${SRCROOT}/ConvertIpAddress.hpp
${SRCROOT}/Dns.cpp
${SRCROOT}/DnsStruct.hpp
${INCROOT}/Dns.h
${INCROOT}/Export.h
${SRCROOT}/Ftp.cpp
${SRCROOT}/FtpStruct.hpp
+76
View File
@@ -0,0 +1,76 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2026 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/IpAddress.h>
#include <SFML/Network/IpAddress.hpp>
#include <cstring>
#include <optional>
////////////////////////////////////////////////////////////
// Convert sf::IpAddress to sfIpAddress
////////////////////////////////////////////////////////////
[[nodiscard]] inline sfIpAddress convertIpAddress(const sf::IpAddress& address)
{
sfIpAddress result{};
std::strncpy(result.address, address.toString().c_str(), sizeof(result.address) - 1);
return result;
}
////////////////////////////////////////////////////////////
// Convert std::optional<sf::IpAddress> to sfIpAddress
////////////////////////////////////////////////////////////
[[nodiscard]] inline sfIpAddress convertIpAddress(const std::optional<sf::IpAddress>& address)
{
return address ? convertIpAddress(*address) : sfIpAddress_None;
}
////////////////////////////////////////////////////////////
// Convert sfIpAddress to std::optional<sf::IpAddress>
////////////////////////////////////////////////////////////
[[nodiscard]] inline std::optional<sf::IpAddress> convertIpAddress(const sfIpAddress& address)
{
return sf::IpAddress::fromString(address.address);
}
////////////////////////////////////////////////////////////
// Convert an optional sfIpAddressType to std::optional<sf::IpAddress::Type>
////////////////////////////////////////////////////////////
[[nodiscard]] inline std::optional<sf::IpAddress::Type> convertIpAddressType(const sfIpAddressType* type)
{
if (!type)
return std::nullopt;
return static_cast<sf::IpAddress::Type>(*type);
}
+285
View File
@@ -0,0 +1,285 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2026 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/ConvertIpAddress.hpp>
#include <CSFML/Network/Dns.h>
#include <CSFML/Network/DnsStruct.hpp>
#include <SFML/Network/Dns.hpp>
#include <SFML/System/String.hpp>
#include <cassert>
#include <cstdlib>
#include <cstring>
namespace
{
////////////////////////////////////////////////////////////
[[nodiscard]] sf::String fromUtf8(const char* string)
{
return sf::String::fromUtf8(string, string + std::strlen(string));
}
////////////////////////////////////////////////////////////
[[nodiscard]] std::string toUtf8(const sf::String& string)
{
const auto utf8 = string.toUtf8();
return {utf8.begin(), utf8.end()};
}
////////////////////////////////////////////////////////////
[[nodiscard]] std::vector<sf::IpAddress> convertServers(const sfIpAddress* servers, size_t serverCount)
{
std::vector<sf::IpAddress> result;
if (!servers)
return result;
result.reserve(serverCount);
for (size_t i = 0; i < serverCount; ++i)
{
if (const auto address = convertIpAddress(servers[i]))
result.push_back(*address);
}
return result;
}
////////////////////////////////////////////////////////////
[[nodiscard]] std::optional<sf::Time> convertTimeout(sfTime timeout)
{
if (timeout.microseconds == 0)
return std::nullopt;
return sf::microseconds(timeout.microseconds);
}
} // namespace
////////////////////////////////////////////////////////////
sfIpAddress* sfDns_resolve(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout, size_t* count)
{
assert(hostname);
assert(count);
*count = 0;
const auto addresses = sf::Dns::resolve(fromUtf8(hostname), convertServers(servers, serverCount), convertTimeout(timeout));
if (!addresses || addresses->empty())
return nullptr;
auto* result = static_cast<sfIpAddress*>(std::malloc(addresses->size() * sizeof(sfIpAddress)));
if (!result)
return nullptr;
for (std::size_t i = 0; i < addresses->size(); ++i)
result[i] = convertIpAddress((*addresses)[i]);
*count = addresses->size();
return result;
}
////////////////////////////////////////////////////////////
sfDnsNsRecords* sfDns_queryNs(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout)
{
assert(hostname);
auto* records = new sfDnsNsRecords;
for (const auto& record :
sf::Dns::queryNs(fromUtf8(hostname), convertServers(servers, serverCount), convertTimeout(timeout)))
records->Records.push_back(toUtf8(record));
return records;
}
////////////////////////////////////////////////////////////
sfDnsMxRecords* sfDns_queryMx(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout)
{
assert(hostname);
auto* records = new sfDnsMxRecords;
for (const auto& record :
sf::Dns::queryMx(fromUtf8(hostname), convertServers(servers, serverCount), convertTimeout(timeout)))
records->Records.push_back({toUtf8(record.exchange), record.preference});
return records;
}
////////////////////////////////////////////////////////////
sfDnsSrvRecords* sfDns_querySrv(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout)
{
assert(hostname);
auto* records = new sfDnsSrvRecords;
for (const auto& record :
sf::Dns::querySrv(fromUtf8(hostname), convertServers(servers, serverCount), convertTimeout(timeout)))
records->Records.push_back({toUtf8(record.target), record.port, record.weight, record.priority});
return records;
}
////////////////////////////////////////////////////////////
sfDnsTxtRecords* sfDns_queryTxt(const char* hostname, const sfIpAddress* servers, size_t serverCount, sfTime timeout)
{
assert(hostname);
auto* records = new sfDnsTxtRecords;
for (const auto& record :
sf::Dns::queryTxt(fromUtf8(hostname), convertServers(servers, serverCount), convertTimeout(timeout)))
{
auto& strings = records->Records.emplace_back();
for (const auto& string : record)
strings.push_back(toUtf8(string));
}
return records;
}
////////////////////////////////////////////////////////////
sfIpAddress sfDns_getPublicAddress(sfTime timeout, sfIpAddressType type)
{
return convertIpAddress(sf::Dns::getPublicAddress(convertTimeout(timeout), static_cast<sf::IpAddress::Type>(type)));
}
////////////////////////////////////////////////////////////
void sfDnsNsRecords_destroy(const sfDnsNsRecords* records)
{
delete records;
}
////////////////////////////////////////////////////////////
size_t sfDnsNsRecords_getCount(const sfDnsNsRecords* records)
{
assert(records);
return records->Records.size();
}
////////////////////////////////////////////////////////////
const char* sfDnsNsRecords_getRecord(const sfDnsNsRecords* records, size_t index)
{
assert(records);
assert(index < records->Records.size());
return records->Records[index].c_str();
}
////////////////////////////////////////////////////////////
void sfDnsMxRecords_destroy(const sfDnsMxRecords* records)
{
delete records;
}
////////////////////////////////////////////////////////////
size_t sfDnsMxRecords_getCount(const sfDnsMxRecords* records)
{
assert(records);
return records->Records.size();
}
////////////////////////////////////////////////////////////
sfDnsMxRecord sfDnsMxRecords_getRecord(const sfDnsMxRecords* records, size_t index)
{
assert(records);
assert(index < records->Records.size());
const auto& record = records->Records[index];
return {record.exchange.c_str(), record.preference};
}
////////////////////////////////////////////////////////////
void sfDnsSrvRecords_destroy(const sfDnsSrvRecords* records)
{
delete records;
}
////////////////////////////////////////////////////////////
size_t sfDnsSrvRecords_getCount(const sfDnsSrvRecords* records)
{
assert(records);
return records->Records.size();
}
////////////////////////////////////////////////////////////
sfDnsSrvRecord sfDnsSrvRecords_getRecord(const sfDnsSrvRecords* records, size_t index)
{
assert(records);
assert(index < records->Records.size());
const auto& record = records->Records[index];
return {record.target.c_str(), record.port, record.weight, record.priority};
}
////////////////////////////////////////////////////////////
void sfDnsTxtRecords_destroy(const sfDnsTxtRecords* records)
{
delete records;
}
////////////////////////////////////////////////////////////
size_t sfDnsTxtRecords_getCount(const sfDnsTxtRecords* records)
{
assert(records);
return records->Records.size();
}
////////////////////////////////////////////////////////////
size_t sfDnsTxtRecords_getStringCount(const sfDnsTxtRecords* records, size_t index)
{
assert(records);
assert(index < records->Records.size());
return records->Records[index].size();
}
////////////////////////////////////////////////////////////
const char* sfDnsTxtRecords_getString(const sfDnsTxtRecords* records, size_t index, size_t stringIndex)
{
assert(records);
assert(index < records->Records.size());
assert(stringIndex < records->Records[index].size());
return records->Records[index][stringIndex].c_str();
}
+82
View File
@@ -0,0 +1,82 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2026 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <cstdint>
#include <string>
#include <vector>
////////////////////////////////////////////////////////////
// Internal structure of sfDnsNsRecords
////////////////////////////////////////////////////////////
struct sfDnsNsRecords
{
std::vector<std::string> Records;
};
////////////////////////////////////////////////////////////
// Internal structure of sfDnsMxRecords
////////////////////////////////////////////////////////////
struct sfDnsMxRecords
{
struct Record
{
std::string exchange;
std::uint16_t preference{};
};
std::vector<Record> Records;
};
////////////////////////////////////////////////////////////
// Internal structure of sfDnsSrvRecords
////////////////////////////////////////////////////////////
struct sfDnsSrvRecords
{
struct Record
{
std::string target;
std::uint16_t port{};
std::uint16_t weight{};
std::uint16_t priority{};
};
std::vector<Record> Records;
};
////////////////////////////////////////////////////////////
// Internal structure of sfDnsTxtRecords
////////////////////////////////////////////////////////////
struct sfDnsTxtRecords
{
std::vector<std::vector<std::string>> Records;
};
+2 -1
View File
@@ -25,6 +25,7 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/ConvertIpAddress.hpp>
#include <CSFML/Network/Ftp.h>
#include <CSFML/Network/FtpStruct.hpp>
@@ -205,7 +206,7 @@ sfFtpResponse* sfFtp_connect(sfFtp* ftp, sfIpAddress server, unsigned short port
{
assert(ftp);
std::optional<sf::IpAddress> sfmlServer = sf::IpAddress::resolve(server.address);
std::optional<sf::IpAddress> sfmlServer = convertIpAddress(server);
if (!sfmlServer)
return nullptr;
+106 -25
View File
@@ -25,63 +25,90 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/ConvertIpAddress.hpp>
#include <CSFML/Network/IpAddress.h>
#include <SFML/Network/IpAddress.hpp>
#include <algorithm>
#include <array>
#include <cstring>
namespace
{
// Helper function for converting a SFML address to a CSFML one
[[nodiscard]] sfIpAddress fromSFMLAddress(std::optional<sf::IpAddress> address)
{
if (!address)
return sfIpAddress_None;
sfIpAddress result{};
std::strncpy(result.address, address->toString().c_str(), 15);
return result;
}
} // namespace
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_None = {{0}};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_Any = sfIpAddress_fromBytes(0, 0, 0, 0);
const sfIpAddress sfIpAddress_Any = {"0.0.0.0"};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_LocalHost = sfIpAddress_fromBytes(127, 0, 0, 1);
const sfIpAddress sfIpAddress_LocalHost = {"127.0.0.1"};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_Broadcast = sfIpAddress_fromBytes(255, 255, 255, 255);
const sfIpAddress sfIpAddress_Broadcast = {"255.255.255.255"};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_AnyV4 = {"0.0.0.0"};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_LocalHostV4 = {"127.0.0.1"};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_BroadcastV4 = {"255.255.255.255"};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_AnyV6 = {"::"};
////////////////////////////////////////////////////////////
const sfIpAddress sfIpAddress_LocalHostV6 = {"::1"};
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_fromString(const char* address)
{
assert(address);
return fromSFMLAddress(sf::IpAddress::resolve(address));
return convertIpAddress(sf::IpAddress::fromString(address));
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_resolve(const char* address)
{
assert(address);
return convertIpAddress(sf::IpAddress::resolve(address));
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_fromBytes(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3)
{
return fromSFMLAddress(sf::IpAddress(byte0, byte1, byte2, byte3));
return convertIpAddress(sf::IpAddress(byte0, byte1, byte2, byte3));
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_fromInteger(uint32_t address)
{
return fromSFMLAddress(sf::IpAddress(address));
return convertIpAddress(sf::IpAddress(address));
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_fromV6Bytes(const uint8_t bytes[16])
{
assert(bytes);
std::array<std::uint8_t, 16> array{};
std::copy(bytes, bytes + array.size(), array.begin());
return convertIpAddress(sf::IpAddress(array));
}
@@ -96,20 +123,74 @@ void sfIpAddress_toString(sfIpAddress address, char* string)
////////////////////////////////////////////////////////////
uint32_t sfIpAddress_toInteger(sfIpAddress address)
{
const auto sfmlAddress = sf::IpAddress::resolve(address.address);
return sfmlAddress ? sfmlAddress->toInteger() : 0;
const auto sfmlAddress = convertIpAddress(address);
return sfmlAddress && sfmlAddress->isV4() ? sfmlAddress->toInteger() : 0;
}
////////////////////////////////////////////////////////////
bool sfIpAddress_toV6Bytes(sfIpAddress address, uint8_t bytes[16])
{
assert(bytes);
const auto sfmlAddress = convertIpAddress(address);
if (!sfmlAddress || !sfmlAddress->isV6())
return false;
const auto array = sfmlAddress->toBytes();
std::copy(array.begin(), array.end(), bytes);
return true;
}
////////////////////////////////////////////////////////////
sfIpAddressType sfIpAddress_getType(sfIpAddress address)
{
const auto sfmlAddress = convertIpAddress(address);
return sfmlAddress ? static_cast<sfIpAddressType>(sfmlAddress->getType()) : sfIpAddressV4;
}
////////////////////////////////////////////////////////////
bool sfIpAddress_isV4(sfIpAddress address)
{
const auto sfmlAddress = convertIpAddress(address);
return sfmlAddress && sfmlAddress->isV4();
}
////////////////////////////////////////////////////////////
bool sfIpAddress_isV6(sfIpAddress address)
{
const auto sfmlAddress = convertIpAddress(address);
return sfmlAddress && sfmlAddress->isV6();
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_getLocalAddress()
{
return fromSFMLAddress(sf::IpAddress::getLocalAddress());
return convertIpAddress(sf::IpAddress::getLocalAddress());
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_getLocalAddressOfType(sfIpAddressType type)
{
return convertIpAddress(sf::IpAddress::getLocalAddress(static_cast<sf::IpAddress::Type>(type)));
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_getPublicAddress(sfTime timeout)
{
return fromSFMLAddress(sf::IpAddress::getPublicAddress(sf::microseconds(timeout.microseconds)));
return convertIpAddress(sf::IpAddress::getPublicAddress(sf::microseconds(timeout.microseconds)));
}
////////////////////////////////////////////////////////////
sfIpAddress sfIpAddress_getPublicAddressOfType(sfTime timeout, const sfIpAddressType* type, bool secure)
{
return convertIpAddress(
sf::IpAddress::getPublicAddress(sf::microseconds(timeout.microseconds), convertIpAddressType(type), secure));
}
+2 -1
View File
@@ -25,6 +25,7 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/ConvertIpAddress.hpp>
#include <CSFML/Network/TcpListener.h>
#include <CSFML/Network/TcpListenerStruct.hpp>
#include <CSFML/Network/TcpSocketStruct.hpp>
@@ -75,7 +76,7 @@ sfSocketStatus sfTcpListener_listen(sfTcpListener* listener, unsigned short port
{
assert(listener);
std::optional<sf::IpAddress> sfmlAddress = sf::IpAddress::resolve(address.address);
std::optional<sf::IpAddress> sfmlAddress = convertIpAddress(address);
if (!sfmlAddress)
{
+3 -2
View File
@@ -25,6 +25,7 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/ConvertIpAddress.hpp>
#include <CSFML/Network/PacketStruct.hpp>
#include <CSFML/Network/TcpSocket.h>
#include <CSFML/Network/TcpSocketStruct.hpp>
@@ -82,7 +83,7 @@ sfIpAddress sfTcpSocket_getRemoteAddress(const sfTcpSocket* socket)
sfIpAddress result = sfIpAddress_None;
if (address)
{
std::strncpy(result.address, address->toString().c_str(), 15);
result = convertIpAddress(*address);
}
return result;
@@ -100,7 +101,7 @@ unsigned short sfTcpSocket_getRemotePort(const sfTcpSocket* socket)
////////////////////////////////////////////////////////////
sfSocketStatus sfTcpSocket_connect(sfTcpSocket* socket, sfIpAddress remoteAddress, unsigned short remotePort, sfTime timeout)
{
std::optional<sf::IpAddress> address = sf::IpAddress::resolve(remoteAddress.address);
std::optional<sf::IpAddress> address = convertIpAddress(remoteAddress);
if (!address)
{
+6 -5
View File
@@ -25,6 +25,7 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <CSFML/Network/ConvertIpAddress.hpp>
#include <CSFML/Network/PacketStruct.hpp>
#include <CSFML/Network/UdpSocket.h>
#include <CSFML/Network/UdpSocketStruct.hpp>
@@ -76,7 +77,7 @@ sfSocketStatus sfUdpSocket_bind(sfUdpSocket* socket, unsigned short port, sfIpAd
{
assert(socket);
std::optional<sf::IpAddress> sfmlAddress = sf::IpAddress::resolve(address.address);
std::optional<sf::IpAddress> sfmlAddress = convertIpAddress(address);
if (!sfmlAddress)
{
@@ -101,7 +102,7 @@ sfSocketStatus sfUdpSocket_send(sfUdpSocket* socket, const void* data, size_t si
assert(socket);
// Convert the address
std::optional<sf::IpAddress> address = sf::IpAddress::resolve(remoteAddress.address);
std::optional<sf::IpAddress> address = convertIpAddress(remoteAddress);
if (!address)
{
@@ -139,7 +140,7 @@ sfSocketStatus sfUdpSocket_receive(sfUdpSocket* socket,
if (address)
{
std::strncpy(remoteAddress->address, address->toString().c_str(), 15);
*remoteAddress = convertIpAddress(*address);
}
}
@@ -157,7 +158,7 @@ sfSocketStatus sfUdpSocket_sendPacket(sfUdpSocket* socket, sfPacket* packet, sfI
assert(packet);
// Convert the address
std::optional<sf::IpAddress> address = sf::IpAddress::resolve(remoteAddress.address);
std::optional<sf::IpAddress> address = convertIpAddress(remoteAddress);
if (!address)
{
@@ -187,7 +188,7 @@ sfSocketStatus sfUdpSocket_receivePacket(sfUdpSocket* socket, sfPacket* packet,
if (address)
{
std::strncpy(remoteAddress->address, address->toString().c_str(), 15);
*remoteAddress = convertIpAddress(*address);
}
}
+2 -1
View File
@@ -66,12 +66,13 @@ set_target_warnings(test-csfml-graphics)
catch_discover_tests(test-csfml-graphics WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_executable(test-csfml-network
Network/Dns.test.cpp
Network/Ftp.test.cpp
Network/Http.test.cpp
Network/IpAddress.test.cpp
Network/SocketStatus.test.cpp
)
target_link_libraries(test-csfml-network PRIVATE csfml-network Catch2::Catch2WithMain SFML::Network)
target_link_libraries(test-csfml-network PRIVATE csfml-network csfml-system Catch2::Catch2WithMain SFML::Network)
set_target_warnings(test-csfml-network)
catch_discover_tests(test-csfml-network)
+25
View File
@@ -0,0 +1,25 @@
#include <CSFML/Network/Dns.h>
#include <CSFML/System/Alloc.h>
#include <catch2/catch_test_macros.hpp>
#include <cstring>
TEST_CASE("[Network] sfDns")
{
SECTION("sfDns_resolve")
{
size_t count = 0;
sfIpAddress* addresses = sfDns_resolve("127.0.0.1", nullptr, 0, sfSeconds(1), &count);
REQUIRE(addresses != nullptr);
REQUIRE(count == 1);
CHECK(std::strcmp(addresses[0].address, "127.0.0.1") == 0);
sfFree(addresses);
addresses = sfDns_resolve("::1", nullptr, 0, sfSeconds(1), &count);
REQUIRE(addresses != nullptr);
REQUIRE(count == 1);
CHECK(std::strcmp(addresses[0].address, "::1") == 0);
sfFree(addresses);
}
}
+50 -1
View File
@@ -1,5 +1,7 @@
#include <CSFML/Network/IpAddress.h>
#include <SFML/Network/IpAddress.hpp>
#include <catch2/catch_test_macros.hpp>
#include <cstring>
@@ -17,15 +19,62 @@ TEST_CASE("[Network] sfIpAddress")
CHECK(std::strcmp(sfIpAddress_Any.address, "0.0.0.0") == 0);
CHECK(std::strcmp(sfIpAddress_LocalHost.address, "127.0.0.1") == 0);
CHECK(std::strcmp(sfIpAddress_Broadcast.address, "255.255.255.255") == 0);
CHECK(std::strcmp(sfIpAddress_AnyV4.address, "0.0.0.0") == 0);
CHECK(std::strcmp(sfIpAddress_LocalHostV4.address, "127.0.0.1") == 0);
CHECK(std::strcmp(sfIpAddress_BroadcastV4.address, "255.255.255.255") == 0);
CHECK(std::strcmp(sfIpAddress_AnyV6.address, "::") == 0);
CHECK(std::strcmp(sfIpAddress_LocalHostV6.address, "::1") == 0);
}
SECTION("sfIpAddressType")
{
STATIC_CHECK(sfIpAddressV4 == static_cast<int>(sf::IpAddress::Type::IpV4));
STATIC_CHECK(sfIpAddressV6 == static_cast<int>(sf::IpAddress::Type::IpV6));
}
SECTION("sfIpAddress_fromString")
{
CHECK(sfIpAddress_toInteger(sfIpAddress_fromString("")) == 0);
CHECK(sfIpAddress_toInteger(sfIpAddress_fromString("256.256.256.256")) == 0);
CHECK(sfIpAddress_toInteger(sfIpAddress_fromString("localhost")) == 0x7F000001);
CHECK(sfIpAddress_toInteger(sfIpAddress_fromString("localhost")) == 0);
CHECK(sfIpAddress_toInteger(sfIpAddress_fromString("192.168.0.1")) == 0xC0A80001);
CHECK(sfIpAddress_toInteger(sfIpAddress_fromString("8.8.8.8")) == 0x08080808);
CHECK(std::strcmp(sfIpAddress_fromString("2606:4700:4700::1111").address, "2606:4700:4700::1111") == 0);
CHECK(std::strcmp(sfIpAddress_fromString("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff").address,
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") == 0);
}
SECTION("sfIpAddress_resolve")
{
CHECK(sfIpAddress_toInteger(sfIpAddress_resolve("")) == 0);
CHECK(sfIpAddress_toInteger(sfIpAddress_resolve("localhost")) == 0x7F000001);
CHECK(sfIpAddress_toInteger(sfIpAddress_resolve("192.168.0.1")) == 0xC0A80001);
}
SECTION("Type")
{
CHECK(sfIpAddress_isV4(sfIpAddress_LocalHostV4));
CHECK(!sfIpAddress_isV6(sfIpAddress_LocalHostV4));
CHECK(sfIpAddress_getType(sfIpAddress_LocalHostV4) == sfIpAddressV4);
CHECK(!sfIpAddress_isV4(sfIpAddress_LocalHostV6));
CHECK(sfIpAddress_isV6(sfIpAddress_LocalHostV6));
CHECK(sfIpAddress_getType(sfIpAddress_LocalHostV6) == sfIpAddressV6);
CHECK(!sfIpAddress_isV4(sfIpAddress_None));
CHECK(!sfIpAddress_isV6(sfIpAddress_None));
}
SECTION("sfIpAddress_fromV6Bytes")
{
const uint8_t bytes[16] = {0x26, 0x06, 0x47, 0x00, 0x47, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0x11, 0x11};
const sfIpAddress address = sfIpAddress_fromV6Bytes(bytes);
CHECK(std::strcmp(address.address, "2606:4700:4700::1111") == 0);
CHECK(sfIpAddress_toInteger(address) == 0);
uint8_t result[16] = {};
CHECK(sfIpAddress_toV6Bytes(address, result));
CHECK(std::memcmp(bytes, result, sizeof(bytes)) == 0);
CHECK(!sfIpAddress_toV6Bytes(sfIpAddress_LocalHostV4, result));
}
SECTION("sfIpAddress_fromBytes")