diff --git a/include/SFML/Network/IpAddress.hpp b/include/SFML/Network/IpAddress.hpp index 8205e9f4..5d9c8e8d 100644 --- a/include/SFML/Network/IpAddress.hpp +++ b/include/SFML/Network/IpAddress.hpp @@ -99,7 +99,7 @@ public: /// This constructor uses the internal representation of /// the address directly. It should be used for optimization /// purposes, and only if you got that representation from - /// IpAddress::ToInteger(). + /// IpAddress::toInteger(). /// /// \param address 4 bytes of the address packed into a 32-bits integer /// @@ -182,15 +182,27 @@ public: // 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) private: + friend SFML_NETWORK_API bool operator <(const IpAddress& left, const IpAddress& right); + + //////////////////////////////////////////////////////////// + /// \brief Resolve the given address string + /// + /// \param address Address string + /// + //////////////////////////////////////////////////////////// + void resolve(const std::string& address); + //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// Uint32 m_address; ///< Address stored as an unsigned 32 bits integer + bool m_valid; ///< Is the address valid? }; //////////////////////////////////////////////////////////// diff --git a/include/SFML/Network/TcpListener.hpp b/include/SFML/Network/TcpListener.hpp index a46ef293..b9d14acf 100644 --- a/include/SFML/Network/TcpListener.hpp +++ b/include/SFML/Network/TcpListener.hpp @@ -30,6 +30,7 @@ //////////////////////////////////////////////////////////// #include #include +#include namespace sf @@ -71,14 +72,15 @@ public: /// If the socket was previously listening to another port, /// it will be stopped first and bound to the new port. /// - /// \param port Port to listen for new connections + /// \param port Port to listen for new connections + /// \param address Address of the interface to listen on /// /// \return Status code /// /// \see accept, close /// //////////////////////////////////////////////////////////// - Status listen(unsigned short port); + Status listen(unsigned short port, const IpAddress& address = IpAddress::Any); //////////////////////////////////////////////////////////// /// \brief Stop listening and close the socket diff --git a/include/SFML/Network/UdpSocket.hpp b/include/SFML/Network/UdpSocket.hpp index f00c257d..f4b69dcb 100644 --- a/include/SFML/Network/UdpSocket.hpp +++ b/include/SFML/Network/UdpSocket.hpp @@ -30,12 +30,12 @@ //////////////////////////////////////////////////////////// #include #include +#include #include namespace sf { -class IpAddress; class Packet; //////////////////////////////////////////////////////////// @@ -82,14 +82,15 @@ public: /// system to automatically pick an available port, and then /// call getLocalPort to retrieve the chosen port. /// - /// \param port Port to bind the socket to + /// \param port Port to bind the socket to + /// \param address Address of the interface to bind to /// /// \return Status code /// /// \see unbind, getLocalPort /// //////////////////////////////////////////////////////////// - Status bind(unsigned short port); + Status bind(unsigned short port, const IpAddress& address = IpAddress::Any); //////////////////////////////////////////////////////////// /// \brief Unbind the socket from the local port to which it is bound diff --git a/src/SFML/Network/IpAddress.cpp b/src/SFML/Network/IpAddress.cpp index 19f08403..e2beead2 100644 --- a/src/SFML/Network/IpAddress.cpp +++ b/src/SFML/Network/IpAddress.cpp @@ -29,89 +29,56 @@ #include #include #include - - -namespace -{ - sf::Uint32 resolve(const std::string& address) - { - if (address == "255.255.255.255") - { - // The broadcast address needs to be handled explicitly, - // because it is also the value returned by inet_addr on error - return INADDR_BROADCAST; - } - else - { - // 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) - return ip; - - // Not a valid address, try to convert it as a host name - addrinfo hints; - std::memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - addrinfo* result = NULL; - if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0) - { - if (result) - { - ip = reinterpret_cast(result->ai_addr)->sin_addr.s_addr; - freeaddrinfo(result); - return ip; - } - } - - // Not a valid address nor a host name - return 0; - } - } -} +#include 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() : -m_address(0) +m_address(0), +m_valid (false) { - // We're using 0 (INADDR_ANY) instead of INADDR_NONE to represent the invalid address, - // because the latter is also the broadcast address (255.255.255.255); it's ok because - // SFML doesn't publicly use INADDR_ANY (it is always used implicitly) } //////////////////////////////////////////////////////////// IpAddress::IpAddress(const std::string& address) : -m_address(resolve(address)) +m_address(0), +m_valid (false) { + resolve(address); } //////////////////////////////////////////////////////////// IpAddress::IpAddress(const char* address) : -m_address(resolve(address)) +m_address(0), +m_valid (false) { + resolve(address); } //////////////////////////////////////////////////////////// IpAddress::IpAddress(Uint8 byte0, Uint8 byte1, Uint8 byte2, Uint8 byte3) : -m_address(htonl((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3)) +m_address(htonl((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3)), +m_valid (true) { } //////////////////////////////////////////////////////////// IpAddress::IpAddress(Uint32 address) : -m_address(htonl(address)) +m_address(htonl(address)), +m_valid (true) { } @@ -193,10 +160,59 @@ IpAddress IpAddress::getPublicAddress(Time timeout) } +//////////////////////////////////////////////////////////// +void IpAddress::resolve(const std::string& address) +{ + m_address = 0; + m_valid = false; + + if (address == "255.255.255.255") + { + // The broadcast address needs to be handled explicitly, + // because it is also the value returned by inet_addr on error + m_address = INADDR_BROADCAST; + m_valid = true; + } + else if (address == "0.0.0.0") + { + m_address = INADDR_ANY; + m_valid = true; + } + else + { + // Try to convert the address as a byte representation ("xxx.xxx.xxx.xxx") + Uint32 ip = inet_addr(address.c_str()); + if (ip != INADDR_NONE) + { + m_address = ip; + m_valid = true; + } + else + { + // Not a valid address, try to convert it as a host name + addrinfo hints; + std::memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + addrinfo* result = NULL; + if (getaddrinfo(address.c_str(), NULL, &hints, &result) == 0) + { + if (result) + { + ip = reinterpret_cast(result->ai_addr)->sin_addr.s_addr; + freeaddrinfo(result); + m_address = ip; + m_valid = true; + } + } + } + } +} + + //////////////////////////////////////////////////////////// bool operator ==(const IpAddress& left, const IpAddress& right) { - return left.toInteger() == right.toInteger(); + return !(left < right) && !(right < left); } @@ -210,7 +226,7 @@ bool operator !=(const IpAddress& left, const IpAddress& right) //////////////////////////////////////////////////////////// bool operator <(const IpAddress& left, const IpAddress& right) { - return left.toInteger() < right.toInteger(); + return std::make_pair(left.m_valid, left.m_address) < std::make_pair(right.m_valid, right.m_address); } diff --git a/src/SFML/Network/TcpListener.cpp b/src/SFML/Network/TcpListener.cpp index 7a68707f..451b85e1 100644 --- a/src/SFML/Network/TcpListener.cpp +++ b/src/SFML/Network/TcpListener.cpp @@ -61,14 +61,18 @@ unsigned short TcpListener::getLocalPort() const //////////////////////////////////////////////////////////// -Socket::Status TcpListener::listen(unsigned short port) +Socket::Status TcpListener::listen(unsigned short port, const IpAddress& address) { // Create the internal socket if it doesn't exist create(); + // Check if the address is valid + if ((address == IpAddress::None) || (address == IpAddress::Broadcast)) + return Error; + // Bind the socket to the specified port - sockaddr_in address = priv::SocketImpl::createAddress(INADDR_ANY, port); - if (bind(getHandle(), reinterpret_cast(&address), sizeof(address)) == -1) + sockaddr_in addr = priv::SocketImpl::createAddress(address.toInteger(), port); + if (bind(getHandle(), reinterpret_cast(&addr), sizeof(addr)) == -1) { // Not likely to happen, but... err() << "Failed to bind listener socket to port " << port << std::endl; diff --git a/src/SFML/Network/UdpSocket.cpp b/src/SFML/Network/UdpSocket.cpp index ffa14949..5bb1ff47 100644 --- a/src/SFML/Network/UdpSocket.cpp +++ b/src/SFML/Network/UdpSocket.cpp @@ -64,14 +64,18 @@ unsigned short UdpSocket::getLocalPort() const //////////////////////////////////////////////////////////// -Socket::Status UdpSocket::bind(unsigned short port) +Socket::Status UdpSocket::bind(unsigned short port, const IpAddress& address) { // Create the internal socket if it doesn't exist create(); + // Check if the address is valid + if ((address == IpAddress::None) || (address == IpAddress::Broadcast)) + return Error; + // Bind the socket - sockaddr_in address = priv::SocketImpl::createAddress(INADDR_ANY, port); - if (::bind(getHandle(), reinterpret_cast(&address), sizeof(address)) == -1) + sockaddr_in addr = priv::SocketImpl::createAddress(address.toInteger(), port); + if (::bind(getHandle(), reinterpret_cast(&addr), sizeof(addr)) == -1) { err() << "Failed to bind socket to port " << port << std::endl; return Error;