Fixed: Implements IPv6 in CInetAddress
This commit is contained in:
parent
0995ae0622
commit
7aaf71582e
2 changed files with 173 additions and 45 deletions
|
@ -24,7 +24,9 @@
|
|||
|
||||
|
||||
struct sockaddr_in;
|
||||
struct sockaddr_in6;
|
||||
struct in_addr;
|
||||
struct in6_addr;
|
||||
|
||||
|
||||
#ifdef NL_OS_WINDOWS
|
||||
|
@ -89,17 +91,25 @@ public:
|
|||
/// Sets hostname and port (ex: www.nevrax.com:80)
|
||||
void setNameAndPort( const std::string& hostNameAndPort );
|
||||
|
||||
/** Sets internal socket address directly (contents is copied).
|
||||
/** Sets internal IPv4 socket address directly (contents is copied).
|
||||
* It also retrieves the host name if CInetAddress::RetrieveNames is true.
|
||||
*/
|
||||
void setSockAddr( const sockaddr_in* saddr );
|
||||
|
||||
/** Sets internal IPv6 socket address directly (contents is copied).
|
||||
* It also retrieves the host name if CInetAddress::RetrieveNames is true.
|
||||
*/
|
||||
void setSockAddr6( const sockaddr_in6* saddr6 );
|
||||
|
||||
/// Returns if object (address and port) is valid
|
||||
bool isValid() const;
|
||||
|
||||
/// Returns internal socket address (read only)
|
||||
/// Returns internal IPv4 socket address (read only)
|
||||
const sockaddr_in *sockAddr() const;
|
||||
|
||||
/// Returns internal IPv6 socket address (read only)
|
||||
const sockaddr_in6 *sockAddr6() const;
|
||||
|
||||
/// Returns internal IP address
|
||||
uint32 internalIPAddress() const;
|
||||
|
||||
|
@ -140,9 +150,12 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
/// Constructor with ip address, port=0
|
||||
/// Constructor with IPv4 address, port=0
|
||||
CInetAddress( const in_addr *ip, const char *hostname = 0);
|
||||
|
||||
/// Constructor with IPv6 address, port=0
|
||||
CInetAddress( const in6_addr *ip, const char *hostname = 0);
|
||||
|
||||
/// Update _HostName from _SockAddr
|
||||
void updateHostName();
|
||||
|
||||
|
@ -153,6 +166,7 @@ private:
|
|||
|
||||
std::string _HostName;
|
||||
sockaddr_in *_SockAddr;
|
||||
sockaddr_in6 *_SockAddr6;
|
||||
bool _Valid;
|
||||
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#ifdef NL_OS_WINDOWS
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# include <ws2ipdef.h>
|
||||
// for Windows 2000 compatibility
|
||||
# include <wspiapi.h>
|
||||
#elif defined NL_OS_UNIX
|
||||
|
@ -58,20 +59,32 @@ bool CInetAddress::RetrieveNames = false;
|
|||
CInetAddress::CInetAddress()
|
||||
{
|
||||
init();
|
||||
|
||||
// IPv4
|
||||
_SockAddr->sin_port = 0; // same as htons(0)
|
||||
memset( &_SockAddr->sin_addr, 0, sizeof(in_addr) ); // same as htonl(INADDR_ANY)
|
||||
|
||||
// IPv6
|
||||
_SockAddr6->sin6_port = 0;
|
||||
memset( &_SockAddr6->sin6_addr, 0, sizeof(in6_addr) ); // same as htonl(INADDR_ANY)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Constructor with ip address, port=0
|
||||
* Constructor with IPv4 address, port=0
|
||||
*/
|
||||
CInetAddress::CInetAddress( const in_addr *ip, const char *hostname )
|
||||
{
|
||||
init();
|
||||
|
||||
// IPv4
|
||||
_SockAddr->sin_port = 0;
|
||||
memcpy( &_SockAddr->sin_addr, ip, sizeof(in_addr) );
|
||||
|
||||
// invalid IPv6
|
||||
_SockAddr6->sin6_port = 0;
|
||||
memset( &_SockAddr6->sin6_addr, 0, sizeof(in6_addr) );
|
||||
|
||||
// get the host name to be displayed
|
||||
if(hostname)
|
||||
{
|
||||
|
@ -81,6 +94,36 @@ CInetAddress::CInetAddress( const in_addr *ip, const char *hostname )
|
|||
{
|
||||
updateHostName();
|
||||
}
|
||||
|
||||
_Valid = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Constructor with IPv6 address, port=0
|
||||
*/
|
||||
CInetAddress::CInetAddress( const in6_addr *ip, const char *hostname )
|
||||
{
|
||||
init();
|
||||
|
||||
// IPv6
|
||||
_SockAddr6->sin6_port = 0;
|
||||
memcpy( &_SockAddr6->sin6_addr, ip, sizeof(in6_addr) );
|
||||
|
||||
// invalid IPv4
|
||||
_SockAddr->sin_port = 0;
|
||||
memset( &_SockAddr->sin_addr, 0, sizeof(in_addr) );
|
||||
|
||||
// get the host name to be displayed
|
||||
if(hostname)
|
||||
{
|
||||
_HostName = hostname;
|
||||
}
|
||||
else
|
||||
{
|
||||
updateHostName();
|
||||
}
|
||||
|
||||
_Valid = true;
|
||||
}
|
||||
|
||||
|
@ -92,7 +135,20 @@ void CInetAddress::updateHostName()
|
|||
{
|
||||
char host[NI_MAXHOST];
|
||||
|
||||
sint status = getnameinfo((struct sockaddr *) _SockAddr, sizeof (struct sockaddr), host, NI_MAXHOST, NULL, 0, NI_NUMERICSERV);
|
||||
// if unable to resolve DNS, returns an error and use IP address instead
|
||||
sint status = 1;
|
||||
|
||||
// check if IPv4 is valid
|
||||
if (_SockAddr->sin_addr.s_addr != 0)
|
||||
{
|
||||
// IPv4
|
||||
status = getnameinfo((struct sockaddr *) _SockAddr, sizeof (sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICSERV | NI_NAMEREQD);
|
||||
}
|
||||
else if (!IN6_IS_ADDR_UNSPECIFIED(&_SockAddr6->sin6_addr))
|
||||
{
|
||||
// IPv6
|
||||
status = getnameinfo((struct sockaddr *) _SockAddr6, sizeof (sockaddr_in6), host, NI_MAXHOST, NULL, 0, NI_NUMERICSERV | NI_NAMEREQD);
|
||||
}
|
||||
|
||||
if ( status )
|
||||
{
|
||||
|
@ -134,6 +190,7 @@ CInetAddress::CInetAddress( const CInetAddress& other )
|
|||
init();
|
||||
_HostName = other._HostName;
|
||||
memcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) );
|
||||
memcpy( _SockAddr6, other._SockAddr6, sizeof( *_SockAddr6 ) );
|
||||
_Valid = other._Valid;
|
||||
}
|
||||
|
||||
|
@ -145,6 +202,7 @@ CInetAddress& CInetAddress::operator=( const CInetAddress& other )
|
|||
{
|
||||
_HostName = other._HostName;
|
||||
memcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) );
|
||||
memcpy( _SockAddr6, other._SockAddr6, sizeof( *_SockAddr6 ) );
|
||||
_Valid = other._Valid;
|
||||
return *this;
|
||||
}
|
||||
|
@ -185,9 +243,15 @@ void CInetAddress::init()
|
|||
|
||||
_Valid = false;
|
||||
|
||||
// IPv4
|
||||
_SockAddr = new sockaddr_in;
|
||||
memset(_SockAddr, 0, sizeof(_SockAddr));
|
||||
_SockAddr->sin_family = AF_INET;
|
||||
memset( _SockAddr->sin_zero, 0, 8 );
|
||||
|
||||
// IPv6
|
||||
_SockAddr6 = new sockaddr_in6;
|
||||
memset(_SockAddr6, 0, sizeof(_SockAddr6));
|
||||
_SockAddr6->sin6_family = AF_INET6;
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,6 +261,7 @@ void CInetAddress::init()
|
|||
CInetAddress::~CInetAddress()
|
||||
{
|
||||
delete _SockAddr;
|
||||
delete _SockAddr6;
|
||||
// _Valid = false;
|
||||
}
|
||||
|
||||
|
@ -225,12 +290,41 @@ void CInetAddress::setNameAndPort( const std::string& hostNameAndPort )
|
|||
/*
|
||||
* Resolves a name
|
||||
*/
|
||||
CInetAddress& CInetAddress::setByName( const std::string& hostName )
|
||||
CInetAddress& CInetAddress::setByName(const std::string& hostName)
|
||||
{
|
||||
// Try to convert directly for addresses such as a.b.c.d
|
||||
in_addr iaddr;
|
||||
iaddr.s_addr = inet_addr( hostName.c_str() );
|
||||
if ( iaddr.s_addr == INADDR_NONE )
|
||||
// invalid IPv4
|
||||
memset(&_SockAddr->sin_addr, 0, sizeof(in_addr));
|
||||
|
||||
// invalid IPv6
|
||||
memset(&_SockAddr6->sin6_addr, 0, sizeof(in6_addr));
|
||||
|
||||
// Try to convert directly for addresses such as a.b.c.d and a:b:c:d:e:f:g:h
|
||||
in_addr ipv4;
|
||||
sint res = inet_pton(AF_INET, hostName.c_str(), &ipv4);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
// hostname is a valid IPv4
|
||||
memcpy(&_SockAddr->sin_addr, &ipv4, sizeof(in_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
in6_addr ipv6;
|
||||
res = inet_pton(AF_INET6, hostName.c_str(), &ipv6);
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
// hostname is a valid IPv6
|
||||
memcpy(&_SockAddr6->sin6_addr, &ipv6, sizeof(in6_addr));
|
||||
}
|
||||
}
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
// use IPv4 or IPv6 as hostname
|
||||
_HostName = hostName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise use the traditional DNS look-up
|
||||
struct addrinfo hints;
|
||||
|
@ -249,6 +343,9 @@ CInetAddress& CInetAddress::setByName( const std::string& hostName )
|
|||
throw ESocket( (string("Hostname resolution failed for ")+hostName).c_str() );
|
||||
}
|
||||
|
||||
// hostname is valid, use it
|
||||
_HostName = hostName;
|
||||
|
||||
struct addrinfo *p = res;
|
||||
|
||||
// process all addresses
|
||||
|
@ -260,20 +357,14 @@ CInetAddress& CInetAddress::setByName( const std::string& hostName )
|
|||
// ipv4
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
|
||||
// convert the IP to a string
|
||||
_HostName = string(inet_ntoa(ipv4->sin_addr));
|
||||
memcpy( &_SockAddr->sin_addr, &ipv4->sin_addr, sizeof(in_addr) );
|
||||
}
|
||||
else if (p->ai_family == AF_INET6)
|
||||
{
|
||||
// ipv6
|
||||
// TODO: modify class to be able to handle IPv6
|
||||
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
|
||||
// struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
|
||||
// convert the IP to a string
|
||||
// inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
|
||||
// memcpy( &_SockAddr->sin_addr, &ipv6->sin_addr, sizeof(in_addr) );
|
||||
memcpy( &_SockAddr6->sin6_addr, &ipv6->sin6_addr, sizeof(in6_addr) );
|
||||
}
|
||||
|
||||
// process next address
|
||||
|
@ -283,11 +374,7 @@ CInetAddress& CInetAddress::setByName( const std::string& hostName )
|
|||
// free the linked list
|
||||
freeaddrinfo(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
_HostName = hostName;
|
||||
memcpy( &_SockAddr->sin_addr, &iaddr, sizeof(iaddr) );
|
||||
}
|
||||
|
||||
_Valid = true;
|
||||
return *this;
|
||||
}
|
||||
|
@ -296,10 +383,10 @@ CInetAddress& CInetAddress::setByName( const std::string& hostName )
|
|||
/*
|
||||
* Sets port
|
||||
*/
|
||||
void CInetAddress::setPort( uint16 port )
|
||||
void CInetAddress::setPort(uint16 port)
|
||||
{
|
||||
_SockAddr->sin_port = htons( port );
|
||||
|
||||
_SockAddr->sin_port = htons(port);
|
||||
_SockAddr6->sin6_port = htons(port);
|
||||
}
|
||||
|
||||
|
||||
|
@ -308,7 +395,10 @@ void CInetAddress::setPort( uint16 port )
|
|||
*/
|
||||
void CInetAddress::setSockAddr( const sockaddr_in* saddr )
|
||||
{
|
||||
memcpy( _SockAddr, saddr, sizeof(*saddr) );
|
||||
memcpy(_SockAddr, saddr, sizeof(*saddr) );
|
||||
|
||||
// invalid IPv6
|
||||
memset(&_SockAddr6->sin6_addr, 0, sizeof(in6_addr));
|
||||
|
||||
// Get host name
|
||||
// Warning: when it can't find it, it take more than 4 seconds
|
||||
|
@ -316,6 +406,28 @@ void CInetAddress::setSockAddr( const sockaddr_in* saddr )
|
|||
{
|
||||
updateHostName();
|
||||
}
|
||||
|
||||
_Valid = true;
|
||||
}
|
||||
|
||||
|
||||
/* Sets internal socket address directly (contents is copied).
|
||||
* It also retrieves the host name if CInetAddress::RetrieveNames is true.
|
||||
*/
|
||||
void CInetAddress::setSockAddr6( const sockaddr_in6* saddr6 )
|
||||
{
|
||||
memcpy( _SockAddr6, saddr6, sizeof(*saddr6) );
|
||||
|
||||
// invalid IPv4
|
||||
memset(&_SockAddr->sin_addr, 0, sizeof(in_addr));
|
||||
|
||||
// Get host name
|
||||
// Warning: when it can't find it, it take more than 4 seconds
|
||||
if ( CInetAddress::RetrieveNames )
|
||||
{
|
||||
updateHostName();
|
||||
}
|
||||
|
||||
_Valid = true;
|
||||
}
|
||||
|
||||
|
@ -330,7 +442,7 @@ bool CInetAddress::isValid() const
|
|||
|
||||
|
||||
/*
|
||||
* Returns internal socket address (read only)
|
||||
* Returns internal IPv4 socket address (read only)
|
||||
*/
|
||||
const sockaddr_in *CInetAddress::sockAddr() const
|
||||
{
|
||||
|
@ -338,6 +450,15 @@ const sockaddr_in *CInetAddress::sockAddr() const
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns internal IPv6 socket address (read only)
|
||||
*/
|
||||
const sockaddr_in6 *CInetAddress::sockAddr6() const
|
||||
{
|
||||
return _SockAddr6;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns internal IP address
|
||||
*/
|
||||
|
@ -383,10 +504,13 @@ uint32 CInetAddress::internalNetAddress() const
|
|||
*/
|
||||
string CInetAddress::ipAddress() const
|
||||
{
|
||||
/*stringstream ss; // or use inet_ntoa
|
||||
ss << inet_ntoa ( _SockAddr->sin_addr );
|
||||
return ss.str();*/
|
||||
const char *name = inet_ntoa ( _SockAddr->sin_addr );
|
||||
// longer size is IPv6
|
||||
char straddr[INET6_ADDRSTRLEN];
|
||||
const char *name = inet_ntop(AF_INET, &_SockAddr->sin_addr, straddr, INET_ADDRSTRLEN);
|
||||
|
||||
// IPv4 is invalid, return IPv6
|
||||
if (name == NULL || strcmp(name, "0.0.0.0") == 0) name = inet_ntop(AF_INET6, &_SockAddr6->sin6_addr, straddr, INET6_ADDRSTRLEN);
|
||||
|
||||
return name ? string (name) : "";
|
||||
}
|
||||
|
||||
|
@ -414,9 +538,6 @@ uint16 CInetAddress::port() const
|
|||
*/
|
||||
std::string CInetAddress::asString() const
|
||||
{
|
||||
// stringstream ss;
|
||||
// ss << hostName() << ":" << port() << " (" << ipAddress() << ")";
|
||||
// return ss.str();
|
||||
return hostName() + ":" + NLMISC::toString(port()) + " (" + ipAddress() + ")";
|
||||
}
|
||||
|
||||
|
@ -426,9 +547,6 @@ std::string CInetAddress::asString() const
|
|||
*/
|
||||
std::string CInetAddress::asIPString() const
|
||||
{
|
||||
// stringstream ss;
|
||||
// ss << ipAddress() << ":" << port();
|
||||
// return ss.str();
|
||||
return ipAddress() + ":" + NLMISC::toString(port());
|
||||
}
|
||||
|
||||
|
@ -537,13 +655,9 @@ std::vector<CInetAddress> CInetAddress::localAddresses()
|
|||
else if (p->ai_family == AF_INET6)
|
||||
{
|
||||
// ipv6
|
||||
// TODO: modify class to be able to handle IPv6
|
||||
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
|
||||
// struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
|
||||
// convert the IP to a string
|
||||
// inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
|
||||
// memcpy( &_SockAddr->sin_addr, &ipv6->sin_addr, sizeof(in_addr) );
|
||||
vect.push_back( CInetAddress( &ipv6->sin6_addr, localhost ) );
|
||||
}
|
||||
|
||||
// process next address
|
||||
|
|
Loading…
Reference in a new issue