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