(file) Return to HostAddress.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

File: [Pegasus] / pegasus / src / Pegasus / Common / HostAddress.cpp (download)
Revision: 1.1.2.2, Tue Jun 12 08:31:58 2007 UTC (17 years ago) by venkat.puvvada
Changes since 1.1.2.1: +24 -20 lines
PEP#: 291
TITLE: OpenPegasus Support for IPv6: Stage 1

//%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

#ifdef PEGASUS_OS_VMS
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; 
#endif

#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;
}

#ifdef PEGASUS_ENABLE_IPV6
/*
     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, sizeof(struct in6_addr));

    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;
}
#endif

/*
    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; 
}

#ifdef PEGASUS_ENABLE_IPV6
/*  
    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, sizeof (struct in6_addr));
    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   
#endif  // defined (PEGASUS_OS_TYPE_WINDOWS) || !defined (PEGASUS_ENABLE_IPV6)

void HostAddress::_init()
{
    _hostAddress = String::EMPTY;
    _hostAddrStr = String::EMPTY;
    _portNumber = PORT_UNSPECIFIED;
    _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)
    {
        _hostAddress = rhs._hostAddress;
        _hostAddrStr = rhs._hostAddrStr;
        _portNumber = rhs._portNumber;
        _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::getPort()
{
    return _portNumber;
}

String HostAddress::getPortString()
{
    char portStr[10];
    sprintf(portStr, "%u", _portNumber);
    return String(portStr);
}

Uint32 HostAddress::getAddressType()
{
    return _addrType;
}

Boolean HostAddress::isValid()
{
    return _isValid;
}

String HostAddress::getHost()
{
    return _hostAddress;
}

Boolean HostAddress::isPortSpecified()
{
    return _portNumber != PORT_UNSPECIFIED && _portNumber != PORT_INVALID;
}

Boolean HostAddress::equal(int af, void *p1, void *p2)
{
    switch (af)
    {
#ifdef PEGASUS_ENABLE_IPV6
        case AF_INET6:
             return !memcmp(p1, p2, sizeof(struct in6_addr));
#endif
        case AF_INET:
             return !memcmp(p1, p2, sizeof(struct in_addr));
    }    

    return false;
}

void HostAddress::_parseAddress()
{
    if (_hostAddrStr == String::EMPTY)
    {
        _isValid = false;
        return;
    }
    Uint32 i = 0;
#ifdef PEGASUS_ENABLE_IPV6        
    if (_hostAddrStr[0] == '[')
    {   
        i = 1;
        while (_hostAddrStr[i] && _hostAddrStr[i] != ']')
        {
            ++i;
        }
        if (_hostAddrStr[i] == ']')
        {
            _hostAddress = _hostAddrStr.subString (1, i - 1);
            if( !(_isValid = isValidIPV6Address(_hostAddress)))
            {
                return;
            }
            _addrType = AT_IPV6;
            ++i;
        } 
        else 
        {
            _hostAddress = _hostAddrStr;
            return;
        }
    }
    else if ((_isValid = isValidIPV6Address(_hostAddrStr)))
    {
        _addrType = AT_IPV6;
        _hostAddress = _hostAddrStr;
        return;
    }
    else 
#endif
    if (!_isValid)
    {
        while (_hostAddrStr[i] && _hostAddrStr[i] != ':')
        {
            ++i;
        }
        _hostAddress = _hostAddrStr.subString(0, i);
        if( !(_isValid = isValidIPV4Address(_hostAddress)))
        {
            // Not a valid IPV4 address, check for valid hostName
            if(!(_isValid = isValidHostName(_hostAddress)))
            {
                return;
            }
            _addrType = AT_HOSTNAME;
        }
        else
        { 
            _addrType = AT_IPV4;
        }
    }
    // Check for Port number.
    Uint32 port = 0;  
    if (_hostAddrStr[i] == ':')
    {
        ++i;
        while (isascii(_hostAddrStr[i]) && isdigit(_hostAddrStr[i]))
        {
            port = port * 10 + ( _hostAddrStr[i] - '0' );
            if (port > MAX_PORT_NUMBER)
            {
                _portNumber = PORT_INVALID;
                _isValid = false;
                return;  
            }
            ++i;
        }
    
        if (_hostAddrStr[i-1] != ':' && _hostAddrStr[i] == char(0))
        {
            _portNumber = port;
        }
        else
        {
            _portNumber = PORT_INVALID;
            _isValid = false;
        }
    }
}

#ifdef PEGASUS_ENABLE_IPV6
Boolean HostAddress::isValidIPV6Address (const String &ipv6Address)
{
    CString addr = ipv6Address.getCString();
    struct in6_addr iaddr;

    return  1 == convertTextToBinary(AF_INET6, (const char*) addr,
                    (void*)&iaddr);
}
#endif

Boolean HostAddress::isValidIPV4Address (const String &ipv4Address)
{
    CString addr = ipv4Address.getCString();
    struct in_addr iaddr;

    return  1 == convertTextToBinary(AF_INET, (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)
{
#ifndef PEGASUS_ENABLE_IPV6
    if (af == AF_INET)
    {
        return _inet_ptonv4(src, dst);
    }
    return -1;
#else
#if defined (PEGASUS_OS_TYPE_UNIX) || defined (PEGASUS_OS_VMS)
    return ::inet_pton(af, src, dst);
#else
    if (af == AF_INET)
    {
        return _inet_ptonv4(src, dst);
    }
    else if(af == AF_INET6)
    {
        return _inet_ptonv6(src, dst);
    }
    else
    {
        return -1; // Unsupported address family.
    }
#endif // PEGASUS_OS_TYPE_UNIX
#endif // PEGASUS_ENABLE_IPV6
}

const char * HostAddress::convertBinaryToText(int af, const void *src,
    char *dst, Uint32 size)
{
#ifndef PEGASUS_ENABLE_IPV6
    if (af == AF_INET)
    {
        return _inet_ntopv4(src, dst, size);
    }
    return 0;
#else
#if defined (PEGASUS_OS_TYPE_UNIX) || defined (PEGASUS_OS_VMS)
    return ::inet_ntop(af, src, dst, size);
#else
    if (af == AF_INET)
    {
        return _inet_ntopv4(src, dst, size);
    }
    else if (af == AF_INET6)
    {
        return _inet_ntopv6(src, dst, size);
    }
    else
    {
        return 0; // Unsupported address family.
    }
#endif // PEGASUS_OS_TYPE_UNIX
#endif // PEGASUS_ENABLE_IPV6
}

PEGASUS_NAMESPACE_END

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2