blob: 4c6804726449b8343505a61426e140a5646429f6 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// 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 <cc++/config.h>
40#include <cc++/export.h>
41#include <cc++/address.h>
42#include "private.h"
43#include <cstdlib>
44
45#ifdef CCXX_IPV6
46
47#ifdef CCXX_NAMESPACES
48namespace ost {
49#endif
50
51#ifndef WIN32
52Mutex IPV6Address::mutex;
53#endif
54
55const IPV6MulticastValidator IPV6Multicast::validator;
56
57void IPV6MulticastValidator::operator()(const in6_addr address) const
58{
59#ifdef CCXX_EXCEPTIONS
60 // "0000:" is always accepted, as it is an "empty" address.
61 if ( (address.s6_addr[0] != 0 || address.s6_addr[1] != 0) &&
62 (address.s6_addr[0] != 0xff || address.s6_addr[1] < 0x1f)) {
63 throw "Multicast address not in the valid prefix ff00-ff1f:";
64 }
65#endif
66}
67
68IPV6Address::IPV6Address(const IPV6Validator *_validator)
69 : validator(_validator), hostname(NULL) {
70 addr_count = 1;
71 ipaddr = new struct in6_addr[1];
72 memcpy(ipaddr, &in6addr_any, sizeof(in6_addr));
73}
74
75IPV6Address::IPV6Address(const char *address, const IPV6Validator *_validator) :
76 validator(_validator), ipaddr(NULL), addr_count(0), hostname(NULL) {
77 if ( this->validator )
78 this->validator = validator;
79 if(address == 0 || !strcmp(address, "*"))
80 setAddress(NULL);
81 else
82 setAddress(address);
83}
84
85IPV6Address::IPV6Address(struct in6_addr addr, const IPV6Validator *_validator) :
86 validator(_validator), ipaddr(NULL), hostname(NULL) {
87 if ( this->validator ){
88 this->validator = validator;
89 (*validator)(addr);
90 }
91 addr_count = 1;
92 ipaddr = new struct in6_addr[1];
93 memcpy(&ipaddr, &addr, sizeof(struct in6_addr));
94}
95
96IPV6Address::IPV6Address(const IPV6Address &rhs) :
97 validator(rhs.validator), addr_count(rhs.addr_count), hostname(NULL) {
98 ipaddr = new struct in6_addr[addr_count];
99 memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count);
100}
101
102IPV6Address::~IPV6Address()
103{
104 if(ipaddr) {
105 delete[] ipaddr;
106 ipaddr = NULL;
107 }
108 if(hostname) {
109 delString(hostname);
110 hostname = NULL;
111 }
112}
113
114struct in6_addr IPV6Address::getAddress(void) const
115{
116 return ipaddr[0];
117}
118
119struct in6_addr IPV6Address::getAddress(size_t i) const
120{
121 return (i < addr_count ? ipaddr[i] : ipaddr[0]);
122}
123
124bool IPV6Address::isInetAddress(void) const
125{
126 struct in6_addr addr;
127 memset(&addr, 0, sizeof(addr));
128 if(!ipaddr)
129 return false;
130 if(memcmp(&addr, &ipaddr[0], sizeof(addr)))
131 return true;
132 return false;
133}
134
135IPV6Address &IPV6Address::operator=(const char *str)
136{
137 if(str == 0 || !strcmp(str, "*"))
138 str = "::";
139
140 setAddress(str);
141
142 return *this;
143}
144
145IPV6Address &IPV6Address::operator=(struct in6_addr addr)
146{
147 if(ipaddr)
148 delete[] ipaddr;
149 if ( validator )
150 (*validator)(addr);
151 addr_count = 1;
152 ipaddr = new struct in6_addr[1];
153 ipaddr[0] = addr;
154 if(hostname)
155 delString(hostname);
156 hostname = NULL;
157 return *this;
158}
159
160IPV6Address &IPV6Address::operator=(const IPV6Address &rhs)
161{
162 if(this == &rhs) return *this;
163
164 addr_count = rhs.addr_count;
165 if(ipaddr)
166 delete[] ipaddr;
167 ipaddr = new struct in6_addr[addr_count];
168 memcpy(ipaddr, rhs.ipaddr, sizeof(struct in6_addr) * addr_count);
169 validator = rhs.validator;
170 if(hostname)
171 delString(hostname);
172 hostname = NULL;
173
174 return *this;
175}
176
177bool IPV6Address::operator==(const IPV6Address &a) const
178{
179 const IPV6Address *smaller, *larger;
180 size_t s, l;
181
182 if(addr_count > a.addr_count) {
183 smaller = &a;
184 larger = this;
185 }
186 else {
187 smaller = this;
188 larger = &a;
189 }
190
191 // Loop through all addr's in the smaller and make sure
192 // that they are all in the larger
193 for(s = 0; s < smaller->addr_count; s++) {
194 // bool found = false;
195 for(l = 0; l < larger->addr_count &&
196 memcmp((char *)&ipaddr[s], (char *)&a.ipaddr[l], sizeof(struct in6_addr)); l++);
197 if(l == larger->addr_count) return false;
198 }
199 return true;
200}
201
202bool IPV6Address::operator!=(const IPV6Address &a) const
203{
204 // Impliment in terms of operator==
205 return (*this == a ? false : true);
206}
207
208IPV6Host &IPV6Host::operator&=(const IPV6Mask &ma)
209{
210 for(size_t i = 0; i < addr_count; i++) {
211 struct in6_addr mask = ma.getAddress();
212 unsigned char *a = (unsigned char *)&ipaddr[i];
213 unsigned char *m = (unsigned char *)&mask;
214
215 for(size_t j = 0; j < sizeof(struct in6_addr); ++j)
216 *(a++) &= *(m++);
217 }
218 if(hostname)
219 delString(hostname);
220 hostname = NULL;
221
222 return *this;
223}
224
225IPV6Host::IPV6Host(struct in6_addr addr) :
226IPV6Address(addr) {}
227
228IPV6Host::IPV6Host(const char *host) :
229IPV6Address(host)
230{
231 char namebuf[256];
232
233 if(!host) {
234 gethostname(namebuf, 256);
235 setAddress(namebuf);
236 }
237}
238
239bool IPV6Address::setIPAddress(const char *host)
240{
241 if(!host)
242 return false;
243
244 struct in6_addr l_addr;
245
246#ifdef WIN32
247 struct sockaddr saddr;
248 int slen = sizeof(saddr);
249 struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr;
250 int ok = WSAStringToAddress((LPSTR)host, AF_INET6, NULL, &saddr, &slen);
251 l_addr = paddr->sin6_addr;
252#else
253 int ok = inet_pton(AF_INET6, host, &l_addr);
254#endif
255 if ( validator )
256 (*validator)(l_addr);
257 if ( !ok )
258 return false;
259 *this = l_addr;
260 return true;
261}
262
263#if defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME2)
264
265void IPV6Address::setAddress(const char *host)
266{
267 if(hostname)
268 delString(hostname);
269 hostname = NULL;
270
271 if(!host) // The way this is currently used, this can never happen
272 host = "::";
273
274#ifdef WIN32
275 if(!stricmp(host, "localhost"))
276 host = "::1";
277#endif
278
279 if(!setIPAddress(host)) {
280 struct addrinfo hint, *list = NULL, *first;
281 memset(&hint, 0, sizeof(hint));
282 hint.ai_family = AF_INET6;
283 struct in6_addr *addr;
284 struct sockaddr_in6 *ip6addr;
285
286 if(getaddrinfo(host, NULL, &hint, &list) || !list) {
287 if(ipaddr)
288 delete[] ipaddr;
289 ipaddr = new struct in6_addr[1];
290 memset((void *)&ipaddr[0], 0, sizeof(ipaddr));
291 return;
292 }
293
294 // Count the number of IP addresses returned
295 addr_count = 0;
296 first = list;
297 while(list) {
298 ++addr_count;
299 list = list->ai_next;
300 }
301
302 // Allocate enough memory
303 if(ipaddr)
304 delete[] ipaddr; // Cause this was allocated in base
305 ipaddr = new struct in6_addr[addr_count];
306
307 // Now go through the list again assigning to
308 // the member ipaddr;
309 list = first;
310 int i = 0;
311 while(list) {
312 ip6addr = (struct sockaddr_in6 *)list->ai_addr;
313 addr = &ip6addr->sin6_addr;
314 if(validator)
315 (*validator)(*addr);
316 ipaddr[i++] = *addr;
317 list = list->ai_next;
318 }
319 freeaddrinfo(first);
320 }
321}
322
323#else
324
325void IPV6Address::setAddress(const char *host)
326{
327 if(hostname)
328 delString(hostname);
329 hostname = NULL;
330
331 if(!host) // The way this is currently used, this can never happen
332 host = "::";
333
334#ifdef WIN32
335 if(!stricmp(host, "localhost"))
336 host = "::1";
337#endif
338
339 if(!setIPAddress(host)) {
340 struct hostent *hp;
341 struct in6_addr **bptr;
342#if defined(__GLIBC__)
343 char hbuf[8192];
344 struct hostent hb;
345 int rtn;
346
347 if(gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn))
348 hp = NULL;
349#elif defined(sun)
350 char hbuf[8192];
351 struct hostent hb;
352 int rtn;
353
354 hp = gethostbyname2_r(host, AF_INET6, &hb, hbuf, sizeof(hbuf), &rtn);
355#elif (defined(__osf__) || defined(_OSF_SOURCE) || defined(__hpux))
356 hp = gethostbyname(host);
357#elif defined(WIN32) && (!defined(_MSC_VER) || _MSC_VER < 1300)
358 hp = gethostbyname(host);
359#elif defined(WIN32)
360 hp = gethostbyname2(host, AF_INET6);
361#else
362 mutex.enterMutex();
363 hp = gethostbyname2(host, AF_INET6);
364 mutex.leaveMutex();
365#endif
366 if(!hp) {
367 if(ipaddr)
368 delete[] ipaddr;
369 ipaddr = new struct in6_addr[1];
370 memset((void *)&ipaddr[0], 0, sizeof(ipaddr));
371 return;
372 }
373
374 // Count the number of IP addresses returned
375 addr_count = 0;
376 for(bptr = (struct in6_addr **)hp->h_addr_list; *bptr != NULL; bptr++) {
377 addr_count++;
378 }
379
380 // Allocate enough memory
381 if(ipaddr)
382 delete[] ipaddr; // Cause this was allocated in base
383 ipaddr = new struct in6_addr[addr_count];
384
385 // Now go through the list again assigning to
386 // the member ipaddr;
387 bptr = (struct in6_addr **)hp->h_addr_list;
388 for(unsigned int i = 0; i < addr_count; i++) {
389 if ( validator )
390 (*validator)(*bptr[i]);
391 ipaddr[i] = *bptr[i];
392 }
393 }
394}
395
396#endif
397
398IPV6Broadcast::IPV6Broadcast(const char *net) :
399IPV6Address(net)
400{
401}
402
403IPV6Mask::IPV6Mask(const char *mask) :
404IPV6Address(mask)
405{
406}
407
408const char *IPV6Address::getHostname(void) const
409{
410 struct hostent *hp = NULL;
411 struct in6_addr addr0;
412 static char strbuf[64];
413
414 memset(&addr0, 0, sizeof(addr0));
415 if(!memcmp(&addr0, &ipaddr[0], sizeof(addr0)))
416 return NULL;
417
418 if(!memcmp(&in6addr_loopback, &ipaddr[0], sizeof(addr0)))
419 return "localhost";
420
421#if defined(__GLIBC__)
422 char hbuf[8192];
423 struct hostent hb;
424 int rtn;
425 if(gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, sizeof(hbuf), &hp, &rtn))
426 hp = NULL;
427#elif defined(sun)
428 char hbuf[8192];
429 struct hostent hb;
430 int rtn;
431 hp = gethostbyaddr_r((char *)&ipaddr[0], sizeof(addr0), AF_INET6, &hb, hbuf, (int)sizeof(hbuf), &rtn);
432#elif defined(__osf__) || defined(WIN32)
433 hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6);
434#else
435 mutex.enterMutex();
436 hp = gethostbyaddr((char *)&ipaddr[0], sizeof(addr0), AF_INET6);
437 mutex.leaveMutex();
438#endif
439 if(hp) {
440 if(hostname)
441 delString(hostname);
442 hostname = newString(hp->h_name);
443 return hostname;
444 } else {
445#ifdef WIN32
446 struct sockaddr saddr;
447 struct sockaddr_in6 *paddr = (struct sockaddr_in6 *)&saddr;
448 DWORD slen = sizeof(strbuf);
449 memset(&saddr, 0, sizeof(saddr));
450 paddr->sin6_family = AF_INET6;
451 paddr->sin6_addr = ipaddr[0];
452 WSAAddressToString(&saddr, sizeof(saddr), NULL, strbuf, &slen);
453 return strbuf;
454#else
455 return inet_ntop(AF_INET6, &ipaddr[0], strbuf, sizeof(strbuf));
456#endif
457 }
458}
459
460IPV6Host operator&(const IPV6Host &addr, const IPV6Mask &mask)
461{
462 IPV6Host temp = addr;
463 temp &= mask;
464 return temp;
465}
466
467IPV6Multicast::IPV6Multicast() :
468IPV6Address(&validator)
469{}
470
471IPV6Multicast::IPV6Multicast(const char *address) :
472IPV6Address(address,&validator)
473{}
474
475#ifdef CCXX_NAMESPACES
476}
477#endif
478
479#endif
480
481/** EMACS **
482 * Local variables:
483 * mode: c++
484 * c-basic-offset: 4
485 * End:
486 */