IpAddress is always valid

This commit is contained in:
Vittorio Romeo 2022-06-27 12:02:35 +02:00
parent fd3526f742
commit 8c8d97c6c9
16 changed files with 150 additions and 235 deletions

View File

@ -5,6 +5,7 @@
#include <SFML/Network.hpp>
#include <fstream>
#include <iostream>
#include <optional>
////////////////////////////////////////////////////////////
@ -26,17 +27,17 @@ std::ostream& operator <<(std::ostream& stream, const sf::Ftp::Response& respons
int main()
{
// Choose the server address
sf::IpAddress address;
std::optional<sf::IpAddress> address;
do
{
std::cout << "Enter the FTP server address: ";
std::cin >> address;
}
while (address == sf::IpAddress::None);
while (!address.has_value());
// Connect to the server
sf::Ftp server;
sf::Ftp::Response connectResponse = server.connect(address);
sf::Ftp::Response connectResponse = server.connect(address.value());
std::cout << connectResponse << std::endl;
if (!connectResponse.isOk())
return EXIT_FAILURE;

View File

@ -26,7 +26,7 @@ void runTcpServer(unsigned short port)
sf::TcpSocket socket;
if (listener.accept(socket) != sf::Socket::Done)
return;
std::cout << "Client connected: " << socket.getRemoteAddress() << std::endl;
std::cout << "Client connected: " << socket.getRemoteAddress().value() << std::endl;
// Send a message to the connected client
const char out[] = "Hi, I'm the server";
@ -51,21 +51,21 @@ void runTcpServer(unsigned short port)
void runTcpClient(unsigned short port)
{
// Ask for the server address
sf::IpAddress server;
std::optional<sf::IpAddress> server;
do
{
std::cout << "Type the address or name of the server to connect to: ";
std::cin >> server;
}
while (server == sf::IpAddress::None);
while (!server.has_value());
// Create a socket for communicating with the server
sf::TcpSocket socket;
// Connect to the server
if (socket.connect(server, port) != sf::Socket::Done)
if (socket.connect(server.value(), port) != sf::Socket::Done)
return;
std::cout << "Connected to server " << server << std::endl;
std::cout << "Connected to server " << server.value() << std::endl;
// Receive a message from the server
char in[128];

View File

@ -5,6 +5,7 @@
#include <SFML/Network.hpp>
#include <iomanip>
#include <iostream>
#include <optional>
////////////////////////////////////////////////////////////
@ -24,15 +25,15 @@ void runUdpServer(unsigned short port)
// Wait for a message
char in[128];
std::size_t received;
sf::IpAddress sender;
std::optional<sf::IpAddress> sender;
unsigned short senderPort;
if (socket.receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done)
return;
std::cout << "Message received from client " << sender << ": " << std::quoted(in) << std::endl;
std::cout << "Message received from client " << sender.value() << ": " << std::quoted(in) << std::endl;
// Send an answer to the client
const char out[] = "Hi, I'm the server";
if (socket.send(out, sizeof(out), sender, senderPort) != sf::Socket::Done)
if (socket.send(out, sizeof(out), sender.value(), senderPort) != sf::Socket::Done)
return;
std::cout << "Message sent to the client: " << std::quoted(out) << std::endl;
}
@ -45,29 +46,29 @@ void runUdpServer(unsigned short port)
void runUdpClient(unsigned short port)
{
// Ask for the server address
sf::IpAddress server;
std::optional<sf::IpAddress> server;
do
{
std::cout << "Type the address or name of the server to connect to: ";
std::cin >> server;
}
while (server == sf::IpAddress::None);
while (!server.has_value());
// Create a socket for communicating with the server
sf::UdpSocket socket;
// Send a message to the server
const char out[] = "Hi, I'm a client";
if (socket.send(out, sizeof(out), server, port) != sf::Socket::Done)
if (socket.send(out, sizeof(out), server.value(), port) != sf::Socket::Done)
return;
std::cout << "Message sent to the server: " << std::quoted(out) << std::endl;
// Receive an answer from anyone (but most likely from the server)
char in[128];
std::size_t received;
sf::IpAddress sender;
std::optional<sf::IpAddress> sender;
unsigned short senderPort;
if (socket.receive(in, sizeof(in), received, sender, senderPort) != sf::Socket::Done)
return;
std::cout << "Message received from " << sender << ": " << std::quoted(in) << std::endl;
std::cout << "Message received from " << sender.value() << ": " << std::quoted(in) << std::endl;
}

View File

@ -121,16 +121,16 @@ void doClient(unsigned short port)
}
// Ask for server address
sf::IpAddress server;
std::optional<sf::IpAddress> server;
do
{
std::cout << "Type address or name of the server to connect to: ";
std::cin >> server;
}
while (server == sf::IpAddress::None);
while (!server.has_value());
// Create an instance of our custom recorder
NetworkRecorder recorder(server, port);
NetworkRecorder recorder(server.value(), port);
// Wait for user input...
std::cin.ignore(10000, '\n');

View File

@ -50,7 +50,7 @@ public:
// Wait for a connection
if (m_listener.accept(m_client) != sf::Socket::Done)
return;
std::cout << "Client connected: " << m_client.getRemoteAddress() << std::endl;
std::cout << "Client connected: " << m_client.getRemoteAddress().value() << std::endl;
// Start playback
play();

View File

@ -33,6 +33,7 @@
#include <SFML/Network/TcpSocket.hpp>
#include <SFML/System/Time.hpp>
#include <map>
#include <optional>
#include <string>
@ -420,10 +421,10 @@ private:
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
TcpSocket m_connection; //!< Connection to the host
IpAddress m_host; //!< Web host address
std::string m_hostName; //!< Web host name
unsigned short m_port; //!< Port used for connection with host
TcpSocket m_connection; //!< Connection to the host
std::optional<IpAddress> m_host; //!< Web host address
std::string m_hostName; //!< Web host name
unsigned short m_port; //!< Port used for connection with host
};
} // namespace sf

View File

@ -32,6 +32,7 @@
#include <SFML/System/Time.hpp>
#include <iosfwd>
#include <optional>
#include <string_view>
#include <string>
@ -44,17 +45,8 @@ namespace sf
class SFML_NETWORK_API IpAddress
{
public:
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
/// This constructor creates an empty (invalid) address
///
////////////////////////////////////////////////////////////
IpAddress();
////////////////////////////////////////////////////////////
/// \brief Construct the address from a string
/// \brief Construct the address from a null-terminated string view
///
/// Here \a address can be either a decimal address
/// (ex: "192.168.1.56") or a network name (ex: "localhost").
@ -62,28 +54,14 @@ public:
/// \param address IP address or network name
///
////////////////////////////////////////////////////////////
IpAddress(const std::string& address);
////////////////////////////////////////////////////////////
/// \brief Construct the address from a string
///
/// Here \a address can be either a decimal address
/// (ex: "192.168.1.56") or a network name (ex: "localhost").
/// This is equivalent to the constructor taking a std::string
/// parameter, it is defined for convenience so that the
/// implicit conversions from literal strings to IpAddress work.
///
/// \param address IP address or network name
///
////////////////////////////////////////////////////////////
IpAddress(const char* address);
static std::optional<IpAddress> resolve(std::string_view address);
////////////////////////////////////////////////////////////
/// \brief Construct the address from 4 bytes
///
/// Calling IpAddress(a, b, c, d) is equivalent to calling
/// IpAddress("a.b.c.d"), but safer as it doesn't have to
/// parse a string to get the address components.
/// IpAddress::resolve("a.b.c.d"), but safer as it doesn't
/// have to parse a string to get the address components.
///
/// \param byte0 First byte of the address
/// \param byte1 Second byte of the address
@ -152,7 +130,7 @@ public:
/// \see getPublicAddress
///
////////////////////////////////////////////////////////////
static IpAddress getLocalAddress();
static std::optional<IpAddress> getLocalAddress();
////////////////////////////////////////////////////////////
/// \brief Get the computer's public address
@ -176,12 +154,11 @@ public:
/// \see getLocalAddress
///
////////////////////////////////////////////////////////////
static IpAddress getPublicAddress(Time timeout = Time::Zero);
static std::optional<IpAddress> getPublicAddress(Time timeout = Time::Zero);
////////////////////////////////////////////////////////////
// Static member data
////////////////////////////////////////////////////////////
static const IpAddress None; //!< Value representing an empty/invalid address
static const IpAddress Any; //!< Value representing any address (0.0.0.0)
static const IpAddress LocalHost; //!< The "localhost" address (for connecting a computer to itself locally)
static const IpAddress Broadcast; //!< The "broadcast" address (for sending UDP messages to everyone on a local network)
@ -193,7 +170,7 @@ private:
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
std::optional<Uint32> m_address; //!< Address stored as an unsigned 32 bits integer
Uint32 m_address; //!< Address stored as an unsigned 32 bits integer
};
////////////////////////////////////////////////////////////
@ -271,7 +248,7 @@ SFML_NETWORK_API bool operator >=(const IpAddress& left, const IpAddress& right)
/// \return Reference to the input stream
///
////////////////////////////////////////////////////////////
SFML_NETWORK_API std::istream& operator >>(std::istream& stream, IpAddress& address);
SFML_NETWORK_API std::istream& operator >>(std::istream& stream, std::optional<IpAddress>& address);
////////////////////////////////////////////////////////////
/// \brief Overload of << operator to print an IP address to an output stream
@ -301,16 +278,14 @@ SFML_NETWORK_API std::ostream& operator <<(std::ostream& stream, const IpAddress
///
/// Usage example:
/// \code
/// sf::IpAddress a0; // an invalid address
/// sf::IpAddress a1 = sf::IpAddress::None; // an invalid address (same as a0)
/// sf::IpAddress a2("127.0.0.1"); // the local host address
/// sf::IpAddress a3 = sf::IpAddress::Broadcast; // the broadcast address
/// sf::IpAddress a4(192, 168, 1, 56); // a local address
/// sf::IpAddress a5("my_computer"); // a local address created from a network name
/// sf::IpAddress a6("89.54.1.169"); // a distant address
/// sf::IpAddress a7("www.google.com"); // a distant address created from a network name
/// sf::IpAddress a8 = sf::IpAddress::getLocalAddress(); // my address on the local network
/// sf::IpAddress a9 = sf::IpAddress::getPublicAddress(); // my address on the internet
/// auto a2 = sf::IpAddress::resolve("127.0.0.1"); // the local host address
/// auto a3 = sf::IpAddress::Broadcast; // the broadcast address
/// sf::IpAddress a4(192, 168, 1, 56); // a local address
/// auto a5 = sf::IpAddress::resolve("my_computer"); // a local address created from a network name
/// auto a6 = sf::IpAddress::resolve("89.54.1.169"); // a distant address
/// auto a7 = sf::IpAddress::resolve("www.google.com"); // a distant address created from a network name
/// auto a8 = sf::IpAddress::getLocalAddress(); // my address on the local network
/// auto a9 = sf::IpAddress::getPublicAddress(); // my address on the internet
/// \endcode
///
/// Note that sf::IpAddress currently doesn't support IPv6

View File

@ -159,7 +159,7 @@ public:
/// if (listener.accept(client) == sf::Socket::Done)
/// {
/// // A new client just connected!
/// std::cout << "New connection received from " << client.getRemoteAddress() << std::endl;
/// std::cout << "New connection received from " << client.getRemoteAddress().value() << std::endl;
/// doSomethingWith(client);
/// }
/// }

View File

@ -31,6 +31,7 @@
#include <SFML/Network/Export.hpp>
#include <SFML/Network/Socket.hpp>
#include <SFML/System/Time.hpp>
#include <optional>
namespace sf
@ -69,14 +70,14 @@ public:
/// \brief Get the address of the connected peer
///
/// If the socket is not connected, this function returns
/// sf::IpAddress::None.
/// an unset optional.
///
/// \return Address of the remote peer
///
/// \see getRemotePort
///
////////////////////////////////////////////////////////////
IpAddress getRemoteAddress() const;
std::optional<IpAddress> getRemoteAddress() const;
////////////////////////////////////////////////////////////
/// \brief Get the port of the connected peer to which
@ -299,7 +300,7 @@ private:
/// // Wait for a connection
/// sf::TcpSocket socket;
/// listener.accept(socket);
/// std::cout << "New client connected: " << socket.getRemoteAddress() << std::endl;
/// std::cout << "New client connected: " << socket.getRemoteAddress().value() << std::endl;
///
/// // Receive a message from the client
/// char buffer[1024];

View File

@ -31,6 +31,7 @@
#include <SFML/Network/Export.hpp>
#include <SFML/Network/Socket.hpp>
#include <SFML/Network/IpAddress.hpp>
#include <optional>
#include <vector>
@ -152,7 +153,7 @@ public:
/// \see send
///
////////////////////////////////////////////////////////////
[[nodiscard]] Status receive(void* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort);
[[nodiscard]] Status receive(void* data, std::size_t size, std::size_t& received, std::optional<IpAddress>& remoteAddress, unsigned short& remotePort);
////////////////////////////////////////////////////////////
/// \brief Send a formatted packet of data to a remote peer
@ -187,7 +188,7 @@ public:
/// \see send
///
////////////////////////////////////////////////////////////
[[nodiscard]] Status receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort);
[[nodiscard]] Status receive(Packet& packet, std::optional<IpAddress>& remoteAddress, unsigned short& remotePort);
private:
@ -263,10 +264,10 @@ private:
/// // Receive an answer (most likely from 192.168.1.50, but could be anyone else)
/// char buffer[1024];
/// std::size_t received = 0;
/// sf::IpAddress sender;
/// std::optional<sf::IpAddress> sender;
/// unsigned short port;
/// socket.receive(buffer, sizeof(buffer), received, sender, port);
/// std::cout << sender.ToString() << " said: " << buffer << std::endl;
/// if (socket.receive(buffer, sizeof(buffer), received, sender, port) == sf::Socket::Done)
/// std::cout << sender->toString() << " said: " << buffer << std::endl;
///
/// // ----- The server -----
///
@ -277,10 +278,10 @@ private:
/// // Receive a message from anyone
/// char buffer[1024];
/// std::size_t received = 0;
/// sf::IpAddress sender;
/// std::optional<sf::IpAddress> sender;
/// unsigned short port;
/// socket.receive(buffer, sizeof(buffer), received, sender, port);
/// std::cout << sender.ToString() << " said: " << buffer << std::endl;
/// if (socket.receive(buffer, sizeof(buffer), received, sender, port) == sf::Socket::Done)
/// std::cout << sender->toString() << " said: " << buffer << std::endl;
///
/// // Send an answer
/// std::string message = "Welcome " + sender.toString();

View File

@ -329,7 +329,7 @@ void Http::setHost(const std::string& host, unsigned short port)
if (!m_hostName.empty() && (*m_hostName.rbegin() == '/'))
m_hostName.erase(m_hostName.size() - 1);
m_host = IpAddress(m_hostName);
m_host = IpAddress::resolve(m_hostName);
}
@ -369,7 +369,7 @@ Http::Response Http::sendRequest(const Http::Request& request, Time timeout)
Response received;
// Connect the socket to the host
if (m_connection.connect(m_host, m_port, timeout) == Socket::Done)
if (m_connection.connect(m_host.value(), m_port, timeout) == Socket::Done)
{
// Convert the request to string and send it through the connected socket
std::string requestStr = toSend.prepare();

View File

@ -37,68 +37,56 @@
namespace sf
{
////////////////////////////////////////////////////////////
const IpAddress IpAddress::None;
const IpAddress IpAddress::Any(0, 0, 0, 0);
const IpAddress IpAddress::LocalHost(127, 0, 0, 1);
const IpAddress IpAddress::Broadcast(255, 255, 255, 255);
////////////////////////////////////////////////////////////
IpAddress::IpAddress() = default;
////////////////////////////////////////////////////////////
IpAddress::IpAddress(const std::string& address)
std::optional<IpAddress> IpAddress::resolve(std::string_view address)
{
if (address == "255.255.255.255")
using namespace std::string_view_literals;
if (address.empty())
return std::nullopt;
if (address == "255.255.255.255"sv)
{
// The broadcast address needs to be handled explicitly,
// because it is also the value returned by inet_addr on error
m_address = INADDR_BROADCAST;
return;
return Broadcast;
}
if (address == "0.0.0.0")
{
m_address = INADDR_ANY;
return;
}
if (address == "0.0.0.0"sv)
return Any;
// Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx")
sf::Uint32 ip = inet_addr(address.c_str());
if (ip != INADDR_NONE)
{
m_address = ip;
return;
}
if (const Uint32 ip = inet_addr(address.data()); ip != INADDR_NONE)
return IpAddress(ntohl(ip));
// Not a valid address, try to convert it as a host name
addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
addrinfo hints{}; // Zero-initialize
hints.ai_family = AF_INET;
addrinfo* result = nullptr;
if (getaddrinfo(address.c_str(), nullptr, &hints, &result) == 0 && result)
if (getaddrinfo(address.data(), nullptr, &hints, &result) == 0 && result != nullptr)
{
sockaddr_in sin;
std::memcpy(&sin, result->ai_addr, sizeof(*result->ai_addr));
ip = sin.sin_addr.s_addr;
const Uint32 ip = sin.sin_addr.s_addr;
freeaddrinfo(result);
m_address = ip;
return;
return IpAddress(ntohl(ip));
}
}
////////////////////////////////////////////////////////////
IpAddress::IpAddress(const char* address) :
IpAddress(std::string(address))
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
IpAddress::IpAddress(Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3) :
m_address(htonl(static_cast<uint32_t>((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3)))
m_address(htonl(static_cast<std::uint32_t>((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3)))
{
}
@ -114,7 +102,7 @@ m_address(htonl(address))
std::string IpAddress::toString() const
{
in_addr address;
address.s_addr = m_address.value_or(0);
address.s_addr = m_address;
return inet_ntoa(address);
}
@ -123,30 +111,28 @@ std::string IpAddress::toString() const
////////////////////////////////////////////////////////////
Uint32 IpAddress::toInteger() const
{
return ntohl(m_address.value_or(0));
return ntohl(m_address);
}
////////////////////////////////////////////////////////////
IpAddress IpAddress::getLocalAddress()
std::optional<IpAddress> IpAddress::getLocalAddress()
{
// The method here is to connect a UDP socket to anyone (here to localhost),
// and get the local socket address with the getsockname function.
// UDP connection will not send anything to the network, so this function won't cause any overhead.
IpAddress localAddress;
// Create the socket
SocketHandle sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == priv::SocketImpl::invalidSocket())
return localAddress;
return std::nullopt;
// Connect the socket to localhost on any port
sockaddr_in address = priv::SocketImpl::createAddress(ntohl(INADDR_LOOPBACK), 9);
if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
{
priv::SocketImpl::close(sock);
return localAddress;
return std::nullopt;
}
// Get the local address of the socket connection
@ -154,21 +140,19 @@ IpAddress IpAddress::getLocalAddress()
if (getsockname(sock, reinterpret_cast<sockaddr*>(&address), &size) == -1)
{
priv::SocketImpl::close(sock);
return localAddress;
return std::nullopt;
}
// Close the socket
priv::SocketImpl::close(sock);
// Finally build the IP address
localAddress = IpAddress(ntohl(address.sin_addr.s_addr));
return localAddress;
return IpAddress(ntohl(address.sin_addr.s_addr));
}
////////////////////////////////////////////////////////////
IpAddress IpAddress::getPublicAddress(Time timeout)
std::optional<IpAddress> IpAddress::getPublicAddress(Time timeout)
{
// The trick here is more complicated, because the only way
// to get our public IP address is to get it from a distant computer.
@ -180,10 +164,10 @@ IpAddress IpAddress::getPublicAddress(Time timeout)
Http::Request request("/ip-provider.php", Http::Request::Get);
Http::Response page = server.sendRequest(request, timeout);
if (page.getStatus() == Http::Response::Ok)
return IpAddress(page.getBody());
return IpAddress::resolve(page.getBody());
// Something failed: return an invalid address
return IpAddress();
return std::nullopt;
}
@ -230,11 +214,11 @@ bool operator >=(const IpAddress& left, const IpAddress& right)
////////////////////////////////////////////////////////////
std::istream& operator >>(std::istream& stream, IpAddress& address)
std::istream& operator >>(std::istream& stream, std::optional<IpAddress>& address)
{
std::string str;
stream >> str;
address = IpAddress(str);
address = IpAddress::resolve(str);
return stream;
}

View File

@ -71,7 +71,7 @@ Socket::Status TcpListener::listen(unsigned short port, const IpAddress& address
create();
// Check if the address is valid
if ((address == IpAddress::None) || (address == IpAddress::Broadcast))
if (address == IpAddress::Broadcast)
return Error;
// Bind the socket to the specified port

View File

@ -79,7 +79,7 @@ unsigned short TcpSocket::getLocalPort() const
////////////////////////////////////////////////////////////
IpAddress TcpSocket::getRemoteAddress() const
std::optional<IpAddress> TcpSocket::getRemoteAddress() const
{
if (getHandle() != priv::SocketImpl::invalidSocket())
{
@ -93,7 +93,7 @@ IpAddress TcpSocket::getRemoteAddress() const
}
// We failed to retrieve the address
return IpAddress::None;
return std::nullopt;
}
@ -183,7 +183,7 @@ Socket::Status TcpSocket::connect(const IpAddress& remoteAddress, unsigned short
{
// At this point the connection may have been either accepted or refused.
// To know whether it's a success or a failure, we must check the address of the connected peer
if (getRemoteAddress() != IpAddress::None)
if (getRemoteAddress().has_value())
{
// Connection accepted
status = Done;

View File

@ -74,7 +74,7 @@ Socket::Status UdpSocket::bind(unsigned short port, const IpAddress& address)
create();
// Check if the address is valid
if ((address == IpAddress::None) || (address == IpAddress::Broadcast))
if (address == IpAddress::Broadcast)
return Error;
// Bind the socket
@ -129,11 +129,11 @@ Socket::Status UdpSocket::send(const void* data, std::size_t size, const IpAddre
////////////////////////////////////////////////////////////
Socket::Status UdpSocket::receive(void* data, std::size_t size, std::size_t& received, IpAddress& remoteAddress, unsigned short& remotePort)
Socket::Status UdpSocket::receive(void* data, std::size_t size, std::size_t& received, std::optional<IpAddress>& remoteAddress, unsigned short& remotePort)
{
// First clear the variables to fill
received = 0;
remoteAddress = IpAddress();
remoteAddress = std::nullopt;
remotePort = 0;
// Check the destination buffer
@ -187,7 +187,7 @@ Socket::Status UdpSocket::send(Packet& packet, const IpAddress& remoteAddress, u
////////////////////////////////////////////////////////////
Socket::Status UdpSocket::receive(Packet& packet, IpAddress& remoteAddress, unsigned short& remotePort)
Socket::Status UdpSocket::receive(Packet& packet, std::optional<IpAddress>& remoteAddress, unsigned short& remotePort)
{
// See the detailed comment in send(Packet) above.

View File

@ -3,78 +3,45 @@
#include <doctest.h>
#include <sstream>
#include <string_view>
using namespace std::string_literals;
using namespace std::string_view_literals;
TEST_CASE("sf::IpAddress class - [network]")
{
SUBCASE("Construction")
{
SUBCASE("Default constructor")
SUBCASE("static 'create' function")
{
const sf::IpAddress ipAddress;
CHECK(ipAddress.toString() == "0.0.0.0"s);
CHECK(ipAddress.toInteger() == 0);
CHECK(ipAddress == sf::IpAddress::None);
}
const auto ipAddress = sf::IpAddress::resolve("192.168.0.1"sv);
REQUIRE(ipAddress.has_value());
CHECK(ipAddress->toString() == "192.168.0.1"s);
CHECK(ipAddress->toInteger() == 0xC0A80001);
CHECK(*ipAddress != sf::IpAddress::Any);
CHECK(*ipAddress != sf::IpAddress::Broadcast);
CHECK(*ipAddress != sf::IpAddress::LocalHost);
SUBCASE("std::string constructor")
{
const sf::IpAddress ipAddress = "192.168.0.1"s;
CHECK(ipAddress.toString() == "192.168.0.1"s);
CHECK(ipAddress.toInteger() == 0xC0A80001);
CHECK(ipAddress != sf::IpAddress::None);
CHECK(ipAddress != sf::IpAddress::Any);
CHECK(ipAddress != sf::IpAddress::Broadcast);
CHECK(ipAddress != sf::IpAddress::LocalHost);
const auto broadcast = sf::IpAddress::resolve("255.255.255.255"sv);
REQUIRE(broadcast.has_value());
CHECK(broadcast->toString() == "255.255.255.255"s);
CHECK(broadcast->toInteger() == 0xFFFFFFFF);
CHECK(*broadcast == sf::IpAddress::Broadcast);
const sf::IpAddress broadcast("255.255.255.255"s);
CHECK(broadcast.toString() == "255.255.255.255"s);
CHECK(broadcast.toInteger() == 0xFFFFFFFF);
CHECK(broadcast == sf::IpAddress::Broadcast);
const auto any = sf::IpAddress::resolve("0.0.0.0"sv);
REQUIRE(any.has_value());
CHECK(any->toString() == "0.0.0.0"s);
CHECK(any->toInteger() == 0x00000000);
CHECK(*any == sf::IpAddress::Any);
const sf::IpAddress any("0.0.0.0"s);
CHECK(any.toString() == "0.0.0.0"s);
CHECK(any.toInteger() == 0x00000000);
CHECK(any == sf::IpAddress::Any);
const auto localHost = sf::IpAddress::resolve("localhost"s);
REQUIRE(localHost.has_value());
CHECK(localHost->toString() == "127.0.0.1"s);
CHECK(localHost->toInteger() == 0x7F000001);
CHECK(*localHost == sf::IpAddress::LocalHost);
const sf::IpAddress localHost("localhost"s);
CHECK(localHost.toString() == "127.0.0.1"s);
CHECK(localHost.toInteger() == 0x7F000001);
CHECK(localHost == sf::IpAddress::LocalHost);
const sf::IpAddress invalidIpAddress("255.255.255.256"s);
CHECK(invalidIpAddress.toString() == "0.0.0.0"s);
CHECK(invalidIpAddress.toInteger() == 0);
CHECK(invalidIpAddress == sf::IpAddress::None);
}
SUBCASE("const char* constructor")
{
const sf::IpAddress ipAddress = "192.168.0.1";
CHECK(ipAddress.toString() == "192.168.0.1"s);
CHECK(ipAddress.toInteger() == 0xC0A80001);
CHECK(ipAddress != sf::IpAddress::None);
const sf::IpAddress broadcast("255.255.255.255");
CHECK(broadcast.toString() == "255.255.255.255"s);
CHECK(broadcast.toInteger() == 0xFFFFFFFF);
CHECK(broadcast == sf::IpAddress::Broadcast);
const sf::IpAddress any("0.0.0.0");
CHECK(any.toString() == "0.0.0.0"s);
CHECK(any.toInteger() == 0x00000000);
CHECK(any == sf::IpAddress::Any);
const sf::IpAddress localHost("localhost");
CHECK(localHost.toString() == "127.0.0.1"s);
CHECK(localHost.toInteger() == 0x7F000001);
CHECK(localHost == sf::IpAddress::LocalHost);
const sf::IpAddress invalidIpAddress("255.255.255.256");
CHECK(invalidIpAddress.toString() == "0.0.0.0"s);
CHECK(invalidIpAddress.toInteger() == 0);
CHECK(invalidIpAddress == sf::IpAddress::None);
CHECK(!sf::IpAddress::resolve("255.255.255.256"s).has_value());
CHECK(!sf::IpAddress::resolve("").has_value());
}
SUBCASE("Byte constructor")
@ -82,7 +49,6 @@ TEST_CASE("sf::IpAddress class - [network]")
const sf::IpAddress ipAddress(142, 250, 69, 238);
CHECK(ipAddress.toString() == "142.250.69.238"s);
CHECK(ipAddress.toInteger() == 0x8EFA45EE);
CHECK(ipAddress != sf::IpAddress::None);
}
SUBCASE("Uint32 constructor")
@ -90,7 +56,6 @@ TEST_CASE("sf::IpAddress class - [network]")
const sf::IpAddress ipAddress(0xDEADBEEF);
CHECK(ipAddress.toString() == "222.173.190.239"s);
CHECK(ipAddress.toInteger() == 0xDEADBEEF);
CHECK(ipAddress != sf::IpAddress::None);
}
}
@ -98,26 +63,23 @@ TEST_CASE("sf::IpAddress class - [network]")
{
SUBCASE("getLocalAddress")
{
const sf::IpAddress ipAddress = sf::IpAddress::getLocalAddress();
CHECK(ipAddress.toString() != "0.0.0.0");
CHECK(ipAddress.toInteger() != 0);
CHECK(ipAddress != sf::IpAddress::None);
const std::optional<sf::IpAddress> ipAddress = sf::IpAddress::getLocalAddress();
REQUIRE(ipAddress.has_value());
CHECK(ipAddress->toString() != "0.0.0.0");
CHECK(ipAddress->toInteger() != 0);
}
SUBCASE("getPublicAddress")
{
const sf::IpAddress ipAddress = sf::IpAddress::getPublicAddress();
CHECK(ipAddress.toString() != "0.0.0.0");
CHECK(ipAddress.toInteger() != 0);
CHECK(ipAddress != sf::IpAddress::None);
const std::optional<sf::IpAddress> ipAddress = sf::IpAddress::getPublicAddress();
REQUIRE(ipAddress.has_value());
CHECK(ipAddress->toString() != "0.0.0.0");
CHECK(ipAddress->toInteger() != 0);
}
}
SUBCASE("Static constants")
{
CHECK(sf::IpAddress::None.toString() == "0.0.0.0"s);
CHECK(sf::IpAddress::None.toInteger() == 0);
CHECK(sf::IpAddress::Any.toString() == "0.0.0.0"s);
CHECK(sf::IpAddress::Any.toInteger() == 0);
@ -132,24 +94,19 @@ TEST_CASE("sf::IpAddress class - [network]")
{
SUBCASE("operator==")
{
CHECK(sf::IpAddress() == sf::IpAddress());
CHECK(sf::IpAddress("") == sf::IpAddress(""s));
CHECK(sf::IpAddress("8.8.8.8") == sf::IpAddress(8, 8, 8, 8));
CHECK(sf::IpAddress(0x42, 0x69, 0x96, 0x24) == sf::IpAddress(0x42699624));
CHECK(sf::IpAddress(0xABCDEF01) == sf::IpAddress("171.205.239.1"));
CHECK(sf::IpAddress(0xABCDEF01) == sf::IpAddress(171, 205, 239, 1));
}
SUBCASE("operator!=")
{
CHECK(sf::IpAddress() != sf::IpAddress("1.1.1.1"));
CHECK(sf::IpAddress(0x12344321) != sf::IpAddress(""));
CHECK(sf::IpAddress(0x12344321) != sf::IpAddress(1234));
CHECK(sf::IpAddress(192, 168, 1, 10) != sf::IpAddress(192, 168, 1, 11));
}
SUBCASE("operator<")
{
CHECK(sf::IpAddress(1) < sf::IpAddress(2));
CHECK(sf::IpAddress() < sf::IpAddress(0, 0, 0, 0));
CHECK(sf::IpAddress(0, 0, 0, 0) < sf::IpAddress(1, 0, 0, 0));
CHECK(sf::IpAddress(1, 0, 0, 0) < sf::IpAddress(0, 1, 0, 0));
CHECK(sf::IpAddress(0, 1, 0, 0) < sf::IpAddress(0, 0, 1, 0));
@ -160,7 +117,6 @@ TEST_CASE("sf::IpAddress class - [network]")
SUBCASE("operator>")
{
CHECK(sf::IpAddress(2) > sf::IpAddress(1));
CHECK(sf::IpAddress(0, 0, 0, 0) > sf::IpAddress());
CHECK(sf::IpAddress(1, 0, 0, 0) > sf::IpAddress(0, 0, 0, 0));
CHECK(sf::IpAddress(0, 1, 0, 0) > sf::IpAddress(1, 0, 0, 0));
CHECK(sf::IpAddress(0, 0, 1, 0) > sf::IpAddress(0, 1, 0, 0));
@ -171,49 +127,44 @@ TEST_CASE("sf::IpAddress class - [network]")
SUBCASE("operator<=")
{
CHECK(sf::IpAddress(1) <= sf::IpAddress(2));
CHECK(sf::IpAddress() <= sf::IpAddress(0, 0, 0, 0));
CHECK(sf::IpAddress(0, 0, 0, 0) <= sf::IpAddress(1, 0, 0, 0));
CHECK(sf::IpAddress(1, 0, 0, 0) <= sf::IpAddress(0, 1, 0, 0));
CHECK(sf::IpAddress(0, 1, 0, 0) <= sf::IpAddress(0, 0, 1, 0));
CHECK(sf::IpAddress(0, 0, 1, 0) <= sf::IpAddress(0, 0, 0, 1));
CHECK(sf::IpAddress(0, 0, 0, 1) <= sf::IpAddress(1, 0, 0, 1));
CHECK(sf::IpAddress() <= sf::IpAddress());
CHECK(sf::IpAddress("") <= sf::IpAddress(""s));
CHECK(sf::IpAddress("8.8.8.8") <= sf::IpAddress(8, 8, 8, 8));
CHECK(sf::IpAddress(0x42, 0x69, 0x96, 0x24) <= sf::IpAddress(0x42699624));
CHECK(sf::IpAddress(0xABCDEF01) <= sf::IpAddress("171.205.239.1"));
CHECK(sf::IpAddress(0xABCDEF01) <= sf::IpAddress(171, 205, 239, 1));
}
SUBCASE("operator>=")
{
CHECK(sf::IpAddress(2) >= sf::IpAddress(1));
CHECK(sf::IpAddress(0, 0, 0, 0) >= sf::IpAddress());
CHECK(sf::IpAddress(1, 0, 0, 0) >= sf::IpAddress(0, 0, 0, 0));
CHECK(sf::IpAddress(0, 1, 0, 0) >= sf::IpAddress(1, 0, 0, 0));
CHECK(sf::IpAddress(0, 0, 1, 0) >= sf::IpAddress(0, 1, 0, 0));
CHECK(sf::IpAddress(0, 0, 0, 1) >= sf::IpAddress(0, 0, 1, 0));
CHECK(sf::IpAddress(1, 0, 0, 1) >= sf::IpAddress(0, 0, 0, 1));
CHECK(sf::IpAddress() >= sf::IpAddress());
CHECK(sf::IpAddress("") >= sf::IpAddress(""s));
CHECK(sf::IpAddress("8.8.8.8") >= sf::IpAddress(8, 8, 8, 8));
CHECK(sf::IpAddress(0x42, 0x69, 0x96, 0x24) >= sf::IpAddress(0x42699624));
CHECK(sf::IpAddress(0xABCDEF01) >= sf::IpAddress("171.205.239.1"));
CHECK(sf::IpAddress(0xABCDEF01) >= sf::IpAddress(171, 205, 239, 1));
}
SUBCASE("operator>>")
{
sf::IpAddress ipAddress;
std::optional<sf::IpAddress> ipAddress;
std::istringstream("4.4.4.4") >> ipAddress;
CHECK(ipAddress.toString() == "4.4.4.4"s);
CHECK(ipAddress.toInteger() == 0x04040404);
CHECK(ipAddress != sf::IpAddress::None);
REQUIRE(ipAddress.has_value());
CHECK(ipAddress->toString() == "4.4.4.4"s);
CHECK(ipAddress->toInteger() == 0x04040404);
std::istringstream("92.100.0.72") >> ipAddress;
CHECK(ipAddress.toString() == "92.100.0.72"s);
CHECK(ipAddress.toInteger() == 0x5C640048);
CHECK(ipAddress != sf::IpAddress::None);
REQUIRE(ipAddress.has_value());
CHECK(ipAddress->toString() == "92.100.0.72"s);
CHECK(ipAddress->toInteger() == 0x5C640048);
std::istringstream("") >> ipAddress;
CHECK(!ipAddress.has_value());
}
SUBCASE("operator<<")