| // Copyright (C) 1999-2005 Open Source Telecom Corporation. |
| // Copyright (C) 2006-2010 David Sugar, Tycho Softworks. |
| // |
| // This program is free software; you can redistribute it and/or modify |
| // it under the terms of the GNU General Public License as published by |
| // the Free Software Foundation; either version 2 of the License, or |
| // (at your option) any later version. |
| // |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| // |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| // |
| // As a special exception, you may use this file as part of a free software |
| // library without restriction. Specifically, if other files instantiate |
| // templates or use macros or inline functions from this file, or you compile |
| // this file and link it with other files to produce an executable, this |
| // file does not by itself cause the resulting executable to be covered by |
| // the GNU General Public License. This exception does not however |
| // invalidate any other reasons why the executable file might be covered by |
| // the GNU General Public License. |
| // |
| // This exception applies only to the code released under the name GNU |
| // Common C++. If you copy code from other releases into a copy of GNU |
| // Common C++, as the General Public License permits, the exception does |
| // not apply to the code that you add in this way. To avoid misleading |
| // anyone as to the status of such modified files, you must delete |
| // this exception notice from them. |
| // |
| // If you write modifications of your own for GNU Common C++, it is your choice |
| // whether to permit this exception to apply to your modifications. |
| // If you do not wish that, delete this exception notice. |
| // |
| |
| #include <cc++/config.h> |
| #include <cc++/export.h> |
| #include <cc++/address.h> |
| #include "private.h" |
| #include <cstdlib> |
| |
| #ifdef CCXX_IPV6 |
| |
| #ifdef CCXX_NAMESPACES |
| namespace ost { |
| #endif |
| |
| #ifndef WIN32 |
| Mutex IPV6Address::mutex; |
| #endif |
| |
| const IPV6MulticastValidator IPV6Multicast::validator; |
| |
| void IPV6MulticastValidator::operator()(const in6_addr address) const |
| { |
| #ifdef CCXX_EXCEPTIONS |
| // "0000:" is always accepted, as it is an "empty" address. |
| if ( (address.s6_addr[0] != 0 || address.s6_addr[1] != 0) && |
| (address.s6_addr[0] != 0xff || address.s6_addr[1] < 0x1f)) { |
| throw "Multicast address not in the valid prefix ff00-ff1f:"; |
| } |
| #endif |
| } |
| |
| IPV6Address::IPV6Address(const IPV6Validator *_validator) |
| : validator(_validator), hostname(NULL) { |
| addr_count = 1; |
| ipaddr = new struct in6_addr[1]; |
| memcpy(ipaddr, &in6addr_any, sizeof(in6_addr)); |
| } |
| |
| IPV6Address::IPV6Address(const char *address, const IPV6Validator *_validator) : |
| validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL) { |
| if ( this->validator ) |
| this->validator = validator; |
| if(address == 0 || !strcmp(address, "*")) |
| setAddress(NULL); |
| else |
| setAddress(address); |
| } |
| |
| IPV6Address::IPV6Address(struct in6_addr addr, const IPV6Validator *_validator) : |
| validator(_validator), ipaddr(NULL), hostname(NULL) { |
| if ( this->validator ){ |
| this->validator = validator; |
| (*validator)(addr); |
| } |
| addr_count = 1; |
| ipaddr = new struct in6_addr[1]; |
| memcpy(&ipaddr, &addr, sizeof(struct in6_addr)); |
| } |
| |
| IPV6Address::IPV6Address(const IPV6Address &rhs) : |
| validator(rhs.validator), addr_count(rhs.addr_count), hostname(NULL) { |
| ipaddr = new struct in6_addr[addr_count]; |
| memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count); |
| } |
| |
| IPV6Address::~IPV6Address() |
| { |
| if(ipaddr) { |
| delete[] ipaddr; |
| ipaddr = NULL; |
| } |
| if(hostname) { |
| delString(hostname); |
| hostname = NULL; |
| } |
| } |
| |
| struct in6_addr IPV6Address::getAddress(void) const |
| { |
| return ipaddr[0]; |
| } |
| |
| struct in6_addr IPV6Address::getAddress(size_t i) const |
| { |
| return (i < addr_count ? ipaddr[i] : ipaddr[0]); |
| } |
| |
| bool IPV6Address::isInetAddress(void) const |
| { |
| struct in6_addr addr; |
| memset(&addr, 0, sizeof(addr)); |
| if(!ipaddr) |
| return false; |
| if(memcmp(&addr, &ipaddr[0], sizeof(addr))) |
| return true; |
| return false; |
| } |
| |
| IPV6Address &IPV6Address::operator=(const char *str) |
| { |
| if(str == 0 || !strcmp(str, "*")) |
| str = "::"; |
| |
| setAddress(str); |
| |
| return *this; |
| } |
| |
| IPV6Address &IPV6Address::operator=(struct in6_addr addr) |
| { |
| if(ipaddr) |
| delete[] ipaddr; |
| if ( validator ) |
| (*validator)(addr); |
| addr_count = 1; |
| ipaddr = new struct in6_addr[1]; |
| ipaddr[0] = addr; |
| if(hostname) |
| delString(hostname); |
| hostname = NULL; |
| return *this; |
| } |
| |
| IPV6Address &IPV6Address::operator=(const IPV6Address &rhs) |
| { |
| if(this == &rhs) return *this; |
| |
| addr_count = rhs.addr_count; |
| if(ipaddr) |
| delete[] ipaddr; |
| ipaddr = new struct in6_addr[addr_count]; |
| memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count); |
| validator = rhs.validator; |
| if(hostname) |
| delString(hostname); |
| hostname = NULL; |
| |
| return *this; |
| } |
| |
| bool IPV6Address::operator==(const IPV6Address &a) const |
| { |
| const IPV6Address *smaller, *larger; |
| size_t s, l; |
| |
| if(addr_count > a.addr_count) { |
| smaller = &a; |
| larger = this; |
| } |
| else { |
| smaller = this; |
| larger = &a; |
| } |
| |
| // Loop through all addr's in the smaller and make sure |
| // that they are all in the larger |
| for(s = 0; s < smaller->addr_count; s++) { |
| // bool found = false; |
| for(l = 0; l < larger->addr_count && |
| memcmp((char *)&ipaddr[s], (char *)&a.ipaddr[l], sizeof(struct in6_addr)); l++); |
| if(l == larger->addr_count) return false; |
| } |
| return true; |
| } |
| |
| bool IPV6Address::operator!=(const IPV6Address &a) const |
| { |
| // Impliment in terms of operator== |
| return (*this == a ? false : true); |
| } |
| |
| IPV6Host &IPV6Host::operator&=(const IPV6Mask &ma) |
| { |
| for(size_t i = 0; i < addr_count; i++) { |
| struct in6_addr mask = ma.getAddress(); |
| unsigned char *a = (unsigned char *)&ipaddr[i]; |
| unsigned char *m = (unsigned char *)&mask; |
| |
| for(size_t j = 0; j < sizeof(struct in6_addr); ++j) |
| *(a++) &= *(m++); |
| } |
| if(hostname) |
| delString(hostname); |
| hostname = NULL; |
| |
| return *this; |
| } |
| |
| IPV6Host::IPV6Host(struct in6_addr addr) : |
| IPV6Address(addr) {} |
| |
| IPV6Host::IPV6Host(const char *host) : |
| IPV6Address(host) |
| { |
| char namebuf[256]; |
| |
| if(!host) { |
| gethostname(namebuf, 256); |
| setAddress(namebuf); |
| } |
| } |
| |
| bool IPV6Address::setIPAddress(const char *host) |
| { |
| if(!host) |
| return false; |
| |
| struct in6_addr l_addr; |
| |
| #ifdef WIN32 |
| struct sockaddr saddr; |
| int slen = sizeof(saddr); |
| struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr; |
| int ok = WSAStringToAddress((LPSTR)host, AF_INET6, NULL, &saddr, &slen); |
| l_addr = paddr->sin6_addr; |
| #else |
| int ok = inet_pton(AF_INET6, host, &l_addr); |
| #endif |
| if ( validator ) |
| (*validator)(l_addr); |
| if ( !ok ) |
| return false; |
| *this = l_addr; |
| return true; |
| } |
| |
| #if defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME2) |
| |
| void IPV6Address::setAddress(const char *host) |
| { |
| if(hostname) |
| delString(hostname); |
| hostname = NULL; |
| |
| if(!host) // The way this is currently used, this can never happen |
| host = "::"; |
| |
| #ifdef WIN32 |
| if(!stricmp(host, "localhost")) |
| host = "::1"; |
| #endif |
| |
| if(!setIPAddress(host)) { |
| struct addrinfo hint, *list = NULL, *first; |
| memset(&hint, 0, sizeof(hint)); |
| hint.ai_family = AF_INET6; |
| struct in6_addr *addr; |
| struct sockaddr_in6 *ip6addr; |
| |
| if(getaddrinfo(host, NULL, &hint, &list) || !list) { |
| if(ipaddr) |
| delete[] ipaddr; |
| ipaddr = new struct in6_addr[1]; |
| memset((void *)&ipaddr[0], 0, sizeof(ipaddr)); |
| return; |
| } |
| |
| // Count the number of IP addresses returned |
| addr_count = 0; |
| first = list; |
| while(list) { |
| ++addr_count; |
| list = list->ai_next; |
| } |
| |
| // Allocate enough memory |
| if(ipaddr) |
| delete[] ipaddr; // Cause this was allocated in base |
| ipaddr = new struct in6_addr[addr_count]; |
| |
| // Now go through the list again assigning to |
| // the member ipaddr; |
| list = first; |
| int i = 0; |
| while(list) { |
| ip6addr = (struct sockaddr_in6 *)list->ai_addr; |
| addr = &ip6addr->sin6_addr; |
| if(validator) |
| (*validator)(*addr); |
| ipaddr[i++] = *addr; |
| list = list->ai_next; |
| } |
| freeaddrinfo(first); |
| } |
| } |
| |
| #else |
| |
| void IPV6Address::setAddress(const char *host) |
| { |
| if(hostname) |
| delString(hostname); |
| hostname = NULL; |
| |
| if(!host) // The way this is currently used, this can never happen |
| host = "::"; |
| |
| #ifdef WIN32 |
| if(!stricmp(host, "localhost")) |
| host = "::1"; |
| #endif |
| |
| if(!setIPAddress(host)) { |
| struct hostent *hp; |
| struct in6_addr **bptr; |
| #if defined(__GLIBC__) |
| char hbuf[8192]; |
| struct hostent hb; |
| int rtn; |
| |
| if(gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn)) |
| hp = NULL; |
| #elif defined(sun) |
| char hbuf[8192]; |
| struct hostent hb; |
| int rtn; |
| |
| hp = gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &rtn); |
| #elif (defined(__osf__) || defined(_OSF_SOURCE) || defined(__hpux)) |
| hp = gethostbyname(host); |
| #elif defined(WIN32) && (!defined(_MSC_VER) || _MSC_VER < 1300) |
| hp = gethostbyname(host); |
| #elif defined(WIN32) |
| hp = gethostbyname2(host, AF_INET6); |
| #else |
| mutex.enterMutex(); |
| hp = gethostbyname2(host, AF_INET6); |
| mutex.leaveMutex(); |
| #endif |
| if(!hp) { |
| if(ipaddr) |
| delete[] ipaddr; |
| ipaddr = new struct in6_addr[1]; |
| memset((void *)&ipaddr[0], 0, sizeof(ipaddr)); |
| return; |
| } |
| |
| // Count the number of IP addresses returned |
| addr_count = 0; |
| for(bptr = (struct in6_addr **)hp->h_addr_list; *bptr != NULL; bptr++) { |
| addr_count++; |
| } |
| |
| // Allocate enough memory |
| if(ipaddr) |
| delete[] ipaddr; // Cause this was allocated in base |
| ipaddr = new struct in6_addr[addr_count]; |
| |
| // Now go through the list again assigning to |
| // the member ipaddr; |
| bptr = (struct in6_addr **)hp->h_addr_list; |
| for(unsigned int i = 0; i < addr_count; i++) { |
| if ( validator ) |
| (*validator)(*bptr[i]); |
| ipaddr[i] = *bptr[i]; |
| } |
| } |
| } |
| |
| #endif |
| |
| IPV6Broadcast::IPV6Broadcast(const char *net) : |
| IPV6Address(net) |
| { |
| } |
| |
| IPV6Mask::IPV6Mask(const char *mask) : |
| IPV6Address(mask) |
| { |
| } |
| |
| const char *IPV6Address::getHostname(void) const |
| { |
| struct hostent *hp = NULL; |
| struct in6_addr addr0; |
| static char strbuf[64]; |
| |
| memset(&addr0, 0, sizeof(addr0)); |
| if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0))) |
| return NULL; |
| |
| if(!memcmp(&in6addr_loopback, &ipaddr[0], sizeof(addr0))) |
| return "localhost"; |
| |
| #if defined(__GLIBC__) |
| char hbuf[8192]; |
| struct hostent hb; |
| int rtn; |
| if(gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn)) |
| hp = NULL; |
| #elif defined(sun) |
| char hbuf[8192]; |
| struct hostent hb; |
| int rtn; |
| hp = gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, (int)sizeof(hbuf), &rtn); |
| #elif defined(__osf__) || defined(WIN32) |
| hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6); |
| #else |
| mutex.enterMutex(); |
| hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6); |
| mutex.leaveMutex(); |
| #endif |
| if(hp) { |
| if(hostname) |
| delString(hostname); |
| hostname = newString(hp->h_name); |
| return hostname; |
| } else { |
| #ifdef WIN32 |
| struct sockaddr saddr; |
| struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr; |
| DWORD slen = sizeof(strbuf); |
| memset(&saddr, 0, sizeof(saddr)); |
| paddr->sin6_family = AF_INET6; |
| paddr->sin6_addr = ipaddr[0]; |
| WSAAddressToString(&saddr, sizeof(saddr), NULL, strbuf, &slen); |
| return strbuf; |
| #else |
| return inet_ntop(AF_INET6, &ipaddr[0], strbuf, sizeof(strbuf)); |
| #endif |
| } |
| } |
| |
| IPV6Host operator&(const IPV6Host &addr, const IPV6Mask &mask) |
| { |
| IPV6Host temp = addr; |
| temp &= mask; |
| return temp; |
| } |
| |
| IPV6Multicast::IPV6Multicast() : |
| IPV6Address(&validator) |
| {} |
| |
| IPV6Multicast::IPV6Multicast(const char *address) : |
| IPV6Address(address,&validator) |
| {} |
| |
| #ifdef CCXX_NAMESPACES |
| } |
| #endif |
| |
| #endif |
| |
| /** EMACS ** |
| * Local variables: |
| * mode: c++ |
| * c-basic-offset: 4 |
| * End: |
| */ |