Logo Search packages:      
Sourcecode: poco version File versions  Download package

IPAddress.cpp

//
// IPAddress.cpp
//
// $Id: //poco/1.2/Net/src/IPAddress.cpp#4 $
//
// Library: Net
// Package: NetCore
// Module:  IPAddress
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//


#include "Poco/Net/IPAddress.h"
#include "Poco/Net/NetException.h"
#include "Poco/RefCountedObject.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Types.h"
#include <algorithm>
#include <string.h>


using Poco::RefCountedObject;
using Poco::NumberFormatter;
using Poco::UInt8;
using Poco::UInt16;
using Poco::UInt32;


namespace Poco {
namespace Net {


//
// IPAddressImpl
//


class IPAddressImpl: public RefCountedObject
{
public:
      virtual std::string toString() const = 0;
      virtual poco_socklen_t length() const = 0;
      virtual const void* addr() const = 0;
      virtual IPAddress::Family family() const = 0;
      virtual int af() const = 0;
      virtual bool isWildcard() const     = 0;
      virtual bool isBroadcast() const = 0;
      virtual bool isLoopback() const = 0;
      virtual bool isMulticast() const = 0;
      virtual bool isLinkLocal() const = 0;
      virtual bool isSiteLocal() const = 0;
      virtual bool isIPv4Mapped() const = 0;
      virtual bool isIPv4Compatible() const = 0;
      virtual bool isWellKnownMC() const = 0;
      virtual bool isNodeLocalMC() const = 0;
      virtual bool isLinkLocalMC() const = 0;
      virtual bool isSiteLocalMC() const = 0;
      virtual bool isOrgLocalMC() const = 0;
      virtual bool isGlobalMC() const = 0;

protected:
      IPAddressImpl()
      {
      }
      
      virtual ~IPAddressImpl()
      {
      }

private:
      IPAddressImpl(const IPAddressImpl&);
      IPAddressImpl& operator = (const IPAddressImpl&);
};


class IPv4AddressImpl: public IPAddressImpl
{
public:
      IPv4AddressImpl()
      {
            memset(&_addr, 0, sizeof(_addr));
      }
      
      IPv4AddressImpl(const void* addr)
      {
            memcpy(&_addr, addr, sizeof(_addr));
      }
      
      std::string toString() const
      {
            const UInt8* bytes = reinterpret_cast<const UInt8*>(&_addr);
            std::string result;
            result.reserve(16);
            result.append(NumberFormatter::format(bytes[0]));
            result.append(".");
            result.append(NumberFormatter::format(bytes[1]));
            result.append(".");
            result.append(NumberFormatter::format(bytes[2]));
            result.append(".");
            result.append(NumberFormatter::format(bytes[3]));
            return result;
      }

      poco_socklen_t length() const
      {
            return sizeof(_addr);
      }
      
      const void* addr() const
      {
            return &_addr;
      }
      
      IPAddress::Family family() const
      {
            return IPAddress::IPv4;
      }
      
      int af() const
      {
            return AF_INET;
      }
      
      bool isWildcard() const
      {
            return _addr.s_addr == INADDR_ANY;
      }
      
      bool isBroadcast() const
      {
            return _addr.s_addr == INADDR_NONE;
      }
      
      bool isLoopback() const
      {
            return ntohl(_addr.s_addr) == 0x7F000001; // 127.0.0.1
      }
      
      bool isMulticast() const
      {
            return (ntohl(_addr.s_addr) & 0xF0000000) == 0xE0000000; // 224.0.0.0/24 to 239.0.0.0/24
      }
            
      bool isLinkLocal() const
      {
            return (ntohl(_addr.s_addr) & 0xFFFF0000) == 0xA9FE0000; // 169.254.0.0/16
      }
      
      bool isSiteLocal() const
      {
            UInt32 addr = ntohl(_addr.s_addr);
            return (addr & 0xFF000000) == 0x0A000000 ||      // 10.0.0.0/24
                   (addr & 0xFFFF0000) == 0xC0A80000 ||      // 192.68.0.0/16
                   addr >= 0xAC100000 && addr <= 0xAC1FFFFF; // 172.16.0.0 to 172.31.255.255
      }
      
      bool isIPv4Compatible() const
      {
            return true;
      }

      bool isIPv4Mapped() const
      {
            return true;
      }

      bool isWellKnownMC() const
      {
            return (ntohl(_addr.s_addr) & 0xFFFFFF00) == 0xE0000000; // 224.0.0.0/8
      }
      
      bool isNodeLocalMC() const
      {
            return false;
      }
      
      bool isLinkLocalMC() const
      {
            return (ntohl(_addr.s_addr) & 0xFF000000) == 0xE0000000; // 244.0.0.0/24
      }
      
      bool isSiteLocalMC() const
      {
            return (ntohl(_addr.s_addr) & 0xFFFF0000) == 0xEFFF0000; // 239.255.0.0/16
      }
      
      bool isOrgLocalMC() const
      {
            return (ntohl(_addr.s_addr) & 0xFFFF0000) == 0xEFC00000; // 239.192.0.0/16
      }
      
      bool isGlobalMC() const
      {
            UInt32 addr = ntohl(_addr.s_addr);
            return addr >= 0xE0000100 && addr <= 0xEE000000; // 224.0.1.0 to 238.255.255.255
      }

      static IPv4AddressImpl* parse(const std::string& addr)
      {
            if (addr.empty()) return 0;         
#if defined(_WIN32)
            struct in_addr ia;
            ia.s_addr = inet_addr(addr.c_str());
            if (ia.s_addr == INADDR_NONE && addr != "255.255.255.255")
                  return 0;
            else
                  return new IPv4AddressImpl(&ia);
#else
            struct in_addr ia;
            if (inet_aton(addr.c_str(), &ia))
                  return new IPv4AddressImpl(&ia);
            else
                  return 0;
#endif
      }
            
private:
      struct in_addr _addr;   
};


#if defined(POCO_HAVE_IPv6)


class IPv6AddressImpl: public IPAddressImpl
{
public:
      IPv6AddressImpl()
      {
            memset(&_addr, 0, sizeof(_addr));
      }

      IPv6AddressImpl(const void* addr)
      {
            memcpy(&_addr, addr, sizeof(_addr));
      }

      std::string toString() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            if (isIPv4Compatible() || isIPv4Mapped())
            {
                  std::string result;
                  result.reserve(24);
                  if (words[5] == 0)
                        result.append("::");
                  else
                        result.append("::FFFF:");
                  const UInt8* bytes = reinterpret_cast<const UInt8*>(&_addr);
                  result.append(NumberFormatter::format(bytes[12]));
                  result.append(".");
                  result.append(NumberFormatter::format(bytes[13]));
                  result.append(".");
                  result.append(NumberFormatter::format(bytes[14]));
                  result.append(".");
                  result.append(NumberFormatter::format(bytes[15]));
                  return result;
            }
            else
            {
                  std::string result;
                  result.reserve(46);
                  bool zeroSequence = false;
                  int i = 0;
                  while (i < 8)
                  {
                        if (!zeroSequence && words[i] == 0)
                        {
                              int zi = i;
                              while (zi < 8 && words[zi] == 0) ++zi;
                              if (zi > i + 1)
                              {
                                    i = zi;
                                    result.append(":");
                                    zeroSequence = true;
                              }
                        }
                        if (i > 0) result.append(":");
                        if (i < 8) result.append(NumberFormatter::formatHex(ntohs(words[i++])));
                  }
                  return result;
            }
      }
      
      poco_socklen_t length() const
      {
            return sizeof(_addr);
      }

      const void* addr() const
      {
            return &_addr;
      }

      IPAddress::Family family() const
      {
            return IPAddress::IPv6;
      }

      int af() const
      {
            return AF_INET6;
      }

      bool isWildcard() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && 
                   words[4] == 0 && words[5] == 0 && words[6] == 0 && words[7] == 0;
      }
      
      bool isBroadcast() const
      {
            return false;
      }
      
      bool isLoopback() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && 
                   words[4] == 0 && words[5] == 0 && words[6] == 0 && words[7] == 1;
      }
      
      bool isMulticast() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFE0) == 0xFF00;
      }
            
      bool isLinkLocal() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFE0) == 0xFE80;
      }
      
      bool isSiteLocal() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFE0) == 0xFEC0;
      }
      
      bool isIPv4Compatible() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && words[5] == 0;
      }

      bool isIPv4Mapped() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && words[5] == 0xFFFF;
      }

      bool isWellKnownMC() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFF0) == 0xFF00;
      }
      
      bool isNodeLocalMC() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFEF) == 0xFF01;
      }
      
      bool isLinkLocalMC() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFEF) == 0xFF02;
      }
      
      bool isSiteLocalMC() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFEF) == 0xFF05;
      }
      
      bool isOrgLocalMC() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFEF) == 0xFF08;
      }
      
      bool isGlobalMC() const
      {
            const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
            return (words[0] & 0xFFEF) == 0xFF0F;
      }

      static IPv6AddressImpl* parse(const std::string& addr)
      {
            if (addr.empty()) return 0;
#if defined(_WIN32)
            struct addrinfo* pAI;
            struct addrinfo hints;
            memset(&hints, 0, sizeof(hints));
            hints.ai_flags = AI_NUMERICHOST;
            int rc = getaddrinfo(addr.c_str(), NULL, &hints, &pAI);
            if (rc == 0)
            {
                  IPv6AddressImpl* pResult = new IPv6AddressImpl(&reinterpret_cast<struct sockaddr_in6*>(pAI->ai_addr)->sin6_addr);
                  freeaddrinfo(pAI);
                  return pResult;
            }
            else return 0;
#else
            struct in6_addr ia;
            if (inet_pton(AF_INET6, addr.c_str(), &ia) == 1)
                  return new IPv6AddressImpl(&ia);
            else
                  return 0;
#endif
      }

private:
      struct in6_addr _addr;  
};


#endif // POCO_HAVE_IPv6


//
// IPAddress
//


IPAddress::IPAddress(): _pImpl(new IPv4AddressImpl)
{
}


00457 IPAddress::IPAddress(const IPAddress& addr): _pImpl(addr._pImpl)
{
      _pImpl->duplicate();
}


00463 IPAddress::IPAddress(Family family): _pImpl(0)
{
      if (family == IPv4)
            _pImpl = new IPv4AddressImpl();
#if defined(POCO_HAVE_IPv6)
      else if (family == IPv6)
            _pImpl = new IPv6AddressImpl();
#endif
      else Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}


00475 IPAddress::IPAddress(const std::string& addr)
{
      _pImpl = IPv4AddressImpl::parse(addr);
#if defined(POCO_HAVE_IPv6)
      if (!_pImpl)
            _pImpl = IPv6AddressImpl::parse(addr);
#endif
      if (!_pImpl) throw InvalidAddressException(addr);
}


00486 IPAddress::IPAddress(const std::string& addr, Family family): _pImpl(0)
{
      if (family == IPv4)
            _pImpl = IPv4AddressImpl::parse(addr);
#if defined(POCO_HAVE_IPv6)
      else if (family == IPv6)
            _pImpl = IPv6AddressImpl::parse(addr);
#endif
      else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}


00498 IPAddress::IPAddress(const void* addr, poco_socklen_t length)
{
      if (length == sizeof(struct in_addr))
            _pImpl = new IPv4AddressImpl(addr);
#if defined(POCO_HAVE_IPv6)
      else if (length == sizeof(struct in6_addr))
            _pImpl = new IPv6AddressImpl(addr);
#endif
      else throw Poco::InvalidArgumentException("Invalid address length passed to IPAddress()");
}


00510 IPAddress::~IPAddress()
{
      _pImpl->release();
}


00516 IPAddress& IPAddress::operator = (const IPAddress& addr)
{
      if (&addr != this)
      {
            _pImpl->release();
            _pImpl = addr._pImpl;
            _pImpl->duplicate();
      }
      return *this;
}


00528 void IPAddress::swap(IPAddress& address)
{
      std::swap(_pImpl, address._pImpl);
}

      
00534 IPAddress::Family IPAddress::family() const
{
      return _pImpl->family();
}

      
00540 std::string IPAddress::toString() const
{
      return _pImpl->toString();
}


00546 bool IPAddress::isWildcard() const
{
      return _pImpl->isWildcard();
}
      
00551 bool IPAddress::isBroadcast() const
{
      return _pImpl->isBroadcast();
}


00557 bool IPAddress::isLoopback() const
{
      return _pImpl->isLoopback();
}


00563 bool IPAddress::isMulticast() const
{
      return _pImpl->isMulticast();
}

      
00569 bool IPAddress::isUnicast() const
{
      return !isWildcard() && !isBroadcast() && !isMulticast();
}

      
00575 bool IPAddress::isLinkLocal() const
{
      return _pImpl->isLinkLocal();
}


00581 bool IPAddress::isSiteLocal() const
{
      return _pImpl->isSiteLocal();
}


00587 bool IPAddress::isIPv4Compatible() const
{
      return _pImpl->isIPv4Compatible();
}


00593 bool IPAddress::isIPv4Mapped() const
{
      return _pImpl->isIPv4Mapped();
}


00599 bool IPAddress::isWellKnownMC() const
{
      return _pImpl->isWellKnownMC();
}


00605 bool IPAddress::isNodeLocalMC() const
{
      return _pImpl->isNodeLocalMC();
}


00611 bool IPAddress::isLinkLocalMC() const
{
      return _pImpl->isLinkLocalMC();
}


00617 bool IPAddress::isSiteLocalMC() const
{
      return _pImpl->isSiteLocalMC();
}


00623 bool IPAddress::isOrgLocalMC() const
{
      return _pImpl->isOrgLocalMC();
}


00629 bool IPAddress::isGlobalMC() const
{
      return _pImpl->isGlobalMC();
}


00635 bool IPAddress::operator == (const IPAddress& a) const
{
      poco_socklen_t l1 = length();
      poco_socklen_t l2 = a.length();
      if (l1 == l2)
            return memcmp(addr(), a.addr(), l1) == 0;
      else
            return false;
}


bool IPAddress::operator != (const IPAddress& a) const
{
      poco_socklen_t l1 = length();
      poco_socklen_t l2 = a.length();
      if (l1 == l2)
            return memcmp(addr(), a.addr(), l1) != 0;
      else
            return true;
}


bool IPAddress::operator < (const IPAddress& a) const
{
      poco_socklen_t l1 = length();
      poco_socklen_t l2 = a.length();
      if (l1 == l2)
            return memcmp(addr(), a.addr(), l1) < 0;
      else
            return l1 < l2;
}


bool IPAddress::operator <= (const IPAddress& a) const
{
      poco_socklen_t l1 = length();
      poco_socklen_t l2 = a.length();
      if (l1 == l2)
            return memcmp(addr(), a.addr(), l1) <= 0;
      else
            return l1 < l2;
}


bool IPAddress::operator > (const IPAddress& a) const
{
      poco_socklen_t l1 = length();
      poco_socklen_t l2 = a.length();
      if (l1 == l2)
            return memcmp(addr(), a.addr(), l1) > 0;
      else
            return l1 > l2;
}


bool IPAddress::operator >= (const IPAddress& a) const
{
      poco_socklen_t l1 = length();
      poco_socklen_t l2 = a.length();
      if (l1 == l2)
            return memcmp(addr(), a.addr(), l1) >= 0;
      else
            return l1 > l2;
}


poco_socklen_t IPAddress::length() const
{
      return _pImpl->length();
}

      
00707 const void* IPAddress::addr() const
{
      return _pImpl->addr();
}


00713 int IPAddress::af() const
{
      return _pImpl->af();
}


void IPAddress::init(IPAddressImpl* pImpl)
{
      _pImpl->release();
      _pImpl = pImpl;
}


00726 IPAddress IPAddress::parse(const std::string& addr)
{
      return IPAddress(addr);
}


00732 bool IPAddress::tryParse(const std::string& addr, IPAddress& result)
{
      IPAddressImpl* pImpl = IPv4AddressImpl::parse(addr);
#if defined(POCO_HAVE_IPv6)
      if (!pImpl) pImpl = IPv6AddressImpl::parse(addr);
#endif
      if (pImpl)
      {
            result.init(pImpl);
            return true;
      }
      else return false;
}


} } // namespace Poco::Net

Generated by  Doxygen 1.6.0   Back to index