blob: ec452cd44ff8f4d2423ff70af80364c856fa6d76 [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 1999-2005 Open Source Telecom Corporation.
2// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 2 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17//
18// As a special exception, you may use this file as part of a free software
19// library without restriction. Specifically, if other files instantiate
20// templates or use macros or inline functions from this file, or you compile
21// this file and link it with other files to produce an executable, this
22// file does not by itself cause the resulting executable to be covered by
23// the GNU General Public License. This exception does not however
24// invalidate any other reasons why the executable file might be covered by
25// the GNU General Public License.
26//
27// This exception applies only to the code released under the name GNU
28// Common C++. If you copy code from other releases into a copy of GNU
29// Common C++, as the General Public License permits, the exception does
30// not apply to the code that you add in this way. To avoid misleading
31// anyone as to the status of such modified files, you must delete
32// this exception notice from them.
33//
34// If you write modifications of your own for GNU Common C++, it is your choice
35// whether to permit this exception to apply to your modifications.
36// If you do not wish that, delete this exception notice.
37//
38
39#include <ucommon-config.h>
40#ifdef HAVE_ENDIAN_H
41#include <endian.h>
42#endif
43#include <commoncpp/config.h>
44#include <commoncpp/export.h>
45#include <commoncpp/thread.h>
46#include <commoncpp/address.h>
47#include <cstdlib>
48
49#ifndef _MSWINDOWS_
50#include <sys/socket.h>
51#include <netinet/in.h>
52#include <arpa/inet.h>
53#endif
54
55#if defined(_MSWINDOWS_) && !defined(__BIG_ENDIAN)
56#define __LITTLE_ENDIAN 1234
57#define __BIG_ENDIAN 4321
58#define __PDP_ENDIAN 3412
59#define __BYTE_ORDER __LITTLE_ENDIAN
60#endif
61
62using namespace COMMONCPP_NAMESPACE;
63
64#if __BYTE_ORDER == __BIG_ENDIAN
65enum {
66 MCAST_VALID_MASK = 0xF0000000,
67 MCAST_VALID_VALUE = 0xE0000000
68};
69#else
70enum {
71 MCAST_VALID_MASK = 0x000000F0,
72 MCAST_VALID_VALUE = 0x000000E0
73};
74#endif
75
76#ifndef _MSWINDOWS_
77Mutex IPV4Address::mutex;
78#endif
79
80IPV4Host IPV4Host::_host_;
81
82const IPV4MulticastValidator IPV4Multicast::validator;
83
84void IPV4MulticastValidator::operator()(const in_addr address) const
85{
86#ifdef CCXX_EXCEPTIONS
87 // "0.0.0.0" is always accepted, as it is an "empty" address.
88 if ( (address.s_addr != INADDR_ANY) &&
89 (address.s_addr & MCAST_VALID_MASK) != MCAST_VALID_VALUE ) {
90 throw "Multicast address not in the valid range: from 224.0.0.1 through 239.255.255.255";
91 }
92#endif
93}
94
95IPV4Address::IPV4Address(const IPV4Validator *_validator) :
96validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL)
97{
98 *this = (long unsigned int)INADDR_ANY;
99}
100
101IPV4Address::IPV4Address(const char *address, const IPV4Validator *_validator) :
102validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL)
103{
104 if(address == 0 || !strcmp(address, "*"))
105 setAddress(NULL);
106 else
107 setAddress(address);
108}
109
110IPV4Address::IPV4Address(struct in_addr addr, const IPV4Validator *_validator) :
111validator(_validator), ipaddr(NULL), hostname(NULL)
112{
113 if ( this->validator ) {
114 (*validator)(addr);
115 }
116 addr_count = 1;
117 ipaddr = new struct in_addr[1];
118 ipaddr[0] = addr;
119}
120
121IPV4Address::IPV4Address(const IPV4Address &rhs) :
122validator(rhs.validator), addr_count(rhs.addr_count), hostname(NULL)
123{
124 ipaddr = new struct in_addr[addr_count];
125 memcpy(ipaddr, rhs.ipaddr, sizeof(struct in_addr) * addr_count);
126}
127
128IPV4Address::~IPV4Address()
129{
130 if(ipaddr) {
131 delete[] ipaddr;
132 ipaddr = NULL;
133 }
134 if(hostname) {
135 delString(hostname);
136 hostname = NULL;
137 }
138}
139
140struct in_addr IPV4Address::getAddress(void) const
141{
142 return ipaddr[0];
143}
144
145struct in_addr IPV4Address::getAddress(size_t i) const
146{
147 return (i < addr_count ? ipaddr[i] : ipaddr[0]);
148}
149
150bool IPV4Address::isInetAddress(void) const
151{
152 struct in_addr addr;
153 memset(&addr, 0, sizeof(addr));
154 if(memcmp(&addr, &ipaddr[0], sizeof(addr)))
155 return true;
156 return false;
157}
158
159IPV4Address &IPV4Address::operator=(const char *str)
160{
161 if(str == 0 || !strcmp(str, "*"))
162 str = "0.0.0.0";
163
164 setAddress(str);
165
166 return *this;
167}
168
169IPV4Address &IPV4Address::operator=(struct in_addr addr)
170{
171 if(ipaddr)
172 delete[] ipaddr;
173 if ( validator )
174 (*validator)(addr);
175 addr_count = 1;
176 ipaddr = new struct in_addr[1];
177 ipaddr[0] = addr;
178 if(hostname)
179 delString(hostname);
180 hostname = NULL;
181 return *this;
182}
183
184IPV4Address &IPV4Address::operator=(unsigned long addr)
185{
186 union {
187 uint32_t addr;
188 struct in_addr in4;
189 } aptr;
190
191 aptr.addr = addr;
192
193 if ( validator )
194 (*validator)(aptr.in4);
195
196 if(ipaddr)
197 delete[] ipaddr;
198
199 addr_count = 1;
200 ipaddr = new struct in_addr[1];
201 memcpy(ipaddr, &aptr.in4, sizeof(struct in_addr));
202 if(hostname)
203 delString(hostname);
204 hostname = NULL;
205 return *this;
206}
207
208IPV4Address &IPV4Address::operator=(const IPV4Address &rhs)
209{
210 if(this == &rhs) return *this;
211
212 addr_count = rhs.addr_count;
213 if(ipaddr)
214 delete[] ipaddr;
215 ipaddr = new struct in_addr[addr_count];
216 memcpy(ipaddr, rhs.ipaddr, sizeof(struct in_addr) * addr_count);
217 validator = rhs.validator;
218 if(hostname)
219 delString(hostname);
220 hostname = NULL;
221
222 return *this;
223}
224
225bool IPV4Address::operator==(const IPV4Address &a) const
226{
227 const IPV4Address *smaller, *larger;
228 size_t s, l;
229
230 if(addr_count > a.addr_count) {
231 smaller = &a;
232 larger = this;
233 }
234 else {
235 smaller = this;
236 larger = &a;
237 }
238
239 // Loop through all addr's in the smaller and make sure
240 // that they are all in the larger
241 for(s = 0; s < smaller->addr_count; s++) {
242 // bool found = false;
243 for(l = 0; l < larger->addr_count &&
244 memcmp((char *)&smaller->ipaddr[s], (char *)&larger->ipaddr[l], sizeof(struct in_addr)); l++);
245 if(l == larger->addr_count) return false;
246 }
247 return true;
248}
249
250bool IPV4Address::operator!=(const IPV4Address &a) const
251{
252 // Impliment in terms of operator==
253 return (*this == a ? false : true);
254}
255
256IPV4Host &IPV4Host::operator&=(const IPV4Mask &ma)
257{
258 for(size_t i = 0; i < addr_count; i++) {
259 struct in_addr mask = ma.getAddress();
260 unsigned char *a = (unsigned char *)&ipaddr[i];
261 unsigned char *m = (unsigned char *)&mask;
262
263 for(size_t j = 0; j < sizeof(struct in_addr); ++j)
264 *(a++) &= *(m++);
265 }
266 if(hostname)
267 delString(hostname);
268 hostname = NULL;
269
270 return *this;
271}
272
273IPV4Host::IPV4Host(struct in_addr addr) :
274IPV4Address(addr) {}
275
276IPV4Host::IPV4Host(const char *host) :
277IPV4Address(host)
278{
279 char namebuf[256];
280
281 if(!host) {
282 if(this == &_host_) {
283 gethostname(namebuf, 256);
284 setAddress(namebuf);
285 }
286 else
287 *this = _host_;
288 }
289}
290
291bool IPV4Address::setIPAddress(const char *host)
292{
293 if(!host)
294 return false;
295
296#if defined(_MSWINDOWS_)
297 struct sockaddr_in addr;
298 addr.sin_addr.s_addr = inet_addr(host);
299 if ( validator )
300 (*validator)(addr.sin_addr);
301 if(addr.sin_addr.s_addr == INADDR_NONE)
302 return false;
303 *this = addr.sin_addr.s_addr;
304#else
305 struct in_addr l_addr;
306
307 int ok = inet_aton(host, &l_addr);
308 if ( validator )
309 (*validator)(l_addr);
310 if ( !ok )
311 return false;
312 *this = l_addr;
313#endif
314 return true;
315}
316
317void IPV4Address::setAddress(const char *host)
318{
319 if(hostname)
320 delString(hostname);
321 hostname = NULL;
322
323 if(!host) // The way this is currently used, this can never happen
324 {
325 *this = (long unsigned int)htonl(INADDR_ANY);
326 return;
327 }
328
329#ifdef _MSWINDOWS_
330 if(!stricmp(host, "localhost")) {
331 *this = (long unsigned int)inet_addr("127.0.0.1");
332 return;
333 }
334#endif
335
336 if(!setIPAddress(host)) {
337 struct hostent *hp;
338 struct in_addr **bptr;
339#if defined(__GLIBC__)
340 char hbuf[8192];
341 struct hostent hb;
342 int rtn;
343
344 if(gethostbyname_r(host, &hb, hbuf, sizeof(hbuf), &hp, &rtn))
345 hp = NULL;
346#elif defined(sun)
347 char hbuf[8192];
348 struct hostent hb;
349 int rtn;
350
351 hp = gethostbyname_r(host, &hb, hbuf, sizeof(hbuf), &rtn);
352#elif (defined(__osf__) || defined(_MSWINDOWS_))
353 hp = gethostbyname(host);
354#else
355 mutex.enterMutex();
356 hp = gethostbyname(host);
357 mutex.leaveMutex();
358#endif
359 if(!hp) {
360 if(ipaddr)
361 delete[] ipaddr;
362 ipaddr = new struct in_addr[1];
363 memset(ipaddr, 0, sizeof(struct in_addr));
364 return;
365 }
366
367 // Count the number of IP addresses returned
368 addr_count = 0;
369 for(bptr = (struct in_addr **)hp->h_addr_list; *bptr != NULL; bptr++) {
370 addr_count++;
371 }
372
373 // Allocate enough memory
374 if(ipaddr)
375 delete[] ipaddr; // Cause this was allocated in base
376 ipaddr = new struct in_addr[addr_count];
377
378 // Now go through the list again assigning to
379 // the member ipaddr;
380 bptr = (struct in_addr **)hp->h_addr_list;
381 for(unsigned int i = 0; i < addr_count; i++) {
382 if ( validator )
383 (*validator)(*bptr[i]);
384 ipaddr[i] = *bptr[i];
385 }
386 }
387}
388
389IPV4Broadcast::IPV4Broadcast(const char *net) :
390IPV4Address(net)
391{
392}
393
394IPV4Mask::IPV4Mask(const char *mask)
395{
396 unsigned long x = 0xffffffff;
397 int l = 32 - atoi(mask);
398
399 if(setIPAddress(mask))
400 return;
401
402 if(l < 1 || l > 32) {
403#ifdef CCXX_EXCEPTIONS
404 if(Thread::getException() == Thread::throwObject)
405 throw((IPV4Address *)this);
406#endif
407 return;
408 }
409
410 *this = htonl(x << l);
411}
412
413const char *IPV4Address::getHostname(void) const
414{
415 struct hostent *hp = NULL;
416 struct in_addr addr0;
417
418 memset(&addr0, 0, sizeof(addr0));
419 if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0)))
420 return NULL;
421
422#ifdef _MSWINDOWS_
423 memset(&addr0, 0xff, sizeof(addr0));
424 if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0)))
425 return "255.255.255.255";
426 long a = inet_addr("127.0.0.1");
427 if(!memcmp(&a, &ipaddr[0], sizeof(a)))
428 return "localhost";
429#endif
430
431#if defined(__GLIBC__)
432 char hbuf[8192];
433 struct hostent hb;
434 int rtn;
435 if(gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET, &hb, hbuf, sizeof(hbuf), &hp, &rtn))
436 hp = NULL;
437#elif defined(sun)
438 char hbuf[8192];
439 struct hostent hb;
440 int rtn;
441 hp = gethostbyaddr_r((char *)&ipaddr[0], (int)sizeof(addr0), (int)AF_INET, &hb, hbuf, (int)sizeof(hbuf), &rtn);
442#elif defined(__osf__) || defined(_MSWINDOWS_)
443 hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET);
444#else
445 mutex.enterMutex();
446 hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET);
447 mutex.leaveMutex();
448#endif
449 if(hp) {
450 if(hostname)
451 delString(hostname);
452 hostname = newString(hp->h_name);
453 return hostname;
454 } else {
455 return inet_ntoa(ipaddr[0]);
456 }
457}
458
459IPV4Host operator&(const IPV4Host &addr, const IPV4Mask &mask)
460{
461 IPV4Host temp = addr;
462 temp &= mask;
463 return temp;
464}
465
466IPV4Multicast::IPV4Multicast() :
467 IPV4Address(&validator)
468{}
469
470IPV4Multicast::IPV4Multicast(const struct in_addr address) :
471 IPV4Address(address, &validator)
472{}
473
474IPV4Multicast::IPV4Multicast(const char *address) :
475 IPV4Address(address, &validator)
476{}
477
478#ifdef CCXX_IPV6
479
480#ifndef _MSWINDOWS_
481Mutex IPV6Address::mutex;
482#endif
483
484const IPV6MulticastValidator IPV6Multicast::validator;
485
486void IPV6MulticastValidator::operator()(const in6_addr address) const
487{
488#ifdef CCXX_EXCEPTIONS
489 // "0000:" is always accepted, as it is an "empty" address.
490 if ( (address.s6_addr[0] != 0 || address.s6_addr[1] != 0) &&
491 (address.s6_addr[0] != 0xff || address.s6_addr[1] < 0x1f)) {
492 throw "Multicast address not in the valid prefix ff00-ff1f:";
493 }
494#endif
495}
496
497IPV6Address::IPV6Address(const IPV6Validator *_validator) :
498validator(_validator), hostname(NULL)
499{
500 addr_count = 1;
501 ipaddr = new struct in6_addr[1];
502 memcpy(ipaddr, &in6addr_any, sizeof(struct in6_addr));
503}
504
505IPV6Address::IPV6Address(const char *address, const IPV6Validator *_validator) :
506validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL)
507{
508 if(address == 0 || !strcmp(address, "*"))
509 setAddress(NULL);
510 else
511 setAddress(address);
512}
513
514IPV6Address::IPV6Address(struct in6_addr addr, const IPV6Validator *_validator) :
515validator(_validator), ipaddr(NULL), hostname(NULL)
516{
517 if ( this->validator ) {
518 (*validator)(addr);
519 }
520 addr_count = 1;
521 ipaddr = new struct in6_addr[1];
522 memcpy(&ipaddr, &addr, sizeof(struct in6_addr));
523}
524
525IPV6Address::IPV6Address(const IPV6Address &rhs) :
526 validator(rhs.validator), addr_count(rhs.addr_count), hostname(NULL) {
527 ipaddr = new struct in6_addr[addr_count];
528 memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count);
529}
530
531IPV6Address::~IPV6Address()
532{
533 if(ipaddr) {
534 delete[] ipaddr;
535 ipaddr = NULL;
536 }
537 if(hostname) {
538 delString(hostname);
539 hostname = NULL;
540 }
541}
542
543struct in6_addr IPV6Address::getAddress(void) const
544{
545 return ipaddr[0];
546}
547
548struct in6_addr IPV6Address::getAddress(size_t i) const
549{
550 return (i < addr_count ? ipaddr[i] : ipaddr[0]);
551}
552
553bool IPV6Address::isInetAddress(void) const
554{
555 struct in6_addr addr;
556 memset(&addr, 0, sizeof(addr));
557 if(!ipaddr)
558 return false;
559 if(memcmp(&addr, &ipaddr[0], sizeof(addr)))
560 return true;
561 return false;
562}
563
564IPV6Address &IPV6Address::operator=(const char *str)
565{
566 if(str == 0 || !strcmp(str, "*"))
567 str = "::";
568
569 setAddress(str);
570
571 return *this;
572}
573
574IPV6Address &IPV6Address::operator=(struct in6_addr addr)
575{
576 if(ipaddr)
577 delete[] ipaddr;
578 if ( validator )
579 (*validator)(addr);
580 addr_count = 1;
581 ipaddr = new struct in6_addr[1];
582 ipaddr[0] = addr;
583 if(hostname)
584 delString(hostname);
585 hostname = NULL;
586 return *this;
587}
588
589IPV6Address &IPV6Address::operator=(const IPV6Address &rhs)
590{
591 if(this == &rhs) return *this;
592
593 addr_count = rhs.addr_count;
594 if(ipaddr)
595 delete[] ipaddr;
596 ipaddr = new struct in6_addr[addr_count];
597 memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count);
598 validator = rhs.validator;
599 if(hostname)
600 delString(hostname);
601 hostname = NULL;
602
603 return *this;
604}
605
606bool IPV6Address::operator==(const IPV6Address &a) const
607{
608 const IPV6Address *smaller, *larger;
609 size_t s, l;
610
611 if(addr_count > a.addr_count) {
612 smaller = &a;
613 larger = this;
614 }
615 else {
616 smaller = this;
617 larger = &a;
618 }
619
620 // Loop through all addr's in the smaller and make sure
621 // that they are all in the larger
622 for(s = 0; s < smaller->addr_count; s++) {
623 // bool found = false;
624 for(l = 0; l < larger->addr_count &&
625 memcmp((char *)&smaller->ipaddr[s], (char *)&larger->ipaddr[l], sizeof(struct in6_addr)); l++);
626 if(l == larger->addr_count) return false;
627 }
628 return true;
629}
630
631bool IPV6Address::operator!=(const IPV6Address &a) const
632{
633 // Impliment in terms of operator==
634 return (*this == a ? false : true);
635}
636
637IPV6Host &IPV6Host::operator&=(const IPV6Mask &ma)
638{
639 for(size_t i = 0; i < addr_count; i++) {
640 struct in6_addr mask = ma.getAddress();
641 unsigned char *a = (unsigned char *)&ipaddr[i];
642 unsigned char *m = (unsigned char *)&mask;
643
644 for(size_t j = 0; j < sizeof(struct in6_addr); ++j)
645 *(a++) &= *(m++);
646 }
647 if(hostname)
648 delString(hostname);
649 hostname = NULL;
650
651 return *this;
652}
653
654IPV6Host::IPV6Host(struct in6_addr addr) :
655IPV6Address(addr) {}
656
657IPV6Host::IPV6Host(const char *host) :
658IPV6Address(host)
659{
660 char namebuf[256];
661
662 if(!host) {
663 gethostname(namebuf, 256);
664 setAddress(namebuf);
665 }
666}
667
668bool IPV6Address::setIPAddress(const char *host)
669{
670 if(!host)
671 return false;
672
673 struct in6_addr l_addr;
674
675#ifdef _MSWINDOWS_
676 struct sockaddr saddr;
677 int slen = sizeof(saddr);
678 struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr;
679 int ok = WSAStringToAddress((LPSTR)host, AF_INET6, NULL, &saddr, &slen);
680 l_addr = paddr->sin6_addr;
681#else
682 int ok = inet_pton(AF_INET6, host, &l_addr);
683#endif
684 if ( validator )
685 (*validator)(l_addr);
686 if ( !ok )
687 return false;
688 *this = l_addr;
689 return true;
690}
691
692#if defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME2)
693
694void IPV6Address::setAddress(const char *host)
695{
696 if(hostname)
697 delString(hostname);
698 hostname = NULL;
699
700 if(!host) // The way this is currently used, this can never happen
701 host = "::";
702
703#ifdef _MSWINDOWS_
704 if(!stricmp(host, "localhost"))
705 host = "::1";
706#endif
707
708 if(!setIPAddress(host)) {
709 struct addrinfo hint, *list = NULL, *first;
710 memset(&hint, 0, sizeof(hint));
711 hint.ai_family = AF_INET6;
712 struct in6_addr *addr;
713 struct sockaddr_in6 *ip6addr;
714
715 if(getaddrinfo(host, NULL, &hint, &list) || !list) {
716 if(ipaddr)
717 delete[] ipaddr;
718 ipaddr = new struct in6_addr[1];
719 memset((void *)&ipaddr[0], 0, sizeof(struct in6_addr));
720 return;
721 }
722
723 // Count the number of IP addresses returned
724 addr_count = 0;
725 first = list;
726 while(list) {
727 ++addr_count;
728 list = list->ai_next;
729 }
730
731 // Allocate enough memory
732 if(ipaddr)
733 delete[] ipaddr; // Cause this was allocated in base
734 ipaddr = new struct in6_addr[addr_count];
735
736 // Now go through the list again assigning to
737 // the member ipaddr;
738 list = first;
739 int i = 0;
740 while(list) {
741 ip6addr = (struct sockaddr_in6 *)list->ai_addr;
742 addr = &ip6addr->sin6_addr;
743 if(validator)
744 (*validator)(*addr);
745 ipaddr[i++] = *addr;
746 list = list->ai_next;
747 }
748 freeaddrinfo(first);
749 }
750}
751
752#else
753
754void IPV6Address::setAddress(const char *host)
755{
756 if(hostname)
757 delString(hostname);
758 hostname = NULL;
759
760 if(!host) // The way this is currently used, this can never happen
761 host = "::";
762
763#ifdef _MSWINDOWS_
764 if(!stricmp(host, "localhost"))
765 host = "::1";
766#endif
767
768 if(!setIPAddress(host)) {
769 struct hostent *hp;
770 struct in6_addr **bptr;
771#if defined(__GLIBC__)
772 char hbuf[8192];
773 struct hostent hb;
774 int rtn;
775
776 if(gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn))
777 hp = NULL;
778#elif defined(sun)
779 char hbuf[8192];
780 struct hostent hb;
781 int rtn;
782
783 hp = gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &rtn);
784#elif (defined(__osf__) || defined(_OSF_SOURCE) || defined(__hpux))
785 hp = gethostbyname(host);
786#elif defined(_MSWINDOWS_) && (!defined(_MSC_VER) || _MSC_VER < 1300)
787 hp = gethostbyname(host);
788#elif defined(_MSWINDOWS_)
789 hp = gethostbyname2(host, AF_INET6);
790#else
791 mutex.enterMutex();
792 hp = gethostbyname2(host, AF_INET6);
793 mutex.leaveMutex();
794#endif
795 if(!hp) {
796 if(ipaddr)
797 delete[] ipaddr;
798 ipaddr = new struct in6_addr[1];
799 memset((void *)&ipaddr[0], 0, sizeof(struct in6_addr));
800 return;
801 }
802
803 // Count the number of IP addresses returned
804 addr_count = 0;
805 for(bptr = (struct in6_addr **)hp->h_addr_list; *bptr != NULL; bptr++) {
806 addr_count++;
807 }
808
809 // Allocate enough memory
810 if(ipaddr)
811 delete[] ipaddr; // Cause this was allocated in base
812 ipaddr = new struct in6_addr[addr_count];
813
814 // Now go through the list again assigning to
815 // the member ipaddr;
816 bptr = (struct in6_addr **)hp->h_addr_list;
817 for(unsigned int i = 0; i < addr_count; i++) {
818 if ( validator )
819 (*validator)(*bptr[i]);
820 ipaddr[i] = *bptr[i];
821 }
822 }
823}
824
825#endif
826
827IPV6Broadcast::IPV6Broadcast(const char *net) :
828IPV6Address(net)
829{
830}
831
832IPV6Mask::IPV6Mask(const char *mask) :
833IPV6Address(mask)
834{
835}
836
837const char *IPV6Address::getHostname(void) const
838{
839 struct hostent *hp = NULL;
840 struct in6_addr addr0;
841 static char strbuf[64];
842
843 memset(&addr0, 0, sizeof(addr0));
844 if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0)))
845 return NULL;
846
847 if(!memcmp(&in6addr_loopback, &ipaddr[0], sizeof(addr0)))
848 return "localhost";
849
850#if defined(__GLIBC__)
851 char hbuf[8192];
852 struct hostent hb;
853 int rtn;
854 if(gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn))
855 hp = NULL;
856#elif defined(sun)
857 char hbuf[8192];
858 struct hostent hb;
859 int rtn;
860 hp = gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, (int)sizeof(hbuf), &rtn);
861#elif defined(__osf__) || defined(_MSWINDOWS_)
862 hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6);
863#else
864 mutex.enterMutex();
865 hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6);
866 mutex.leaveMutex();
867#endif
868 if(hp) {
869 if(hostname)
870 delString(hostname);
871 hostname = newString(hp->h_name);
872 return hostname;
873 } else {
874#ifdef _MSWINDOWS_
875 struct sockaddr saddr;
876 struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr;
877 DWORD slen = sizeof(strbuf);
878 memset(&saddr, 0, sizeof(saddr));
879 paddr->sin6_family = AF_INET6;
880 paddr->sin6_addr = ipaddr[0];
881 WSAAddressToString(&saddr, sizeof(saddr), NULL, strbuf, &slen);
882 return strbuf;
883#else
884 return inet_ntop(AF_INET6, &ipaddr[0], strbuf, sizeof(strbuf));
885#endif
886 }
887}
888
889IPV6Host operator&(const IPV6Host &addr, const IPV6Mask &mask)
890{
891 IPV6Host temp = addr;
892 temp &= mask;
893 return temp;
894}
895
896IPV6Multicast::IPV6Multicast() :
897IPV6Address(&validator)
898{}
899
900IPV6Multicast::IPV6Multicast(const char *address) :
901IPV6Address(address,&validator)
902{}
903
904#endif
905
906NAMESPACE_COMMONCPP
907using namespace std;
908
909ostream& operator<<(ostream &os, const IPV4Address &ia)
910{
911 os << inet_ntoa(getaddress(ia));
912 return os;
913}
914
915END_NAMESPACE
916
917typedef unsigned char bit_t;
918
919static void bitmask(bit_t *bits, bit_t *mask, unsigned len)
920{
921 while(len--)
922 *(bits++) &= *(mask++);
923}
924
925static void bitimask(bit_t *bits, bit_t *mask, unsigned len)
926{
927 while(len--)
928 *(bits++) |= ~(*(mask++));
929}
930
931static void bitset(bit_t *bits, unsigned blen)
932{
933 bit_t mask;
934
935 while(blen) {
936 mask = (bit_t)(1 << 7);
937 while(mask && blen) {
938 *bits |= mask;
939 mask >>= 1;
940 --blen;
941 }
942 ++bits;
943 }
944}
945
946static unsigned bitcount(bit_t *bits, unsigned len)
947{
948 unsigned count = 0;
949 bit_t mask, test;
950
951 while(len--) {
952 mask = (bit_t)(1<<7);
953 test = *bits++;
954 while(mask) {
955 if(!(mask & test))
956 return count;
957 ++count;
958 mask >>= 1;
959 }
960 }
961 return count;
962}
963
964IPV4Cidr::IPV4Cidr()
965{
966 memset(&network, 0, sizeof(network));
967 memset(&netmask, 0, sizeof(netmask));
968}
969
970IPV4Cidr::IPV4Cidr(const char *cp)
971{
972 set(cp);
973}
974
975IPV4Cidr::IPV4Cidr(IPV4Cidr &cidr)
976{
977 memcpy(&network, &cidr.network, sizeof(network));
978 memcpy(&netmask, &cidr.netmask, sizeof(netmask));
979}
980
981bool IPV4Cidr::isMember(const struct in_addr &addr) const
982{
983 struct in_addr host = addr;
984
985 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
986 if(!memcmp(&host, &network, sizeof(host)))
987 return true;
988
989 return false;
990}
991
992bool IPV4Cidr::isMember(const struct sockaddr *saddr) const
993{
994 struct sockaddr_in *addr = (struct sockaddr_in *)saddr;
995 struct in_addr host;
996
997 if(saddr->sa_family != AF_INET)
998 return false;
999
1000 memcpy(&host, &addr->sin_addr.s_addr, sizeof(host));
1001 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
1002 if(!memcmp(&host, &network, sizeof(host)))
1003 return true;
1004
1005 return false;
1006}
1007
1008struct in_addr IPV4Cidr::getBroadcast(void) const
1009{
1010 struct in_addr bcast;
1011 memcpy(&bcast, &network, sizeof(network));
1012 bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast));
1013 return bcast;
1014}
1015
1016unsigned IPV4Cidr::getMask(const char *cp) const
1017{
1018 unsigned dcount = 0;
1019 const char *gp = cp;
1020 const char *mp = strchr(cp, '/');
1021 unsigned char dots[4];
1022#ifdef _MSWINDOWS_
1023 DWORD mask;
1024#else
1025 uint32_t mask;
1026#endif
1027
1028 if(mp) {
1029 if(!strchr(++mp, '.'))
1030 return atoi(mp);
1031
1032 mask = inet_addr(mp);
1033 return bitcount((bit_t *)&mask, sizeof(mask));
1034 }
1035
1036 memset(dots, 0, sizeof(dots));
1037 dots[0] = atoi(cp);
1038 while(*gp && dcount < 3) {
1039 if(*(gp++) == '.')
1040 dots[++dcount] = atoi(gp);
1041 }
1042
1043 if(dots[3])
1044 return 32;
1045
1046 if(dots[2])
1047 return 24;
1048
1049 if(dots[1])
1050 return 16;
1051
1052 return 8;
1053}
1054
1055void IPV4Cidr::set(const char *cp)
1056{
1057 char cbuf[INET_IPV4_ADDRESS_SIZE];
1058 char *ep;
1059 unsigned dots = 0;
1060#ifdef _MSWINDOWS_
1061 DWORD addr;
1062#endif
1063
1064 memset(&netmask, 0, sizeof(netmask));
1065 bitset((bit_t *)&netmask, getMask(cp));
1066 setString(cbuf, sizeof(cbuf), cp);
1067
1068 ep = (char *)strchr(cp, '/');
1069
1070 if(ep)
1071 *ep = 0;
1072
1073 cp = cbuf;
1074 while(NULL != (cp = strchr(cp, '.'))) {
1075 ++dots;
1076 ++cp;
1077 }
1078
1079 while(dots++ < 3)
1080 addString(cbuf, sizeof(cbuf), ".0");
1081
1082#ifdef _MSWINDOWS_
1083 addr = inet_addr(cbuf);
1084 memcpy(&network, &addr, sizeof(network));
1085#else
1086 inet_aton(cbuf, &network);
1087#endif
1088 bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network));
1089}
1090
1091
1092
1093
1094#ifdef CCXX_IPV6
1095
1096IPV6Cidr::IPV6Cidr()
1097{
1098 memset(&network, 0, sizeof(network));
1099 memset(&netmask, 0, sizeof(netmask));
1100}
1101
1102IPV6Cidr::IPV6Cidr(const char *cp)
1103{
1104 set(cp);
1105}
1106
1107IPV6Cidr::IPV6Cidr(IPV6Cidr &cidr)
1108{
1109 memcpy(&network, &cidr.network, sizeof(network));
1110 memcpy(&netmask, &cidr.netmask, sizeof(netmask));
1111}
1112
1113bool IPV6Cidr::isMember(const struct in6_addr &addr) const
1114{
1115 struct in6_addr host = addr;
1116
1117 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
1118 if(!memcmp(&host, &network, sizeof(host)))
1119 return true;
1120
1121 return false;
1122}
1123
1124bool IPV6Cidr::isMember(const struct sockaddr *saddr) const
1125{
1126 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)saddr;
1127 struct in6_addr host;
1128
1129 if(saddr->sa_family != AF_INET6)
1130 return false;
1131
1132 memcpy(&host, &addr->sin6_addr, sizeof(host));
1133 bitmask((bit_t *)&host, (bit_t *)&netmask, sizeof(host));
1134 if(!memcmp(&host, &network, sizeof(host)))
1135 return true;
1136
1137 return false;
1138}
1139
1140struct in6_addr IPV6Cidr::getBroadcast(void) const
1141{
1142 struct in6_addr bcast;
1143 memcpy(&bcast, &network, sizeof(network));
1144 bitimask((bit_t *)&bcast, (bit_t *)&netmask, sizeof(bcast));
1145 return bcast;
1146}
1147
1148unsigned IPV6Cidr::getMask(const char *cp) const
1149{
1150 unsigned count = 0, rcount = 0;
1151 const char *sp = strchr(cp, '/');
1152 int flag = 0;
1153
1154 if(sp)
1155 return atoi(++sp);
1156
1157 if(!strncmp(cp, "ff00:", 5))
1158 return 8;
1159
1160 if(!strncmp(cp, "fe80:", 5))
1161 return 10;
1162
1163 if(!strncmp(cp, "2002:", 5))
1164 return 16;
1165
1166 sp = strrchr(cp, ':');
1167 while(*(++sp) == '0')
1168 ++sp;
1169 if(*sp)
1170 return 128;
1171
1172 while(*cp && count < 128) {
1173 if(*(cp++) == ':') {
1174 count+= 16;
1175 while(*cp == '0')
1176 ++cp;
1177 if(*cp == ':') {
1178 if(!flag)
1179 rcount = count;
1180 flag = 1;
1181 }
1182 else
1183 flag = 0;
1184 }
1185 }
1186 return rcount;
1187}
1188
1189void IPV6Cidr::set(const char *cp)
1190{
1191 char cbuf[INET_IPV6_ADDRESS_SIZE];
1192 char *ep;
1193
1194 memset(&netmask, 0, sizeof(netmask));
1195 bitset((bit_t *)&netmask, getMask(cp));
1196 setString(cbuf, sizeof(cbuf), cp);
1197 ep = (char *)strchr(cp, '/');
1198 if(ep)
1199 *ep = 0;
1200
1201#ifdef _MSWINDOWS_
1202 int slen = sizeof(network);
1203 WSAStringToAddressA(cbuf, AF_INET6, NULL, (struct sockaddr*)&network, &slen);
1204#else
1205 inet_pton(AF_INET6, cbuf, &network);
1206#endif
1207 bitmask((bit_t *)&network, (bit_t *)&netmask, sizeof(network));
1208}
1209
1210#endif
1211