Added optional argument on which address to bind (socket).

This commit is contained in:
bumbar1 2014-08-09 13:28:25 +02:00 committed by Lukas Dürrenberger
parent 6b9781475d
commit 3a12fc6505
6 changed files with 100 additions and 61 deletions

View file

@ -29,89 +29,56 @@
#include <SFML/Network/Http.hpp>
#include <SFML/Network/SocketImpl.hpp>
#include <cstring>
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<sockaddr_in*>(result->ai_addr)->sin_addr.s_addr;
freeaddrinfo(result);
return ip;
}
}
// Not a valid address nor a host name
return 0;
}
}
}
#include <utility>
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<sockaddr_in*>(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);
}

View file

@ -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<sockaddr*>(&address), sizeof(address)) == -1)
sockaddr_in addr = priv::SocketImpl::createAddress(address.toInteger(), port);
if (bind(getHandle(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
{
// Not likely to happen, but...
err() << "Failed to bind listener socket to port " << port << std::endl;

View file

@ -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<sockaddr*>(&address), sizeof(address)) == -1)
sockaddr_in addr = priv::SocketImpl::createAddress(address.toInteger(), port);
if (::bind(getHandle(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1)
{
err() << "Failed to bind socket to port " << port << std::endl;
return Error;