Skip to content

Commit 047da4f

Browse files
binary1248eXpl0it3r
authored andcommitted
Added support for IPv6 and more types of DNS queries.
1 parent 107f0cd commit 047da4f

33 files changed

+3430
-428
lines changed

.github/workflows/analyze.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- { name: Linux OpenGL ES, os: ubuntu-24.04, flags: -DSFML_OPENGL_ES=ON }
2929
- { name: macOS, os: macos-14 }
3030
- { name: iOS, os: macos-14, flags: -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_ARCHITECTURES=arm64 }
31-
- { name: Android, os: ubuntu-24.04, flags: -DCMAKE_ANDROID_ARCH_ABI=x86_64 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=21 -DCMAKE_ANDROID_NDK=$ANDROID_NDK -DCMAKE_ANDROID_STL_TYPE=c++_shared }
31+
- { name: Android, os: ubuntu-24.04, flags: -DCMAKE_ANDROID_ARCH_ABI=x86_64 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=22 -DCMAKE_ANDROID_NDK=$ANDROID_NDK -DCMAKE_ANDROID_STL_TYPE=c++_shared }
3232

3333
steps:
3434
- name: Checkout Code
@@ -59,7 +59,7 @@ jobs:
5959
echo "$(brew --prefix llvm@18)/bin" >> $GITHUB_PATH
6060
6161
- name: Configure
62-
run: cmake --preset dev ${{ matrix.platform.name != 'Android' && '-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++' || ''}} -DCMAKE_UNITY_BUILD=ON ${{matrix.platform.flags}}
62+
run: cmake --preset dev ${{ matrix.platform.name != 'Android' && '-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++' || ''}} -DCMAKE_UNITY_BUILD=ON -DSFML_RUN_IPV4_LINK_TESTS=ON -DSFML_RUN_IPV4_INTERNET_TESTS=ON -DSFML_RUN_IPV6_LINK_TESTS=ON ${{matrix.platform.flags}}
6363

6464
- name: Analyze Code
6565
run: cmake --build build --target tidy
@@ -92,7 +92,7 @@ jobs:
9292
sudo apt-get install xorg-dev libharfbuzz-dev libxrandr-dev libxcursor-dev libxi-dev libudev-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev libmbedtls-dev xvfb fluxbox
9393
9494
- name: Configure
95-
run: cmake --preset dev -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSFML_BUILD_EXAMPLES=OFF -DSFML_ENABLE_SANITIZERS=ON ${{matrix.platform.flags}}
95+
run: cmake --preset dev -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DSFML_BUILD_EXAMPLES=OFF -DSFML_ENABLE_SANITIZERS=ON -DSFML_RUN_IPV4_LINK_TESTS=ON -DSFML_RUN_IPV4_INTERNET_TESTS=ON -DSFML_RUN_IPV6_LINK_TESTS=ON ${{matrix.platform.flags}}
9696

9797
- name: Build
9898
run: cmake --build build

.github/workflows/build.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ jobs:
7171
config: { name: System Deps, flags: -GNinja -DBUILD_SHARED_LIBS=ON -DSFML_USE_SYSTEM_DEPS=ON }
7272
- platform: { name: Android, os: ubuntu-24.04 }
7373
config:
74-
name: x86 (API 21)
75-
flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=x86 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=21 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=ON -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF
74+
name: x86 (API 22)
75+
flags: -GNinja -DCMAKE_ANDROID_ARCH_ABI=x86 -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=22 -DCMAKE_ANDROID_NDK=$ANDROID_NDK_ROOT -DBUILD_SHARED_LIBS=ON -DCMAKE_ANDROID_STL_TYPE=c++_shared -DSFML_RUN_DISPLAY_TESTS=OFF -DSFML_RUN_AUDIO_DEVICE_TESTS=OFF
7676
arch: x86
77-
api: 21
77+
api: 22
7878
type: { name: Release }
7979
- platform: { name: Android, os: ubuntu-24.04 }
8080
config:
@@ -193,7 +193,7 @@ jobs:
193193
cmake --version
194194
195195
- name: Configure CMake
196-
run: cmake --preset dev -DCMAKE_VERBOSE_MAKEFILE=ON ${{matrix.platform.flags}} ${{matrix.config.flags}} ${{matrix.type.flags}}
196+
run: cmake --preset dev -DCMAKE_VERBOSE_MAKEFILE=ON -DSFML_RUN_IPV4_LINK_TESTS=ON -DSFML_RUN_IPV4_INTERNET_TESTS=ON -DSFML_RUN_IPV6_LINK_TESTS=ON ${{matrix.platform.flags}} ${{matrix.config.flags}} ${{matrix.type.flags}}
197197

198198
- name: Build
199199
run: cmake --build build --config ${{ matrix.type.name == 'Debug' && 'Debug' || 'Release' }} --target install

examples/sockets/TCP.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ void runTcpClient(unsigned short port, bool tls)
113113
do
114114
{
115115
std::cout << "Type the address or name of the server to connect to: ";
116-
std::cin >> server;
116+
std::string hostname;
117+
std::cin >> hostname;
118+
if (const auto addresses = sf::Dns::resolve(hostname); addresses.has_value() && !addresses->empty())
119+
server = addresses->front();
117120
} while (!server.has_value());
118121

119122
// Create a socket for communicating with the server

examples/sockets/UDP.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ void runUdpClient(unsigned short port)
5555
do
5656
{
5757
std::cout << "Type the address or name of the server to connect to: ";
58-
std::cin >> server;
58+
std::string hostname;
59+
std::cin >> hostname;
60+
if (const auto addresses = sf::Dns::resolve(hostname); addresses.has_value() && !addresses->empty())
61+
server = addresses->front();
5962
} while (!server.has_value());
6063

6164
// Create a socket for communicating with the server

examples/voip/Client.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ void doClient(unsigned short port)
126126
do
127127
{
128128
std::cout << "Type address or name of the server to connect to: ";
129-
std::cin >> server;
129+
std::string hostname;
130+
std::cin >> hostname;
131+
if (const auto addresses = sf::Dns::resolve(hostname); addresses.has_value() && !addresses->empty())
132+
server = addresses->front();
130133
} while (!server.has_value());
131134

132135
// Create an instance of our custom recorder

include/SFML/Network.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
// Headers
2929
////////////////////////////////////////////////////////////
3030

31+
#include <SFML/Network/Dns.hpp>
3132
#include <SFML/Network/Ftp.hpp>
3233
#include <SFML/Network/Http.hpp>
3334
#include <SFML/Network/IpAddress.hpp>

include/SFML/Network/Dns.hpp

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
////////////////////////////////////////////////////////////
2+
//
3+
// SFML - Simple and Fast Multimedia Library
4+
// Copyright (C) 2007-2025 Laurent Gomila ([email protected])
5+
//
6+
// This software is provided 'as-is', without any express or implied warranty.
7+
// In no event will the authors be held liable for any damages arising from the use of this software.
8+
//
9+
// Permission is granted to anyone to use this software for any purpose,
10+
// including commercial applications, and to alter it and redistribute it freely,
11+
// subject to the following restrictions:
12+
//
13+
// 1. The origin of this software must not be misrepresented;
14+
// you must not claim that you wrote the original software.
15+
// If you use this software in a product, an acknowledgment
16+
// in the product documentation would be appreciated but is not required.
17+
//
18+
// 2. Altered source versions must be plainly marked as such,
19+
// and must not be misrepresented as being the original software.
20+
//
21+
// 3. This notice may not be removed or altered from any source distribution.
22+
//
23+
////////////////////////////////////////////////////////////
24+
25+
#pragma once
26+
27+
////////////////////////////////////////////////////////////
28+
// Headers
29+
////////////////////////////////////////////////////////////
30+
#include <SFML/Network/Export.hpp>
31+
32+
#include <SFML/Network/IpAddress.hpp>
33+
34+
#include <SFML/System/String.hpp>
35+
#include <SFML/System/Time.hpp>
36+
37+
#include <optional>
38+
#include <vector>
39+
40+
#include <cstdint>
41+
42+
43+
////////////////////////////////////////////////////////////
44+
/// \brief Perform Domain Name System queries to lookup
45+
/// DNS records for various purposes
46+
///
47+
////////////////////////////////////////////////////////////
48+
namespace sf::Dns
49+
{
50+
////////////////////////////////////////////////////////////
51+
/// \brief Resolve a hostname into a list of IP addresses
52+
///
53+
/// \param hostname Hostname to resolve
54+
/// \param servers The list of servers to query, if empty use the default servers
55+
/// \param timeout Query timeout if using a provided list of servers, `std::nullopt` to wait forever
56+
///
57+
/// \return List of IP addresses the given hostname resolves to, `std::nullopt` is returned if name resolution fails, an empty list is returned if the hostname could not be resolved to any address
58+
///
59+
////////////////////////////////////////////////////////////
60+
[[nodiscard]] SFML_NETWORK_API std::optional<std::vector<IpAddress>> resolve(
61+
const sf::String& hostname,
62+
const std::vector<sf::IpAddress>& servers = {},
63+
std::optional<sf::Time> timeout = sf::seconds(1));
64+
65+
////////////////////////////////////////////////////////////
66+
/// \brief Query NS records for a hostname
67+
///
68+
/// \param hostname Hostname to query NS records for
69+
/// \param servers The list of servers to query, if empty use the default servers
70+
/// \param timeout Query timeout if using a provided list of servers, `std::nullopt` to wait forever
71+
///
72+
/// \return List of NS record strings, an empty list is returned if there are no NS records for the hostname
73+
///
74+
////////////////////////////////////////////////////////////
75+
[[nodiscard]] SFML_NETWORK_API std::vector<sf::String> queryNs(const sf::String& hostname,
76+
const std::vector<sf::IpAddress>& servers = {},
77+
std::optional<sf::Time> timeout = sf::seconds(1));
78+
79+
////////////////////////////////////////////////////////////
80+
/// \brief A DNS MX record
81+
///
82+
////////////////////////////////////////////////////////////
83+
struct MxRecord
84+
{
85+
sf::String exchange; //!< Host willing to act as mail exchange
86+
std::uint16_t preference{}; //!< Preference of this record among others, lower values are preferred
87+
};
88+
89+
////////////////////////////////////////////////////////////
90+
/// \brief Query MX records for a hostname
91+
///
92+
/// \param hostname Hostname to query MX records for
93+
/// \param servers The list of servers to query, if empty use the default servers
94+
/// \param timeout Query timeout if using a provided list of servers, `std::nullopt` to wait forever
95+
///
96+
/// \return List of MX records, an empty list is returned if there are no MX records for the hostname
97+
///
98+
////////////////////////////////////////////////////////////
99+
[[nodiscard]] SFML_NETWORK_API std::vector<MxRecord> queryMx(const sf::String& hostname,
100+
const std::vector<sf::IpAddress>& servers = {},
101+
std::optional<sf::Time> timeout = sf::seconds(1));
102+
103+
////////////////////////////////////////////////////////////
104+
/// \brief A DNS SRV record
105+
///
106+
////////////////////////////////////////////////////////////
107+
struct SrvRecord
108+
{
109+
sf::String target; //!< The domain name of the target host
110+
std::uint16_t port{}; //!< The port on the target host of the service
111+
std::uint16_t weight{}; //!< Server selection mechanism, larger weights should be given a proportionately higher probability of being selected
112+
std::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
113+
};
114+
115+
////////////////////////////////////////////////////////////
116+
/// \brief Query SRV records for a hostname
117+
///
118+
/// \param hostname Hostname to query SRV records for
119+
/// \param servers The list of servers to query, if empty use the default servers
120+
/// \param timeout Query timeout if using a provided list of servers, `std::nullopt` to wait forever
121+
///
122+
/// \return List of SRV records, an empty list is returned if there are no SRV records for the hostname
123+
///
124+
////////////////////////////////////////////////////////////
125+
[[nodiscard]] SFML_NETWORK_API std::vector<SrvRecord> querySrv(const sf::String& hostname,
126+
const std::vector<sf::IpAddress>& servers = {},
127+
std::optional<sf::Time> timeout = sf::seconds(1));
128+
129+
////////////////////////////////////////////////////////////
130+
/// \brief Query TXT records for a hostname
131+
///
132+
/// \param hostname Hostname to query TXT records for
133+
/// \param servers The list of servers to query, if empty use the default servers
134+
/// \param timeout Query timeout if using a provided list of servers, `std::nullopt` to wait forever
135+
///
136+
/// \return List of TXT record string lists, an empty list is returned if there are no TXT records for the hostname
137+
///
138+
////////////////////////////////////////////////////////////
139+
[[nodiscard]] SFML_NETWORK_API std::vector<std::vector<sf::String>> queryTxt(
140+
const sf::String& hostname,
141+
const std::vector<sf::IpAddress>& servers = {},
142+
std::optional<sf::Time> timeout = sf::seconds(1));
143+
144+
////////////////////////////////////////////////////////////
145+
/// \brief Get the computer's public address via DNS
146+
///
147+
/// The public address is the address of the computer from the
148+
/// point of view of the internet, i.e. something like 89.54.1.169
149+
/// or 2600:1901:0:13e0::1 as opposed to a private or local address
150+
/// like 192.168.1.56 or fe80::1234:5678:9abc.
151+
/// It is necessary for communication with hosts outside of the
152+
/// local network.
153+
///
154+
/// The only way to reliably get the public address is to send
155+
/// data to a host on the internet and see what the origin
156+
/// address is; as a consequence, this function depends on both
157+
/// your network connection and the server, and may be very slow.
158+
/// You should try to use it as little as possible. Because this
159+
/// function depends on the network connection and on a distant
160+
/// server, you can specify a time limit if you don't want your
161+
/// program to get stuck waiting in case there is a problem; this
162+
/// limit is deactivated by default.
163+
///
164+
/// This function makes use of DNS queries get the public address.
165+
///
166+
/// \param timeout Maximum time to wait, `std::nullopt` to wait forever
167+
/// \param type The type of public address to get
168+
///
169+
/// \return Public IP address of the computer on success, `std::nullopt` otherwise
170+
///
171+
////////////////////////////////////////////////////////////
172+
[[nodiscard]] SFML_NETWORK_API std::optional<IpAddress> getPublicAddress(std::optional<Time> timeout = std::nullopt,
173+
IpAddress::Type type = IpAddress::Type::IpV4);
174+
} // namespace sf::Dns
175+
176+
177+
////////////////////////////////////////////////////////////
178+
/// \namespace sf::Dns
179+
/// \ingroup network
180+
///
181+
/// The `sf::Dns` functions allow querying the Domain Name System.
182+
/// The Domain Name System contains many different kinds of
183+
/// records. The most common records are A and AAAA records
184+
/// used to resolve hostnames to IPv4 and IPv6 addresses
185+
/// respectively. Additionally, other kinds of records such
186+
/// as MX, SRV and TXT records can be queried.
187+
///
188+
/// Usage example:
189+
/// \code
190+
/// std::vector<sf::IpAddress> addresses0 = sf::Dns::resolve("127.0.0.1"); // the local host address
191+
/// std::vector<sf::IpAddress> addresses1 = sf::Dns::resolve("my_computer"); // a list of local addresses created from a network name
192+
/// std::vector<sf::IpAddress> addresses2 = sf::Dns::resolve("89.54.1.169"); // a distant IPv4 address
193+
/// std::vector<sf::IpAddress> addresses3 = sf::Dns::resolve("2606:4700:4700::1111"); // a distant IPv6 address
194+
/// std::vector<sf::IpAddress> addresses4 = sf::Dns::resolve("www.google.com"); // a list of distant address created from a network name
195+
///
196+
/// for (const sf::IpAddress& address : addresses4)
197+
/// {
198+
/// if (address.isV4())
199+
/// {
200+
/// // Do something with IPv4 address
201+
/// }
202+
/// else
203+
/// {
204+
/// // Do something with IPv6 address
205+
/// }
206+
/// }
207+
///
208+
/// std::vector<sf::String> nsRecords = sf::Dns::queryNs("sfml-dev.org");
209+
/// std::vector<sf::Dns::MxRecord> mxRecords = sf::Dns::queryMx("sfml-dev.org");
210+
/// std::vector<std::vector<sf::String>> txtRecords = sf::Dns::queryTxt("sfml-dev.org");
211+
/// std::vector<sf::Dns::SrvRecord> srvRecords = sf::Dns::querySrv("_irc._tcp.sfml-dev.org");
212+
/// \endcode
213+
///
214+
////////////////////////////////////////////////////////////

include/SFML/Network/Http.hpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <map>
3939
#include <optional>
4040
#include <string>
41+
#include <vector>
4142

4243

4344
namespace sf
@@ -351,11 +352,12 @@ class SFML_NETWORK_API Http
351352
/// this unless you really need a port other than the
352353
/// standard one, or use an unknown protocol.
353354
///
354-
/// \param host Web server to connect to
355-
/// \param port Port to use for connection
355+
/// \param host Web server to connect to
356+
/// \param port Port to use for the connection
357+
/// \param addressType Address type to use for the connection, `std::nullopt` to specify no preference
356358
///
357359
////////////////////////////////////////////////////////////
358-
Http(const std::string& host, unsigned short port = 0);
360+
Http(const std::string& host, unsigned short port = 0, std::optional<IpAddress::Type> addressType = std::nullopt);
359361

360362
////////////////////////////////////////////////////////////
361363
/// \brief Deleted copy constructor
@@ -381,13 +383,14 @@ class SFML_NETWORK_API Http
381383
/// this unless you really need a port other than the
382384
/// standard one, or use an unknown protocol.
383385
///
384-
/// \param host Web server to connect to
385-
/// \param port Port to use for connection
386+
/// \param host Web server to connect to
387+
/// \param port Port to use for the connection
388+
/// \param addressType Address type to use for the connection, `std::nullopt` to specify no preference
386389
///
387390
/// \return `true` if the host has been resolved and is valid, `false` otherwise
388391
///
389392
////////////////////////////////////////////////////////////
390-
bool setHost(const std::string& host, unsigned short port = 0);
393+
bool setHost(const std::string& host, unsigned short port = 0, std::optional<IpAddress::Type> addressType = std::nullopt);
391394

392395
////////////////////////////////////////////////////////////
393396
/// \brief Send a HTTP request and return the server's response.
@@ -414,10 +417,11 @@ class SFML_NETWORK_API Http
414417
////////////////////////////////////////////////////////////
415418
// Member data
416419
////////////////////////////////////////////////////////////
417-
std::optional<IpAddress> m_host; //!< Web host address
418-
std::string m_hostName; //!< Web host name
419-
unsigned short m_port{}; //!< Port used for connection with host
420-
bool m_https{}; //!< Use HTTPS
420+
std::vector<IpAddress> m_hosts; //!< Web host addresses
421+
std::optional<IpAddress::Type> m_addressType; //!< Address type
422+
std::string m_hostName; //!< Web host name
423+
unsigned short m_port{}; //!< Port used for connection with host
424+
bool m_https{}; //!< Use HTTPS
421425
};
422426

423427
} // namespace sf

0 commit comments

Comments
 (0)