version 1.2.2.1, 2007/06/26 20:26:13
|
version 1.2.2.2, 2007/07/03 21:50:04
|
|
|
|
//%2007//////////////////////////////////////////////////////////////////////// |
|
// |
|
// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development |
|
// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems. |
|
// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation, The Open Group. |
|
// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.; |
|
// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; VERITAS Software Corporation; The Open Group. |
|
// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.; |
|
// EMC Corporation; Symantec Corporation; The Open Group. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a copy |
|
// of this software and associated documentation files (the "Software"), to |
|
// deal in the Software without restriction, including without limitation the |
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
|
// sell copies of the Software, and to permit persons to whom the Software is |
|
// furnished to do so, subject to the following conditions: |
|
// |
|
// THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN |
|
// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED |
|
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT |
|
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
// |
|
//============================================================================== |
|
// |
|
//%///////////////////////////////////////////////////////////////////////////// |
|
|
|
#include <Pegasus/Common/HostAddress.h> |
|
|
|
PEGASUS_NAMESPACE_BEGIN |
|
|
|
#if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6) |
|
|
|
/* |
|
Address conversion utility functions. |
|
*/ |
|
|
|
/* |
|
Converts given "src" text address (Ex: 127.0.0.1) to equivalent binary form |
|
and stores in "dst" buffer (Ex 0x7f000001). Returns 1 if given ipv4 address |
|
is valid or returns -1 if invalid. Returns value in network byte order. |
|
*/ |
|
|
|
static int _inet_ptonv4(const char *src, void *dst) |
|
{ |
|
Boolean isValid = true; |
|
Uint16 octetValue[4] = {0}; |
|
// Check for valid IPV4 address. |
|
for (Uint32 octet = 1, i = 0; octet <= 4; octet++) |
|
{ |
|
int j = 0; |
|
if (!(isascii(src[i]) && isdigit(src[i]))) |
|
{ |
|
isValid = false; |
|
break; |
|
} |
|
while (isascii(src[i]) && isdigit(src[i])) |
|
{ |
|
if (j == 3) |
|
{ |
|
isValid = false; |
|
break; |
|
} |
|
octetValue[octet-1] = octetValue[octet-1]*10 + (src[i] - '0'); |
|
i++; |
|
j++; |
|
} |
|
if (octetValue[octet-1] > 255) |
|
{ |
|
isValid = false; |
|
break; |
|
} |
|
// Check for invalid character in IP address |
|
if ((octet != 4) && (src[i++] != '.')) |
|
{ |
|
isValid = false; |
|
break; |
|
} |
|
// Check for the case where it's a valid host name that happens |
|
// to have 4 (or more) leading all-numeric host segments. |
|
if ((octet == 4) && (src[i] != ':') && |
|
src[i] != char(0)) |
|
{ |
|
isValid = false; |
|
break; |
|
} |
|
} |
|
if (!isValid) |
|
{ |
|
return 0; |
|
} |
|
|
|
// Return the value in network byte order. |
|
Uint32 value; |
|
value = octetValue[0]; |
|
value = (value << 8) + octetValue[1]; |
|
value = (value << 8) + octetValue[2]; |
|
value = (value << 8) + octetValue[3]; |
|
value = htonl(value); |
|
memcpy (dst, &value, sizeof(Uint32)); |
|
|
|
return 1; |
|
} |
|
|
|
/* |
|
Converts given ipv6 text address (ex. ::1) to binary form and stroes |
|
in "dst" buffer (ex. 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1). Returns 1 |
|
if src ipv6 address is valid or returns -1 if invalid. Returns value |
|
in network byte order. |
|
*/ |
|
static int _inet_ptonv6(const char *src, void *dst) |
|
{ |
|
int ccIndex = -1; |
|
int sNumber = 0; |
|
Uint16 sValues[8] = {0}; |
|
Boolean ipv4Mapped = false; |
|
|
|
while (*src && sNumber < 8) |
|
{ |
|
if (*src == ':') |
|
{ |
|
if (!*++src) |
|
{ |
|
return 0; |
|
} |
|
if (*src == ':') |
|
{ |
|
if (ccIndex != -1) |
|
{ |
|
return 0; |
|
} |
|
ccIndex = sNumber; |
|
if (!*++src) |
|
{ |
|
break; |
|
} |
|
} |
|
} |
|
if ((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src)) |
|
{ |
|
// Check for ipv4 compatible ipv6 or ipv4 mapped ipv6 addresses |
|
if(!strchr(src, ':') && strchr(src, '.')) |
|
{ |
|
if ( _inet_ptonv4 (src, sValues + sNumber) != 1) |
|
{ |
|
return 0; |
|
} |
|
sNumber += 2; |
|
ipv4Mapped = true; |
|
break; |
|
} |
|
int chars = 0; |
|
while (*src && *src != ':') |
|
{ |
|
if (chars++ == 4) |
|
{ |
|
return 0; |
|
} |
|
if (!((isalpha(*src) && tolower(*src) <= 'f') || isdigit(*src))) |
|
{ |
|
return 0; |
|
} |
|
sValues[sNumber] = sValues[sNumber] * 16 + |
|
(isdigit(*src) ? *src - '0' : (tolower(*src) - 'a' + 10)); |
|
++src; |
|
} |
|
sValues[sNumber] = htons(sValues[sNumber]); |
|
++sNumber; |
|
} |
|
else |
|
{ |
|
return 0; |
|
} |
|
} |
|
|
|
if ((!ipv4Mapped &&*src) || (ccIndex == -1 && sNumber < 8) || |
|
(ccIndex != -1 && sNumber == 8) ) |
|
{ |
|
return 0; |
|
} |
|
memset(dst, 0, PEGASUS_IN6_ADDR_SIZE); |
|
for (int i = 0, j = 0; i < 8 ; ++i) |
|
{ |
|
if (ccIndex == i) |
|
{ |
|
i += 7 - sNumber; |
|
} |
|
else |
|
{ |
|
memcpy ((char*) dst + i * 2, sValues + j++ , 2); |
|
} |
|
} |
|
return 1; |
|
} |
|
|
|
/* |
|
Converts given ipv4 address in binary form to text form. Ex. 0x7f000001 |
|
to 127.0.0.1. |
|
*/ |
|
static const char *_inet_ntopv4(const void *src, char *dst, Uint32 size) |
|
{ |
|
|
|
Uint32 n; |
|
|
|
memset(dst, 0, size); |
|
memcpy(&n, src, sizeof (Uint32)); |
|
n = ntohl(n); |
|
sprintf(dst, "%u.%u.%u.%u", n >> 24 & 0xFF , |
|
n >> 16 & 0xFF, n >> 8 & 0xFF, n & 0xFF); |
|
|
|
return dst; |
|
} |
|
|
|
/* |
|
Converts given ipv6 address in binary form to text form. Ex. |
|
0000000000000001 to ::1. |
|
*/ |
|
static const char *_inet_ntopv6(const void *src, char *dst, Uint32 size) |
|
{ |
|
|
|
Uint16 n[8]; |
|
int ccIndex = -1; |
|
int maxZeroCnt = 0; |
|
int zeroCnt = 0; |
|
int index = 0; |
|
|
|
memcpy (n, src, PEGASUS_IN6_ADDR_SIZE); |
|
memset(dst, 0, size); |
|
for (int i = 0; i < 8 ; ++i) |
|
{ |
|
if (n[i]) |
|
{ |
|
if (zeroCnt) |
|
{ |
|
if (zeroCnt > maxZeroCnt) |
|
{ |
|
ccIndex = index; |
|
maxZeroCnt = zeroCnt; |
|
} |
|
zeroCnt = index = 0; |
|
} |
|
n[i] = ntohs (n[i]); |
|
} |
|
else |
|
{ |
|
if(!zeroCnt++) |
|
{ |
|
if (ccIndex == -1) |
|
{ |
|
ccIndex = i; |
|
} |
|
index = i; |
|
} |
|
} |
|
} |
|
char tmp[50]; |
|
*dst = 0; |
|
zeroCnt = 0; |
|
|
|
for (int i = 0; i < 8 ; ++i) |
|
{ |
|
if (i == ccIndex) |
|
{ |
|
sprintf(tmp, "::"); |
|
while ( i < 8 && !n[i]) |
|
{ |
|
++i; |
|
++zeroCnt; |
|
} |
|
--i; |
|
} |
|
else |
|
{ |
|
Boolean mapped = false; |
|
if (ccIndex == 0 && zeroCnt > 4) |
|
{ |
|
// check for ipv4 mapped ipv6 and ipv4 compatible ipv6 |
|
// addresses. |
|
if (zeroCnt == 5 && n[i] == 0xffff) |
|
{ |
|
strcat(dst,"ffff:"); |
|
mapped = true; |
|
} |
|
else if (zeroCnt == 6 && n[6]) |
|
{ |
|
mapped = true; |
|
} |
|
} |
|
if (mapped) |
|
{ |
|
Uint32 m; |
|
m = htons(n[7]); |
|
m = (m << 16) + htons(n[6]); |
|
HostAddress::convertBinaryToText(AF_INET, &m, tmp, 50); |
|
i += 2; |
|
} |
|
else |
|
{ |
|
sprintf(tmp, i < 7 && ccIndex != i + 1 ? "%x:" : "%x", n[i]); |
|
} |
|
} |
|
strcat(dst,tmp); |
|
} |
|
|
|
return dst; |
|
} |
|
#endif // defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6) |
|
|
|
void HostAddress::_init() |
|
{ |
|
_hostAddrStr = String::EMPTY; |
|
_isValid = false; |
|
_addrType = AT_INVALID; |
|
} |
|
|
|
HostAddress::HostAddress() |
|
{ |
|
_init(); |
|
} |
|
|
|
HostAddress::HostAddress(const String &addrStr) |
|
{ |
|
_init(); |
|
_hostAddrStr = addrStr; |
|
_parseAddress(); |
|
} |
|
|
|
HostAddress& HostAddress::operator =(const HostAddress &rhs) |
|
{ |
|
if (this != &rhs) |
|
{ |
|
_hostAddrStr = rhs._hostAddrStr; |
|
_isValid = rhs._isValid; |
|
_addrType = rhs._addrType; |
|
} |
|
|
|
return *this; |
|
} |
|
|
|
HostAddress::HostAddress(const HostAddress &rhs) |
|
{ |
|
*this = rhs; |
|
} |
|
|
|
HostAddress::~HostAddress() |
|
{ |
|
} |
|
|
|
void HostAddress::setHostAddress(const String &addrStr) |
|
{ |
|
_init(); |
|
_hostAddrStr = addrStr; |
|
_parseAddress(); |
|
} |
|
|
|
Uint32 HostAddress::getAddressType() |
|
{ |
|
return _addrType; |
|
} |
|
|
|
Boolean HostAddress::isValid() |
|
{ |
|
return _isValid; |
|
} |
|
|
|
String HostAddress::getHost() |
|
{ |
|
return _hostAddrStr; |
|
} |
|
|
|
Boolean HostAddress::equal(int af, void *p1, void *p2) |
|
{ |
|
switch (af) |
|
{ |
|
case AT_IPV6: |
|
return !memcmp(p1, p2, PEGASUS_IN6_ADDR_SIZE); |
|
case AT_IPV4: |
|
return !memcmp(p1, p2, sizeof(struct in_addr)); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void HostAddress::_parseAddress() |
|
{ |
|
if (_hostAddrStr == String::EMPTY) |
|
{ |
|
return; |
|
} |
|
if ((_isValid = isValidIPV6Address(_hostAddrStr))) |
|
{ |
|
_addrType = AT_IPV6; |
|
} |
|
else if( (_isValid = isValidIPV4Address(_hostAddrStr))) |
|
{ |
|
_addrType = AT_IPV4; |
|
} |
|
else if((_isValid = isValidHostName(_hostAddrStr))) |
|
{ |
|
_addrType = AT_HOSTNAME; |
|
} |
|
} |
|
|
|
Boolean HostAddress::isValidIPV6Address (const String &ipv6Address) |
|
{ |
|
int i = 0; |
|
while (ipv6Address[i]) |
|
{ |
|
if (!isascii(ipv6Address[i++])) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
CString addr = ipv6Address.getCString(); |
|
#ifdef PEGASUS_ENABLE_IPV6 |
|
struct in6_addr iaddr; |
|
#else |
|
char iaddr[PEGASUS_IN6_ADDR_SIZE]; |
|
#endif |
|
return 1 == convertTextToBinary(AT_IPV6, (const char*) addr, |
|
(void*)&iaddr); |
|
} |
|
|
|
Boolean HostAddress::isValidIPV4Address (const String &ipv4Address) |
|
{ |
|
int i = 0; |
|
while (ipv4Address[i]) |
|
{ |
|
if (!isascii(ipv4Address[i++])) |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
CString addr = ipv4Address.getCString(); |
|
struct in_addr iaddr; |
|
|
|
return 1 == convertTextToBinary(AT_IPV4, (const char*) addr, |
|
(void*)&iaddr); |
|
} |
|
|
|
Boolean HostAddress::isValidHostName (const String &hostName) |
|
{ |
|
Uint32 i = 0; |
|
Boolean expectHostSegment = true; |
|
Boolean hostSegmentIsNumeric; |
|
while (expectHostSegment) |
|
{ |
|
expectHostSegment = false; |
|
hostSegmentIsNumeric = true; // assume all-numeric host segment |
|
if (!(isascii(hostName[i]) && |
|
(isalnum(hostName[i]) || (hostName[i] == '_')))) |
|
{ |
|
return false; |
|
} |
|
while (isascii(hostName[i]) && |
|
(isalnum(hostName[i]) || (hostName[i] == '-') || |
|
(hostName[i] == '_'))) |
|
{ |
|
// If a non-digit is encountered, set "all-numeric" |
|
// flag to false |
|
if (isalpha(hostName[i]) || (hostName[i] == '-') || |
|
(hostName[i] == '_')) |
|
{ |
|
hostSegmentIsNumeric = false; |
|
} |
|
i++; |
|
} |
|
if (hostName[i] == '.') |
|
{ |
|
i++; |
|
expectHostSegment = true; |
|
} |
|
} |
|
// If the last Host Segment is all numeric, then return false. |
|
// RFC 1123 says "highest-level component label will be alphabetic". |
|
if (hostSegmentIsNumeric || hostName[i] != char(0)) |
|
{ |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
int HostAddress::convertTextToBinary(int af, const char *src, void *dst) |
|
{ |
|
#if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6) |
|
if (af == AT_IPV4) |
|
{ |
|
return _inet_ptonv4(src, dst); |
|
} |
|
else if(af == AT_IPV6) |
|
{ |
|
return _inet_ptonv6(src, dst); |
|
} |
|
return -1; // Unsupported address family. |
|
#else |
|
return ::inet_pton(af, src, dst); |
|
#endif |
|
} |
|
|
|
const char * HostAddress::convertBinaryToText(int af, const void *src, |
|
char *dst, Uint32 size) |
|
{ |
|
#if defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6) |
|
if (af == AT_IPV6) |
|
{ |
|
return _inet_ntopv6(src, dst, size); |
|
} |
|
else if (af == AT_IPV4) |
|
{ |
|
return _inet_ntopv4(src, dst, size); |
|
} |
|
return 0; // Unsupported address family. |
|
#else |
|
return ::inet_ntop(af, src, dst, size); |
|
#endif |
|
} |
|
|
|
PEGASUS_NAMESPACE_END |