From 8c8d97c6c9f2d9b58688e73970b73be7a84c88e1 Mon Sep 17 00:00:00 2001 From: Vittorio Romeo Date: Mon, 27 Jun 2022 12:02:35 +0200 Subject: [PATCH] IpAddress is always valid --- examples/ftp/Ftp.cpp | 7 +- examples/sockets/TCP.cpp | 10 +- examples/sockets/UDP.cpp | 17 ++-- examples/voip/Client.cpp | 6 +- examples/voip/Server.cpp | 2 +- include/SFML/Network/Http.hpp | 9 +- include/SFML/Network/IpAddress.hpp | 59 ++++------- include/SFML/Network/TcpListener.hpp | 2 +- include/SFML/Network/TcpSocket.hpp | 7 +- include/SFML/Network/UdpSocket.hpp | 17 ++-- src/SFML/Network/Http.cpp | 4 +- src/SFML/Network/IpAddress.cpp | 82 ++++++--------- src/SFML/Network/TcpListener.cpp | 2 +- src/SFML/Network/TcpSocket.cpp | 6 +- src/SFML/Network/UdpSocket.cpp | 8 +- test/Network/IpAddress.cpp | 147 +++++++++------------------ 16 files changed, 150 insertions(+), 235 deletions(-) diff --git a/examples/ftp/Ftp.cpp b/examples/ftp/Ftp.cpp index 82df9e13..977ea7cc 100644 --- a/examples/ftp/Ftp.cpp +++ b/examples/ftp/Ftp.cpp @@ -5,6 +5,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////// @@ -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 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; diff --git a/examples/sockets/TCP.cpp b/examples/sockets/TCP.cpp index 7b2aeac8..ecea209d 100644 --- a/examples/sockets/TCP.cpp +++ b/examples/sockets/TCP.cpp @@ -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 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]; diff --git a/examples/sockets/UDP.cpp b/examples/sockets/UDP.cpp index eeaf213a..20854eec 100644 --- a/examples/sockets/UDP.cpp +++ b/examples/sockets/UDP.cpp @@ -5,6 +5,7 @@ #include #include #include +#include //////////////////////////////////////////////////////////// @@ -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 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 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 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; } diff --git a/examples/voip/Client.cpp b/examples/voip/Client.cpp index ec41aaa9..f718f0f2 100644 --- a/examples/voip/Client.cpp +++ b/examples/voip/Client.cpp @@ -121,16 +121,16 @@ void doClient(unsigned short port) } // Ask for server address - sf::IpAddress server; + std::optional 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'); diff --git a/examples/voip/Server.cpp b/examples/voip/Server.cpp index 9012c77b..64baca3d 100644 --- a/examples/voip/Server.cpp +++ b/examples/voip/Server.cpp @@ -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(); diff --git a/include/SFML/Network/Http.hpp b/include/SFML/Network/Http.hpp index 2f439fb2..dbfe1dde 100644 --- a/include/SFML/Network/Http.hpp +++ b/include/SFML/Network/Http.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -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 m_host; //!< Web host address + std::string m_hostName; //!< Web host name + unsigned short m_port; //!< Port used for connection with host }; } // namespace sf diff --git a/include/SFML/Network/IpAddress.hpp b/include/SFML/Network/IpAddress.hpp index 3b9497fb..76245e49 100644 --- a/include/SFML/Network/IpAddress.hpp +++ b/include/SFML/Network/IpAddress.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -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 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 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 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 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& 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 diff --git a/include/SFML/Network/TcpListener.hpp b/include/SFML/Network/TcpListener.hpp index bea6f58d..a8f9e90e 100644 --- a/include/SFML/Network/TcpListener.hpp +++ b/include/SFML/Network/TcpListener.hpp @@ -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); /// } /// } diff --git a/include/SFML/Network/TcpSocket.hpp b/include/SFML/Network/TcpSocket.hpp index afcdc63c..de383e02 100644 --- a/include/SFML/Network/TcpSocket.hpp +++ b/include/SFML/Network/TcpSocket.hpp @@ -31,6 +31,7 @@ #include #include #include +#include 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 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]; diff --git a/include/SFML/Network/UdpSocket.hpp b/include/SFML/Network/UdpSocket.hpp index c2ec6bc2..58a7b631 100644 --- a/include/SFML/Network/UdpSocket.hpp +++ b/include/SFML/Network/UdpSocket.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -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& 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& 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 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 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(); diff --git a/src/SFML/Network/Http.cpp b/src/SFML/Network/Http.cpp index 5542a2b6..e58e7ef6 100644 --- a/src/SFML/Network/Http.cpp +++ b/src/SFML/Network/Http.cpp @@ -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(); diff --git a/src/SFML/Network/IpAddress.cpp b/src/SFML/Network/IpAddress.cpp index 73b06200..d37a2e8b 100644 --- a/src/SFML/Network/IpAddress.cpp +++ b/src/SFML/Network/IpAddress.cpp @@ -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::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((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3))) +m_address(htonl(static_cast((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::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(&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(&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::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& address) { std::string str; stream >> str; - address = IpAddress(str); + address = IpAddress::resolve(str); return stream; } diff --git a/src/SFML/Network/TcpListener.cpp b/src/SFML/Network/TcpListener.cpp index 6fd0c66c..8213070f 100644 --- a/src/SFML/Network/TcpListener.cpp +++ b/src/SFML/Network/TcpListener.cpp @@ -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 diff --git a/src/SFML/Network/TcpSocket.cpp b/src/SFML/Network/TcpSocket.cpp index f0414d96..69356250 100644 --- a/src/SFML/Network/TcpSocket.cpp +++ b/src/SFML/Network/TcpSocket.cpp @@ -79,7 +79,7 @@ unsigned short TcpSocket::getLocalPort() const //////////////////////////////////////////////////////////// -IpAddress TcpSocket::getRemoteAddress() const +std::optional 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; diff --git a/src/SFML/Network/UdpSocket.cpp b/src/SFML/Network/UdpSocket.cpp index d741e46e..4bf5713e 100644 --- a/src/SFML/Network/UdpSocket.cpp +++ b/src/SFML/Network/UdpSocket.cpp @@ -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& 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& remoteAddress, unsigned short& remotePort) { // See the detailed comment in send(Packet) above. diff --git a/test/Network/IpAddress.cpp b/test/Network/IpAddress.cpp index 5944063e..75803a64 100644 --- a/test/Network/IpAddress.cpp +++ b/test/Network/IpAddress.cpp @@ -3,78 +3,45 @@ #include #include +#include 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 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 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 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<<")