blocxx
SocketAddress.cpp
Go to the documentation of this file.
1/*******************************************************************************
2* Copyright (C) 2005, Vintela, Inc. All rights reserved.
3* Copyright (C) 2006, Novell, Inc. All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* * Redistributions of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of
14* Vintela, Inc.,
15* nor Novell, Inc.,
16* nor the names of its contributors or employees may be used to
17* endorse or promote products derived from this software without
18* specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30* POSSIBILITY OF SUCH DAMAGE.
31*******************************************************************************/
32
33
38
39#include "blocxx/BLOCXX_config.h"
41#include "blocxx/ByteSwap.hpp"
42#include "blocxx/Assertion.hpp"
43#include "blocxx/Mutex.hpp"
44#include "blocxx/MutexLock.hpp"
46#include "blocxx/Format.hpp"
47
48extern "C"
49{
50#if !defined(BLOCXX_WIN32)
51#include <netdb.h>
52#include <netinet/in.h>
53#include <arpa/inet.h>
54#include <sys/param.h>
55#include <sys/utsname.h>
56#include <unistd.h>
57#endif
58
59#include <errno.h>
60}
61
62namespace BLOCXX_NAMESPACE
63{
64
65#ifdef BLOCXX_WIN32
66
67#include <WS2tcpip.h>
68
69const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
70{
71 if (af == AF_INET)
72 {
73 struct sockaddr_in in;
74 memset(&in, 0, sizeof(in));
75 in.sin_family = AF_INET;
76 memcpy(&in.sin_addr, src, sizeof(struct in_addr));
77 getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST);
78 return dst;
79 }
80 else if (af == AF_INET6)
81 {
82 struct sockaddr_in6 in;
83 memset(&in, 0, sizeof(in));
84 in.sin6_family = AF_INET6;
85 memcpy(&in.sin6_addr, src, sizeof(struct in_addr6));
86 getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST);
87 return dst;
88 }
89 return NULL;
90}
91#endif
92
95
96const char* const SocketAddress::ALL_LOCAL_ADDRESSES = "0.0.0.0";
97
98#if !defined(BLOCXX_WIN32)
100//static
103{
104 SocketAddress rval;
105 rval.m_type = UDS;
106 rval.m_name = filename;
107 rval.m_address = "localhost";
108 memset(&rval.m_UDSNativeAddress, 0, sizeof(rval.m_UDSNativeAddress));
109 rval.m_UDSNativeAddress.sun_family = AF_UNIX;
110 strncpy(rval.m_UDSNativeAddress.sun_path, filename.c_str(),
111 sizeof(rval.m_UDSNativeAddress.sun_path) - 1);
112 if (::strlen(rval.m_UDSNativeAddress.sun_path) != filename.length())
113 {
114 BLOCXX_THROW(SocketAddressException, Format("UDS filename (%1) is too long", filename).c_str());
115 }
116#ifdef BLOCXX_SOLARIS
117 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path) +
118 offsetof(struct sockaddr_un, sun_path);
119#elif defined BLOCXX_OPENUNIX
120 rval.m_UDSNativeAddress.sun_len = sizeof(rval.m_UDSNativeAddress);
121 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path) +
122 offsetof(struct sockaddr_un, sun_path);
123#elif defined BLOCXX_AIX || defined BLOCXX_DARWIN
124 // AIX requires the NULL terminator to be included in the sizes.
125 rval.m_UDSNativeAddress.sun_len = filename.length() + 1;
126 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path) +
127 offsetof(struct sockaddr_un, sun_path) + 1;
128#elif defined BLOCXX_FREEBSD
129 rval.m_nativeSize = ::strlen(rval.m_UDSNativeAddress.sun_path)
130 + sizeof(rval.m_UDSNativeAddress.sun_len)
131 + sizeof(rval.m_UDSNativeAddress.sun_family);
132#else
133 rval.m_nativeSize = sizeof(rval.m_UDSNativeAddress.sun_family) +
134 ::strlen(rval.m_UDSNativeAddress.sun_path);
135#endif
136 return rval;
137}
138
139#endif // #if !defined(BLOCXX_WIN32)
140
146
147#ifndef BLOCXX_HAVE_GETHOSTBYNAME_R
149#endif
150
152//static
154SocketAddress::getByName(const String& hostName, UInt16 port)
155{
156#ifdef BLOCXX_HAVE_IPV6
157 // create SocketAddress structure for IPV6 protocol
159 memset(&sa, 0, sizeof(sa));
160 if( inet_pton(AF_INET6, hostName.c_str(), (void*)&(reinterpret_cast<sockaddr_in6*>(&sa)->sin6_addr)))
161 {
162 reinterpret_cast<sockaddr_in6*>(&sa)->sin6_family = AF_INET6;
163 reinterpret_cast<sockaddr_in6*>(&sa)->sin6_port = htons(port);
165 p.m_type = INET;
166 p.m_name = hostName;
167 return p;
168 }
169#endif
170#if defined(BLOCXX_HAVE_GETHOSTBYNAME_R) && defined(BLOCXX_GETHOSTBYNAME_R_ARGUMENTS)
171 hostent hostbuf;
172 hostent* host = &hostbuf;
173#if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6)
174 char buf[2048];
175 int h_err = 0;
176 if (gethostbyname_r(hostName.c_str(), &hostbuf, buf, sizeof(buf),
177 &host, &h_err) == -1)
178 {
179 host = NULL;
180 }
181#elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5)
182
183 char buf[2048];
184 int h_err(0);
185 // returns NULL if not successful
186 host = gethostbyname_r(hostName.c_str(), &hostbuf, buf, sizeof(buf), &h_err);
187
188#elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3)
189 hostent_data hostdata;
190 if (gethostbyname_r(hostName.c_str(), &hostbuf, &hostdata) != 0)
191 {
192 host = NULL;
193 }
194
195#else
196#error Not yet supported: gethostbyname_r() with other argument counts.
197#endif /* BLOCXX_GETHOSTBYNAME_R_ARGUMENTS */
198#else
200#if defined(BLOCXX_NCR)
201 hostent* host = gethostbyname(const_cast<char *>(hostName.c_str()));
202#else
203 hostent* host = gethostbyname(hostName.c_str());
204#endif
205#endif /* defined(BLOCXX_HAVE_GETHOSTBYNAME_R) && defined(BLOCXX_GETHOSTBYNAME_R_ARGUMENTS) */
206
207 if (!host)
208 {
209 BLOCXX_THROW(UnknownHostException, String("Unknown host: ").concat(hostName).c_str());
210 }
211 in_addr addr;
212 memcpy(&addr, host->h_addr_list[0], sizeof(addr));
213 return getFromNativeForm(addr, port, host->h_name);
214}
215
217//static
220{
221 return SocketAddress(nativeForm);
222}
223
224#if !defined(BLOCXX_WIN32)
226//static
229{
230 return SocketAddress(nativeForm);
231}
232#endif // !defined(BLOCXX_WIN32)
233
235//static
238 UInt16 nativePort, const String& hostName)
239{
241 memset(&addr, 0, sizeof(addr));
242 reinterpret_cast<sockaddr_in*>(&addr)->sin_family = AF_INET;
243 reinterpret_cast<sockaddr_in*>(&addr)->sin_port = hton16(nativePort);
244 reinterpret_cast<sockaddr_in*>(&addr)->sin_addr = nativeForm;
246 p.m_type = INET;
247 p.m_name = hostName;
248 return p;
249}
250
252{
253 if (m_type == INET)
254 {
255 return reinterpret_cast<const sockaddr*>(&m_inetNativeAddress);
256 }
257
258#if !defined(BLOCXX_WIN32)
259 else if (m_type == UDS)
260 {
261 return reinterpret_cast<const sockaddr*>(&m_UDSNativeAddress);
262 }
263#endif
264
265 return 0;
266}
267
273
274#if !defined(BLOCXX_WIN32)
276// Get a pointer to the UnixSocketAddress_t
277// precondition: getType() == UDS
282#endif
283
287{
288 struct in_addr addr;
289 addr.s_addr = hton32(INADDR_ANY);
290 SocketAddress rval = getFromNativeForm(addr, port, "localhost");
291 char buf[256];
292 gethostname(buf, sizeof(buf));
293 String hname(buf);
294 if (hname.indexOf('.') == String::npos)
295 {
296#if defined(BLOCXX_HAVE_GETHOSTBYNAME_R) && defined(BLOCXX_GETHOSTBYNAME_R_ARGUMENTS)
297 hostent hostbuf;
298 hostent* hent = &hostbuf;
299#if (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 6)
300 char local_buf[2048];
301 int h_err = 0;
302 if (gethostbyname_r(buf, &hostbuf, local_buf, sizeof(local_buf),
303 &hent, &h_err) == -1)
304 {
305 hent = NULL;
306 }
307#elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 5)
308
309 char local_buf[2048];
310 int h_err(0);
311 // returns NULL if not successful
312 hent = gethostbyname_r(buf, &hostbuf, local_buf, sizeof(local_buf), &h_err);
313
314#elif (BLOCXX_GETHOSTBYNAME_R_ARGUMENTS == 3)
315 hostent_data hostdata;
316 if (gethostbyname_r(buf, &hostbuf, &hostdata) != 0)
317 {
318 hent = NULL;
319 }
320
321#else
322#error Not yet supported: gethostbyname_r() with other argument counts.
323#endif /* BLOCXX_GETHOSTBYNAME_R_ARGUMENTS */
324#else
326 hostent* hent = gethostbyname(buf);
327#endif
328 if (hent && hent->h_name && (strlen(hent->h_name) > 0))
329 {
330 hname = String(hent->h_name);
331 }
332 }
333 rval.m_name = hname;
334 return rval;
335}
336
339 const InetSocketAddress_t* address, size_t /*size*/)
340{
341 m_type = INET;
342 memcpy(&m_inetNativeAddress, address, sizeof(m_inetNativeAddress));
343#ifdef BLOCXX_HAVE_IPV6
344 char buf[INET6_ADDRSTRLEN];
345 if ( reinterpret_cast<sockaddr*>(&m_inetNativeAddress)->sa_family==AF_INET6)
346 {
347 m_address = inet_ntop(AF_INET6, &(reinterpret_cast<sockaddr_in6*>(&m_inetNativeAddress)->sin6_addr), buf, sizeof(buf));
348 }
349 else
350 {
351 m_address = inet_ntop(AF_INET, &(reinterpret_cast<sockaddr_in*>(&m_inetNativeAddress)->sin_addr), buf, sizeof(buf));
352 }
353#else
354 m_address = inet_ntoa( reinterpret_cast<sockaddr_in*>(&m_inetNativeAddress)->sin_addr);
355#endif
357}
358
359#if !defined(BLOCXX_WIN32)
362 const UnixSocketAddress_t* address, size_t /*size*/)
363{
364 m_type = UDS;
365 memcpy(&m_UDSNativeAddress, address, sizeof(m_UDSNativeAddress));
366 m_address = "localhost";
367 m_name = m_UDSNativeAddress.sun_path;
369}
370#endif // !defined(BLOCXX_WIN32)
371
374{
376
377#ifdef BLOCXX_HAVE_IPV6
378 if ( reinterpret_cast<const sockaddr*>(&m_inetNativeAddress)->sa_family==AF_INET6)
379 {
380 return ntoh16(reinterpret_cast<const sockaddr_in6*>(&m_inetNativeAddress)->sin6_port);
381 }
382 else
383 {
384 return ntoh16(reinterpret_cast<const sockaddr_in*>(&m_inetNativeAddress)->sin_port);
385 }
386#else
387 return ntoh16(reinterpret_cast<const sockaddr_in*>(&m_inetNativeAddress)->sin_port);
388#endif
389}
390
391#if !defined(BLOCXX_WIN32)
394 : m_nativeSize(0), m_type(UDS)
395{
396 assignFromNativeForm(&nativeForm, sizeof(nativeForm));
397}
398#endif // !defined(BLOCXX_WIN32)
399
403{
404 assignFromNativeForm(&nativeForm, sizeof(nativeForm));
405}
406
409{
410 return m_name;
411}
412
414{
415 return m_address;
416}
417
419{
420 return m_nativeSize;
421}
422
424{
425 if (type == INET)
426 {
428 memset(&addr, 0, sizeof(addr));
429 reinterpret_cast<sockaddr_in*>(&addr)->sin_family = AF_INET;
431 }
432#if !defined(BLOCXX_WIN32)
433 else if (type == UDS)
434 {
435 sockaddr_un addr;
436 memset(&addr, 0, sizeof(addr));
437 addr.sun_family = AF_UNIX;
439 }
440#endif
441
442 BLOCXX_THROW(SocketAddressException, "Bad Address Type");
443}
444
445const String
447{
449 String rval;
450 if (m_type == INET)
451 {
452 rval = getAddress() + ":" + String(UInt32(getPort()));
453 }
454 else
455 {
456 rval = this->m_name;
457 }
458 return rval;
459}
460
461} // end namespace BLOCXX_NAMESPACE
462
#define BLOCXX_ASSERT(CON)
BLOCXX_ASSERT works similar to the assert() macro, but instead of calling abort(),...
Definition Assertion.hpp:57
#define BLOCXX_DEFINE_EXCEPTION_WITH_ID(NAME)
Define a new exception class named <NAME>Exception that derives from Exception.
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
unsigned socklen_t
void assignFromNativeForm(const UnixSocketAddress_t *address, size_t len)
UInt16 getPort() const
Get the port associated with the address.
InetSocketAddress_t m_inetNativeAddress
const String getAddress() const
Returns the IP address of the host.
const SocketAddress_t * getNativeForm() const
const InetSocketAddress_t * getInetAddress() const
Get a pointer to the InetSocketAddress_t precondition: getType() == INET.
const UnixSocketAddress_t * getUnixAddress() const
Get a pointer to the UnixSocketAddress_t precondition: getType() == UDS.
static SocketAddress allocEmptyAddress(AddressType type)
Allocate an empty SocketAddress.
const String getName() const
Returns the hostname (FQDN) of the address.
static const char *const ALL_LOCAL_ADDRESSES
static SocketAddress getFromNativeForm(const InetAddress_t &nativeForm, UInt16 nativePort, const String &hostname)
UnixSocketAddress_t m_UDSNativeAddress
static SocketAddress getAnyLocalHost(UInt16 port=0)
Do a DNS lookup on a hostname and return a list of all addresses that map to that hostname.
static SocketAddress getByName(const String &host, unsigned short port=0)
Do a DNS lookup on a hostname and return an SocketAddress for that host.
const String toString() const
Returns the IP address and the port with a colon in between.
static SocketAddress getUDS(const String &filename)
This String class is an abstract data type that represents as NULL terminated string of characters.
Definition String.hpp:67
const char * c_str() const
Definition String.cpp:905
size_t length() const
Definition String.cpp:354
size_t indexOf(char ch, size_t fromIndex=0) const
Find the first occurence of a given character in this String object.
Definition String.cpp:556
static const size_t npos
Definition String.hpp:742
Taken from RFC 1321.
sockaddr_in InetSocketAddress_t
UInt16 hton16(UInt16 v)
Definition ByteSwap.hpp:91
sockaddr SocketAddress_t
UInt16 ntoh16(UInt16 v)
Definition ByteSwap.hpp:120
UInt32 hton32(UInt32 v)
Definition ByteSwap.hpp:98
sockaddr_un UnixSocketAddress_t