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 
39 #include "blocxx/BLOCXX_config.h"
40 #include "blocxx/SocketAddress.hpp"
41 #include "blocxx/ByteSwap.hpp"
42 #include "blocxx/Assertion.hpp"
43 #include "blocxx/Mutex.hpp"
44 #include "blocxx/MutexLock.hpp"
45 #include "blocxx/ExceptionIds.hpp"
46 #include "blocxx/Format.hpp"
47 
48 extern "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 
62 namespace BLOCXX_NAMESPACE
63 {
64 
65 #ifdef BLOCXX_WIN32
66 
67 #include <WS2tcpip.h>
68 
69 const 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 
96 const char* const SocketAddress::ALL_LOCAL_ADDRESSES = "0.0.0.0";
97 
98 #if !defined(BLOCXX_WIN32)
99 
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 
143  : m_nativeSize(0) , m_type(UNSET)
144 {
145 }
146 
147 #ifndef BLOCXX_HAVE_GETHOSTBYNAME_R
149 #endif
150 
152 //static
154 SocketAddress::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)
225 
226 //static
229 {
230  return SocketAddress(nativeForm);
231 }
232 #endif // !defined(BLOCXX_WIN32)
233 
235 //static
238  UInt16 nativePort, const String& hostName)
239 {
240  InetSocketAddress_t addr;
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;
245  SocketAddress p = SocketAddress(addr);
246  p.m_type = INET;
247  p.m_name = hostName;
248  return p;
249 }
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 
270 {
271  return &m_inetNativeAddress;
272 }
273 
274 #if !defined(BLOCXX_WIN32)
275 
276 // Get a pointer to the UnixSocketAddress_t
277 // precondition: getType() == UDS
279 {
280  return &m_UDSNativeAddress;
281 }
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)
360 
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)
392 
394  : m_nativeSize(0), m_type(UDS)
395 {
396  assignFromNativeForm(&nativeForm, sizeof(nativeForm));
397 }
398 #endif // !defined(BLOCXX_WIN32)
399 
402  : m_nativeSize(0), m_type(INET)
403 {
404  assignFromNativeForm(&nativeForm, sizeof(nativeForm));
405 }
406 
409 {
410  return m_name;
411 }
414 {
415  return m_address;
416 }
419 {
420  return m_nativeSize;
421 }
424 {
425  if (type == INET)
426  {
427  InetSocketAddress_t addr;
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 }
445 const 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