OpenDDS  Snapshot(2023/04/28-20:55)
NetworkResource.cpp
Go to the documentation of this file.
1 /*
2  *
3  *
4  * Distributed under the OpenDDS License.
5  * See: http://www.opendds.org/license.html
6  */
7 
8 #include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/
9 
10 #include "NetworkResource.h"
11 
12 #include "LogAddr.h"
13 #include "TimeTypes.h"
14 
15 #include <ace/OS_NS_netdb.h>
16 #include <ace/Sock_Connect.h>
17 #include <ace/OS_NS_sys_socket.h> // For setsockopt()
18 #include <ace/OS_NS_arpa_inet.h>
19 
20 #include <cstdlib>
21 #include <cstring>
22 
23 #if !defined (__ACE_INLINE__)
24 # include "NetworkResource.inl"
25 #endif /* !__ACE_INLINE__ */
26 
28 
31 {
32  return (outCdr << ACE_OutputCDR::from_boolean(ACE_CDR_BYTE_ORDER)) &&
33  (outCdr << ACE_OutputCDR::from_octet(value.reserved_)) &&
34  (outCdr << value.addr_.c_str());
35 }
36 
39 {
40  CORBA::Boolean byte_order;
41 
42  if (!(inCdr >> ACE_InputCDR::to_boolean(byte_order)))
43  return false;
44 
45  inCdr.reset_byte_order(byte_order);
46 
47  if (!(inCdr >> ACE_InputCDR::to_octet(value.reserved_)))
48  return false;
49 
50  char* buf = 0;
51 
52  if (!(inCdr >> buf))
53  return false;
54 
55  value.addr_ = buf;
56 
57  delete[] buf;
58 
59  return inCdr.good_bit();
60 }
61 
63 
65 
66 namespace OpenDDS {
67 namespace DCPS {
68 
69 bool verify_hostname(const String& hostname, ACE_INET_Addr* addr_array, size_t addr_count,
70  bool prefer_loopback, bool allow_ipv4_fallback)
71 {
72  const ACE_INET_Addr addr = choose_single_coherent_address(hostname, prefer_loopback, allow_ipv4_fallback);
73  for (size_t i = 0; i < addr_count; ++i) {
74  if (addr == addr_array[i]) {
75  return true;
76  }
77  }
78  return false;
79 }
80 
82 {
83  // cache the determined fully qualified hostname and its
84  // address to be used on subsequent calls
85  static String fullname;
86  static ACE_INET_Addr selected_address;
87 
88  if (fullname.length() == 0) {
89  size_t addr_count;
90  ACE_INET_Addr *addr_array = 0;
91  OpenDDS::DCPS::HostnameInfoVector nonFQDN;
92 
93  const int result = ACE::get_ip_interfaces(addr_count, addr_array);
94 
95  struct Array_Guard {
96  Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
97  ~Array_Guard() {
98  delete [] ptr_;
99  }
100  ACE_INET_Addr* const ptr_;
101  } guardObject(addr_array);
102 
103  if (result != 0 || addr_count < 1) {
105  ACE_TEXT("(%P|%t) ERROR: get_fully_qualified_hostname: Unable to probe network. %p\n"),
106  ACE_TEXT("ACE::get_ip_interfaces")));
107 
108  } else {
109  for (size_t i = 0; i < addr_count; i++) {
110  VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: Found IP interface %C\n", LogAddr::ip(addr_array[i]).c_str()), 4);
111  }
112 
113 #ifdef ACE_HAS_IPV6
114  // Front load IPV6 addresses to give preference to IPV6 interfaces
115  size_t index_last_non_ipv6 = 0;
116  for (size_t i = 0; i < addr_count; i++) {
117  if (addr_array[i].get_type() == AF_INET6) {
118  if (i == index_last_non_ipv6) {
119  ++index_last_non_ipv6;
120  } else {
121  std::swap(addr_array[i], addr_array[index_last_non_ipv6]);
122  ++index_last_non_ipv6;
123  }
124  }
125  }
126 #endif
127  for (size_t i = 0; i < addr_count; i++) {
128  char hostname[MAXHOSTNAMELEN+1] = "";
129 
130  // Discover the fully qualified hostname
131  if (ACE::get_fqdn(addr_array[i], hostname, MAXHOSTNAMELEN+1) == 0) {
132  VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: Considering fqdn %C\n", hostname), 4);
133  // Find the first FQDN that resolves to an IP interface address.
134  if (!addr_array[i].is_loopback() && ACE_OS::strchr(hostname, '.') != 0 &&
135  verify_hostname(hostname, addr_array, addr_count, false, false)) {
136  VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: Found fqdn %C from %C\n", hostname, LogAddr(addr_array[i]).c_str()), 2);
137  selected_address = addr_array[i];
138  fullname = hostname;
139  if (addr) {
140  *addr = selected_address;
141  }
142  return fullname;
143  } else {
144  VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: IP interface %C maps to hostname %C\n",
145  LogAddr(addr_array[i]).c_str(), hostname), 2);
146 
147  if (ACE_OS::strncmp(hostname, "localhost", 9) == 0) {
148  addr_array[i].get_host_addr(hostname, MAXHOSTNAMELEN);
149  }
150 
151  if (verify_hostname(hostname, addr_array, addr_count, false, true)) {
153  info.index_ = i;
154  info.hostname_ = hostname;
155  nonFQDN.push_back(info);
156  }
157  }
158  }
159  }
160  }
161 
162  OpenDDS::DCPS::HostnameInfoVector::iterator itBegin = nonFQDN.begin();
163  OpenDDS::DCPS::HostnameInfoVector::iterator itEnd = nonFQDN.end();
164 
165  for (OpenDDS::DCPS::HostnameInfoVector::iterator it = itBegin; it != itEnd; ++it) {
166  if (!addr_array[it->index_].is_loopback()) {
167  ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: get_fully_qualified_hostname: Could not find FQDN. Using "
168  "\"%C\" as fully qualified hostname, please "
169  "correct system configuration.\n", it->hostname_.c_str()));
170  selected_address = addr_array[it->index_];
171  fullname = it->hostname_;
172  if (addr) {
173  *addr = selected_address;
174  }
175  return fullname;
176  }
177  }
178 
179  // If no non-loopback IP is found from the above step, return a non-loopback
180  // address from the IP interfaces list.
181  for (size_t i = 0; i < addr_count; ++i) {
182  if (!addr_array[i].is_loopback()) {
183  char addr_str[MAXHOSTNAMELEN+1] = "";
184  addr_array[i].get_host_addr(addr_str, MAXHOSTNAMELEN);
185  ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: get_fully_qualified_hostname: Could not find FQDN. Using "
186  "\"%C\" as fully qualified hostname, please "
187  "correct system configuration.\n", addr_str));
188  selected_address = addr_array[i];
189  fullname = addr_str;
190  if (addr) {
191  *addr = selected_address;
192  }
193  return fullname;
194  }
195  }
196 
197  // As a last resort, return the first loopback address from the non-FQDNs list if not empty.
198  if (itBegin != itEnd) {
199  ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: get_fully_qualified_hostname: Could not find FQDN. Using "
200  "\"%C\" as fully qualified hostname, please "
201  "correct system configuration.\n", itBegin->hostname_.c_str()));
202  selected_address = addr_array[itBegin->index_];
203  fullname = itBegin->hostname_;
204  if (addr) {
205  *addr = selected_address;
206  }
207  return fullname;
208  }
209 
210 #ifdef OPENDDS_SAFETY_PROFILE
211  // address resolution may not be available due to safety profile,
212  // return an address that should work for running tests
213  if (addr) {
214  static const char local[] = {1, 0, 0, 127};
215  addr->set_address(local, sizeof local);
216  }
217  return "localhost";
218 #else
220  "(%P|%t) ERROR: get_fully_qualified_hostname: Failed to discover the fully qualified hostname\n"));
221 #endif
222  }
223 
224  if (addr) {
225  *addr = selected_address;
226  }
227  return fullname;
228 }
229 
231 {
232  ACE_INET_Addr *if_addrs = 0;
233  size_t if_cnt = 0;
234  size_t endpoint_count = 0;
235 
236  int result =
237 #ifdef OPENDDS_SAFETY_PROFILE
238  -1;
239 #else
240  ACE::get_ip_interfaces(if_cnt, if_addrs);
241 #endif
242 
243  struct Array_Guard {
244  Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
245  ~Array_Guard() {
246  delete[] ptr_;
247  }
248  ACE_INET_Addr* const ptr_;
249  } guardObject(if_addrs);
250 
251  if (!result) {
252  size_t lo_cnt = 0; // Loopback interface count
253 #if defined (ACE_HAS_IPV6)
254  size_t ipv4_cnt = 0;
255  size_t ipv4_lo_cnt = 0;
256  size_t ipv6_ll = 0;
257  bool ipv6_non_ll = false;
258 #endif
259  for (size_t j = 0; j < if_cnt; ++j) {
260  // Scan for the loopback interface since it shouldn't be included in
261  // the list of cached hostnames unless it is the only interface.
262  if (if_addrs[j].is_loopback())
263  ++lo_cnt;
264 #if defined (ACE_HAS_IPV6)
265  // Scan for IPv4 interfaces since these should not be included
266  // when IPv6-only is selected.
267  if (if_addrs[j].get_type() != AF_INET6 ||
268  if_addrs[j].is_ipv4_mapped_ipv6()) {
269  ++ipv4_cnt;
270  if (if_addrs[j].is_loopback())
271  ++ipv4_lo_cnt; // keep track of IPv4 loopback ifs
272  } else if (!if_addrs[j].is_linklocal() &&
273  !if_addrs[j].is_loopback()) {
274  ipv6_non_ll = true; // we have at least 1 non-local IPv6 if
275  } else if (if_addrs[j].is_linklocal()) {
276  ++ipv6_ll; // count link local addrs to exclude them afterwards
277  }
278 #endif /* ACE_HAS_IPV6 */
279  }
280 
281  bool ipv4_only = ACE_INET_Addr().get_type() == AF_INET;
282 
283 #if defined (ACE_HAS_IPV6)
284 
285  // If the loopback interface is the only interface then include it
286  // in the list of interfaces to query for a hostname, otherwise
287  // exclude it from the list.
288  bool ignore_lo;
289  if (ipv4_only) {
290  ignore_lo = ipv4_cnt != ipv4_lo_cnt;
291  } else {
292  ignore_lo = if_cnt != lo_cnt;
293  }
294 
295  // Adjust counts for IPv4 only if required
296  size_t if_ok_cnt = if_cnt;
297  if (ipv4_only) {
298  if_ok_cnt = ipv4_cnt;
299  lo_cnt = ipv4_lo_cnt;
300  ipv6_ll = 0;
301  }
302 
303  // In case there are no non-local IPv6 ifs in the list only exclude
304  // IPv4 loopback.
305  // IPv6 loopback will be needed to successfully connect IPv6 clients
306  // in a localhost environment.
307  if (!ipv4_only && !ipv6_non_ll)
308  lo_cnt = ipv4_lo_cnt;
309 
310  if (!ignore_lo)
311  endpoint_count = if_ok_cnt - ipv6_ll;
312  else
313  endpoint_count = if_ok_cnt - ipv6_ll - lo_cnt;
314 #else /* end ACE_HAS_IPV6 begin !ACE_HAS_IPV6*/
315  // If the loopback interface is the only interface then include it
316  // in the list of interfaces to query for a hostname, otherwise
317  // exclude it from the list.
318  bool ignore_lo;
319  ignore_lo = if_cnt != lo_cnt;
320  if (!ignore_lo)
321  endpoint_count = if_cnt;
322  else
323  endpoint_count = if_cnt - lo_cnt;
324 #endif /* !ACE_HAS_IPV6 */
325  if (endpoint_count == 0) {
327  ACE_TEXT("(%P|%t) get_interface_addrs() - ")
328  ACE_TEXT("found no usable addresses\n")), 2);
329  }
330 
331  for (size_t i = 0; i < if_cnt; ++i) {
332  // Ignore any non-IPv4 interfaces when so required.
333  if (ipv4_only && (if_addrs[i].get_type() != AF_INET))
334  continue;
335 #if defined (ACE_HAS_IPV6)
336  // Ignore any loopback interface if there are other
337  // non-loopback interfaces.
338  if (ignore_lo &&
339  if_addrs[i].is_loopback() &&
340  (ipv4_only ||
341  ipv6_non_ll ||
342  if_addrs[i].get_type() != AF_INET6))
343  continue;
344 
345  // Ignore all IPv6 link local interfaces when so required.
346  if (ipv6_non_ll && if_addrs[i].is_linklocal())
347  continue;
348 #else /* ACE_HAS_IPV6 */
349  // Ignore any loopback interface if there are other
350  // non-loopback interfaces.
351  if (ignore_lo && if_addrs[i].is_loopback())
352  continue;
353 #endif /* !ACE_HAS_IPV6 */
354  addrs.push_back(if_addrs[i]);
355  }
356  }
357 #ifdef ACE_HAS_IPV6
358  //front load IPV6 addresses to give preference to IPV6 interfaces
359  size_t index_last_non_ipv6 = 0;
360  for (size_t i = 0; i < addrs.size(); i++) {
361  if (addrs.at(i).get_type() == AF_INET6) {
362  if (i == index_last_non_ipv6) {
363  ++index_last_non_ipv6;
364  }
365  else {
366  std::swap(addrs.at(i), addrs.at(index_last_non_ipv6));
367  ++index_last_non_ipv6;
368  }
369  }
370  }
371 #endif
372 #ifdef OPENDDS_SAFETY_PROFILE
373  // address resolution may not be available due to safety profile,
374  // return an address that should work for running tests
375  if (addrs.empty()) {
376  ACE_INET_Addr addr;
377  static const char local[] = { 1, 0, 0, 127 };
378  addr.set_address(local, sizeof local);
379  addrs.push_back(addr);
380  }
381 #else
382  if (addrs.empty()) {
384  "(%P|%t) ERROR: failed to find usable interface address\n"));
385  }
386 #endif
387 }
388 
389 bool set_socket_multicast_ttl(const ACE_SOCK_Dgram& socket, const unsigned char& ttl)
390 {
391  ACE_HANDLE handle = socket.get_handle();
392  const void* ttlp = &ttl;
393 #if defined(ACE_LINUX) || defined(__linux__) || defined(ACE_HAS_MAC_OSX)
394  int ttl_2 = ttl;
395  ttlp = &ttl_2;
396 #define TTL ttl_2
397 #else
398 #define TTL ttl
399 #endif
400 #if defined (ACE_HAS_IPV6)
401  ACE_INET_Addr local_addr;
402  if (0 != socket.get_local_addr(local_addr)) {
403  VDBG((LM_WARNING, "(%P|%t) set_socket_ttl: "
404  "ACE_SOCK_Dgram::get_local_addr %p\n", ACE_TEXT("")));
405  }
406  if (local_addr.get_type () == AF_INET6) {
407  if (0 != ACE_OS::setsockopt(handle,
408  IPPROTO_IPV6,
409  IPV6_MULTICAST_HOPS,
410  static_cast<const char*>(ttlp),
411  sizeof(TTL))) {
413  ACE_TEXT("(%P|%t) ERROR: ")
414  ACE_TEXT("set_socket_ttl: ")
415  ACE_TEXT("failed to set IPV6 TTL: %d %p\n"),
416  ttl,
417  ACE_TEXT("ACE_OS::setsockopt(TTL)")),
418  false);
419  }
420  } else
421 #endif /* ACE_HAS_IPV6 */
422  if (0 != ACE_OS::setsockopt(handle,
423  IPPROTO_IP,
425  static_cast<const char*>(ttlp),
426  sizeof(TTL))) {
428  ACE_TEXT("(%P|%t) ERROR: ")
429  ACE_TEXT("set_socket_ttl: ")
430  ACE_TEXT("failed to set TTL: %d %p\n"),
431  ttl,
432  ACE_TEXT("ACE_OS::setsockopt(TTL)")),
433  false);
434  }
435  return true;
436 }
437 
438 bool open_appropriate_socket_type(ACE_SOCK_Dgram& socket, const ACE_INET_Addr& local_address, int* proto_family)
439 {
440 #if defined (ACE_HAS_IPV6) && defined (IPV6_V6ONLY)
441  int protocol_family = ACE_PROTOCOL_FAMILY_INET;
442  int protocol = 0;
443  int reuse_addr = 0;
444  if (static_cast<ACE_Addr>(local_address) != ACE_Addr::sap_any) {
445  protocol_family = local_address.get_type();
446  } else if (protocol_family == PF_UNSPEC) {
447  protocol_family = ACE::ipv6_enabled() ? PF_INET6 : PF_INET;
448  }
449 
450  int one = 1;
451  socket.set_handle(ACE_OS::socket(protocol_family,
452  SOCK_DGRAM,
453  protocol));
454 
455  if (socket.get_handle() == ACE_INVALID_HANDLE) {
457  ACE_TEXT("(%P|%t) WARNING:")
458  ACE_TEXT("open_appropriate_socket_type: ")
459  ACE_TEXT("failed to set socket handle\n")),
460  false);
461  } else if (protocol_family != PF_UNIX &&
462  reuse_addr &&
463  socket.set_option(SOL_SOCKET,
464  SO_REUSEADDR,
465  &one,
466  sizeof one) == -1) {
467  socket.close();
469  ACE_TEXT("(%P|%t) WARNING: ")
470  ACE_TEXT("open_appropriate_socket_type: ")
471  ACE_TEXT("failed to set socket SO_REUSEADDR option\n")),
472  false);
473  }
474  ACE_HANDLE handle = socket.get_handle();
475  int ipv6_only = 0;
476  if (protocol_family == PF_INET6 &&
477  0 != ACE_OS::setsockopt(handle,
478  IPPROTO_IPV6,
479  IPV6_V6ONLY,
480  (char*)&ipv6_only,
481  sizeof(ipv6_only))) {
483  ACE_TEXT("(%P|%t) WARNING: ")
484  ACE_TEXT("open_appropriate_socket_type: ")
485  ACE_TEXT("failed to set IPV6_V6ONLY to 0: %p\n"),
486  ACE_TEXT("ACE_OS::setsockopt(IPV6_V6ONLY)")),
487  false);
488  }
489  bool error = false;
490 
491  if (static_cast<ACE_Addr>(local_address) == ACE_Addr::sap_any) {
492  if (protocol_family == PF_INET || protocol_family == PF_INET6) {
493  if (ACE::bind_port(socket.get_handle(),
494  INADDR_ANY,
495  protocol_family) == -1) {
496  error = true;
497  }
498  }
499  } else if (ACE_OS::bind(socket.get_handle(),
500  reinterpret_cast<sockaddr *> (local_address.get_addr()),
501  local_address.get_size()) == -1) {
502  error = true;
503  }
504 
505  if (error) {
506  socket.close();
507  VDBG_LVL((LM_WARNING, "(%P|%t) WARNING: open_appropriate_socket_type: "
508  "failed to bind address to socket\n"), 2);
509  return false;
510  }
511  if (proto_family) {
512  *proto_family = protocol_family;
513  }
514  return true;
515 #else
516  if (proto_family) {
517  *proto_family = PF_INET;
518  }
519  return socket.open(local_address) == 0;
520 #endif
521 }
522 
523 ACE_INET_Addr choose_single_coherent_address(const ACE_INET_Addr& address, bool prefer_loopback)
524 {
525 // Check that ACE_INET_Addr supports next()
526 #if !(ACE_MAJOR_VERSION < 6 || (ACE_MAJOR_VERSION == 6 && (ACE_MINOR_VERSION < 3 || (ACE_MINOR_VERSION == 3 && ACE_MICRO_VERSION < 1))))
527  ACE_INET_Addr copy(address);
528  OPENDDS_VECTOR(ACE_INET_Addr) addresses;
529  do {
530  ACE_INET_Addr temp;
531  temp.set_addr(copy.get_addr(), copy.get_addr_size());
532  addresses.push_back(temp);
533  } while (copy.next());
534  return choose_single_coherent_address(addresses, prefer_loopback);
535 #else
536  ACE_UNUSED_ARG(prefer_loopback);
537  return address;
538 #endif // !(ACE_MAJOR_VERSION < 6 || (ACE_MAJOR_VERSION == 6 && (ACE_MINOR_VERSION < 3 || (ACE_MINOR_VERSION == 3 && ACE_MICRO_VERSION < 1))))
539 }
540 
541 namespace {
542 
543 template <typename T>
544 ACE_INET_Addr tie_breaker(const T& addrs, const String& name)
545 {
546  if (!name.empty()) {
547  for (typename T::const_iterator it = addrs.begin(); it != addrs.end(); ++it) {
548  if (name.compare(LogAddr::host(*it)) == 0) {
549  VDBG((LM_DEBUG, "(%P|%t) tie_breaker - Choosing Address %C\n",
550  LogAddr(*it, LogAddr::IpPortHost).c_str()));
551  return *it;
552  }
553  }
554  }
555  VDBG((LM_DEBUG, "(%P|%t) tie_breaker - Choosing Address %C\n", LogAddr(*(addrs.begin())).c_str()));
556  return *addrs.begin();
557 }
558 
559 }
560 
561 ACE_INET_Addr choose_single_coherent_address(const OPENDDS_VECTOR(ACE_INET_Addr)& addresses, bool prefer_loopback, const String& name)
562 {
563 #ifdef ACE_HAS_IPV6
564  OPENDDS_SET(ACE_INET_Addr) set6_loopback;
565  OPENDDS_SET(ACE_INET_Addr) set6_linklocal;
566  OPENDDS_SET(ACE_INET_Addr) set6_mapped_v4;
568 #endif // ACE_HAS_IPV6
569  OPENDDS_SET(ACE_INET_Addr) set4_loopback;
571 
572  for (OPENDDS_VECTOR(ACE_INET_Addr)::const_iterator it = addresses.begin(); it != addresses.end(); ++it) {
573 #ifdef ACE_HAS_IPV6
574  if (it->get_type() == AF_INET6 && !it->is_multicast()) {
575  if (it->is_loopback()) {
576  VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
577  "Considering Address %C - ADDING TO IPv6 LOOPBACK LIST\n", LogAddr(*it).c_str()));
578  set6_loopback.insert(*it);
579  } else if (it->is_ipv4_mapped_ipv6() || it->is_ipv4_compat_ipv6()) {
580 #ifndef IPV6_V6ONLY
581  VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
582  "Considering Address %C - ADDING TO IPv6 MAPPED / COMPATIBLE IPv4 LIST\n", LogAddr(*it).c_str()));
583  set6_mapped_v4.insert(*it);
584 #endif // ! IPV6_V6ONLY
585  } else if (it->is_linklocal()) {
586  VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
587  "Considering Address %C - ADDING TO IPv6 LINK-LOCAL LIST\n", LogAddr(*it).c_str()));
588  set6_linklocal.insert(*it);
589  } else {
590  VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
591  "Considering Address %C - ADDING TO IPv6 NORMAL LIST\n", LogAddr(*it).c_str()));
592  set6.insert(*it);
593  }
594  }
595 #endif // ACE_HAS_IPV6
596  if (it->get_type() == AF_INET && !it->is_multicast()) {
597  if (it->is_loopback()) {
598  VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
599  "Considering Address %C - ADDING TO IPv4 LOOPBACK LIST\n", LogAddr(*it).c_str()));
600  set4_loopback.insert(*it);
601  } else {
602  VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
603  "Considering Address %C - ADDING TO IPv4 NORMAL LIST\n", LogAddr(*it).c_str()));
604  set4.insert(*it);
605  }
606  }
607  }
608 
609 #ifdef ACE_HAS_IPV6
610  if (prefer_loopback && !set6_loopback.empty()) {
611  return tie_breaker(set6_loopback, name);
612  }
613 #endif // ACE_HAS_IPV6
614 
615  if (prefer_loopback && !set4_loopback.empty()) {
616  return tie_breaker(set4_loopback, name);
617  }
618 
619 #ifdef ACE_HAS_IPV6
620  if (prefer_loopback && !set6_linklocal.empty()) {
621  return tie_breaker(set6_linklocal, name);
622  }
623  if (!set6.empty()) {
624  return tie_breaker(set6, name);
625  }
626  if (!set6_mapped_v4.empty()) {
627  return tie_breaker(set6_mapped_v4, name);
628  }
629 #endif // ACE_HAS_IPV6
630 
631  if (!set4.empty()) {
632  return tie_breaker(set4, name);
633  }
634 
635 #ifdef ACE_HAS_IPV6
636  if (!set6_linklocal.empty()) {
637  return tie_breaker(set6_linklocal, name);
638  }
639  if (!set6_loopback.empty()) {
640  return tie_breaker(set6_loopback, name);
641  }
642 #endif // ACE_HAS_IPV6
643 
644  if (!set4_loopback.empty()) {
645  return tie_breaker(set4_loopback, name);
646  }
647 
648  if (!addresses.empty()) {
649  return tie_breaker(addresses, name);
650  }
651 
652  return ACE_INET_Addr();
653 }
654 
655 ACE_INET_Addr choose_single_coherent_address(const String& address, bool prefer_loopback, bool allow_ipv4_fallback)
656 {
657  ACE_INET_Addr result;
658 
659  if (address.empty()) {
660  return ACE_INET_Addr();
661  }
662 
663  String host_name_str;
664  unsigned short port_number = 0;
665 
666 #ifdef ACE_HAS_IPV6
667  const String::size_type openb = address.find_first_of('[');
668  const String::size_type closeb = address.find_first_of(']', openb);
669  const String::size_type last_double = address.rfind("::", closeb);
670  const String::size_type port_div = closeb != String::npos ?
671  address.find_first_of(':', closeb + 1u) :
672  (last_double != String::npos ?
673  address.find_first_of(':', last_double + 2u) :
674  address.find_last_of(':'));
675 #else
676  const String::size_type port_div = address.find_last_of(':');
677 #endif
678 
679  if (port_div != String::npos) {
680 #ifdef ACE_HAS_IPV6
681  if (openb != String::npos && closeb != String::npos) {
682  host_name_str = address.substr(openb + 1u, closeb - 1u - openb);
683  } else
684 #endif /* ACE_HAS_IPV6 */
685  {
686  host_name_str = address.substr(0, port_div);
687  }
688  port_number = static_cast<unsigned short>(std::strtoul(address.substr(port_div + 1u).c_str(), 0, 10));
689  } else {
690 #ifdef ACE_HAS_IPV6
691  if (openb != String::npos && closeb != String::npos) {
692  host_name_str = address.substr(openb + 1u, closeb - 1u - openb);
693  } else
694 #endif /* ACE_HAS_IPV6 */
695  {
696  host_name_str = address;
697  }
698  }
699 
700  if (host_name_str.empty()) {
701  return ACE_INET_Addr();
702  }
703 
704  const char* host_name = host_name_str.c_str();
705 
706  union ip46
707  {
708  sockaddr_in in4_;
709 #ifdef ACE_HAS_IPV6
710  sockaddr_in6 in6_;
711 #endif /* ACE_HAS_IPV6 */
712  } inet_addr;
713  std::memset(&inet_addr, 0, sizeof inet_addr);
714 
715  int address_family = AF_UNSPEC;
716 
717 #if defined ACE_HAS_IPV6 && defined ACE_USES_IPV4_IPV6_MIGRATION
718  if (address_family == AF_UNSPEC && !ACE::ipv6_enabled()) {
719  address_family = AF_INET;
720  }
721 #endif /* ACE_HAS_IPV6 && ACE_USES_IPV4_IPV6_MIGRATION */
722 
723 #ifdef ACE_HAS_IPV6
724  if (address_family == AF_UNSPEC && ACE::ipv6_enabled() && !allow_ipv4_fallback) {
725  address_family = AF_INET6;
726  }
727 
728  if (address_family != AF_INET && ACE_OS::inet_pton(AF_INET6, host_name, &inet_addr.in6_.sin6_addr) == 1) {
729 #ifdef ACE_HAS_SOCKADDR_IN6_SIN6_LEN
730  inet_addr.in6_.sin6_len = sizeof inet_addr.in6_;
731 #endif /* ACE_HAS_SOCKADDR_IN6_SIN6_LEN */
732  inet_addr.in6_.sin6_family = AF_INET6;
733  result.set_addr(&inet_addr, sizeof inet_addr);
734  result.set_port_number(port_number, 1 /*encode*/);
735  return result;
736  }
737 #else
738  ACE_UNUSED_ARG(allow_ipv4_fallback);
739  address_family = AF_INET;
740 #endif /* ACE_HAS_IPV6 */
741 
742  if (ACE_OS::inet_pton(AF_INET, host_name, &inet_addr.in4_.sin_addr) == 1) {
743 #ifdef ACE_HAS_SOCKADDR_IN_SIN_LEN
744  inet_addr.in4_.sin_len = sizeof inet_addr.in4_;
745 #endif /* ACE_HAS_SOCKADDR_IN_SIN_LEN */
746  inet_addr.in4_.sin_family = AF_INET;
747  result.set_addr(&inet_addr, sizeof inet_addr);
748  result.set_port_number(port_number, 1 /*encode*/);
749  return result;
750  }
751 
752  addrinfo hints;
753  std::memset(&hints, 0, sizeof hints);
754  hints.ai_family = address_family;
755 
756  // The ai_flags used to contain AI_ADDRCONFIG as well but that prevented
757  // lookups from completing if there is no, or only a loopback, IPv6
758  // interface configured. See Bugzilla 4211 for more info.
759 
760 #if defined ACE_HAS_IPV6 && !defined IPV6_V6ONLY
761  hints.ai_flags |= AI_V4MAPPED;
762 #endif
763 
764 #if defined ACE_HAS_IPV6 && defined AI_ALL
765  // Without AI_ALL, Windows machines exhibit inconsistent behaviors on
766  // difference machines we have tested.
767  hints.ai_flags |= AI_ALL;
768 #endif
769 
770  // Note - specify the socktype here to avoid getting multiple entries
771  // returned with the same address for different socket types or
772  // protocols. If this causes a problem for some reason (an address that's
773  // available for TCP but not UDP, or vice-versa) this will need to change
774  // back to unrestricted hints and weed out the duplicate addresses by
775  // searching this->inet_addrs_ which would slow things down.
776  hints.ai_socktype = SOCK_STREAM;
777 
778  addrinfo *res = 0;
779  const int error = ACE_OS::getaddrinfo(host_name, 0, &hints, &res);
780 
781  if (error) {
782  VDBG((LM_WARNING, "(%P|%t) WARNING: choose_single_coherent_address: Call to getaddrinfo for hostname %C returned error: %d\n", host_name, error));
783  return ACE_INET_Addr();
784  }
785 
786  struct AddrInfoGuard {
787  AddrInfoGuard(addrinfo* ptr) : ptr_(ptr) {}
788  ~AddrInfoGuard() {
789  ACE_OS::freeaddrinfo(ptr_);
790  }
791  addrinfo* const ptr_;
792  } guard(res);
793 
794  OPENDDS_VECTOR(ACE_INET_Addr) addresses;
795 
796 #ifdef ACE_WIN32
797  static ACE_Thread_Mutex addr_cache_map_mutex_;
798  typedef std::pair<SystemTimePoint, OPENDDS_SET(ACE_INET_Addr)> AddrCachePair;
799  typedef OPENDDS_MAP(String, AddrCachePair) AddrCacheMap;
800  static AddrCacheMap addr_cache_map_;
801  ACE_Guard<ACE_Thread_Mutex> g(addr_cache_map_mutex_);
803  for (AddrCacheMap::iterator it = addr_cache_map_.begin(); it != addr_cache_map_.end(); /* inc in loop */) {
804  if (it->second.first + TimeDuration(3, 0) < now) {
805  addr_cache_map_.erase(it++);
806  } else {
807  ++it;
808  }
809  }
810  AddrCacheMap::iterator it = addr_cache_map_.find(host_name);
811  if (it != addr_cache_map_.end()) {
812  addresses.insert(addresses.end(), it->second.second.begin(), it->second.second.end());
813  it->second.first = now;
814  }
815 #endif /* ACE_WIN32 */
816 
817  for (addrinfo* curr = res; curr; curr = curr->ai_next) {
818  if (curr->ai_family != AF_INET && curr->ai_family != AF_INET6) {
819  continue;
820  }
821  ip46 addr;
822  std::memset(&addr, 0, sizeof addr);
823  std::memcpy(&addr, curr->ai_addr, curr->ai_addrlen);
824 #ifdef ACE_HAS_IPV6
825  if (curr->ai_family == AF_INET6) {
826  addr.in6_.sin6_port = ACE_NTOHS(port_number);
827  } else {
828 #endif /* ACE_HAS_IPV6 */
829  addr.in4_.sin_port = ACE_NTOHS(port_number);;
830 #ifdef ACE_HAS_IPV6
831  }
832 #endif /* ACE_HAS_IPV6 */
833 
834  ACE_INET_Addr temp;
835  temp.set_addr(&addr, sizeof addr);
836  addresses.push_back(temp);
837 #ifdef ACE_WIN32
838  if (it != addr_cache_map_.end()) {
839  it->second.second.insert(temp);
840  } else {
841  OPENDDS_SET(ACE_INET_Addr) my_set;
842  my_set.insert(temp);
843  addr_cache_map_[host_name] = make_pair(now, my_set);
844  }
845 #endif /* ACE_WIN32 */
846  }
847 
848 #ifdef ACE_WIN32
849  g.release();
850 #endif /* ACE_WIN32 */
851 
852  result = choose_single_coherent_address(addresses, prefer_loopback, host_name);
853  result.set_port_number(port_number, 1 /*encode*/);
854  return result;
855 }
856 
858  const DCPS::Locator_t& locator,
859  bool map /*map IPV4 to IPV6 addr*/)
860 {
861  switch (locator.kind) {
862 #ifdef ACE_HAS_IPV6
863  case LOCATOR_KIND_UDPv6:
864  dest.set_type(AF_INET6);
865  if (dest.set_address(reinterpret_cast<const char*>(locator.address),
866  16, 0 /*encode*/) == -1) {
867  return -1;
868  }
869  dest.set_port_number(locator.port);
870  return 0;
871 #endif
872  case LOCATOR_KIND_UDPv4:
873 #if !defined (ACE_HAS_IPV6) || !defined (IPV6_V6ONLY)
874  ACE_UNUSED_ARG(map);
875 #endif
876  dest.set_type(AF_INET);
877  if (dest.set_address(reinterpret_cast<const char*>(locator.address)
878  + 12, 4, 0 /*network order*/
879 #if defined (ACE_HAS_IPV6) && defined (IPV6_V6ONLY)
880  , map ? 1 : 0 /*map IPV4 to IPV6 addr*/
881 #endif
882  ) == -1) {
883  return -1;
884  }
885  dest.set_port_number(locator.port);
886  return 0;
887  default:
888  return -1; // Unknown kind
889  }
890 
891  return -1;
892 }
893 
896  const ACE_INET_Addr& addr)
897 {
898  const void* raw = addr.get_addr();
899  switch (addr.get_type()) {
900  case AF_INET:
901  {
902  locator.kind = LOCATOR_KIND_UDPv4;
903  const sockaddr_in* in = static_cast<const sockaddr_in*>(raw);
904  std::memset(&locator.address[0], 0, 12);
905  std::memcpy(&locator.address[12], &in->sin_addr, 4);
906  }
907  break;
908 #ifdef ACE_HAS_IPV6
909  case AF_INET6:
910  {
911  locator.kind = LOCATOR_KIND_UDPv6;
912  const sockaddr_in6* in = static_cast<const sockaddr_in6*>(raw);
913  std::memcpy(&locator.address[0], &in->sin6_addr, 16);
914  }
915  break;
916 #endif
917  default:
918  locator.kind = LOCATOR_KIND_INVALID;
919  std::memset(&locator.address[0], 0, 16);
920  break;
921  }
922  locator.port = addr.get_port_number();
923 }
924 
925 }
926 }
927 
const char * get_host_addr(char *addr, int addr_size) const
#define ACE_BEGIN_VERSIONED_NAMESPACE_DECL
void swap(MessageBlock &lhs, MessageBlock &rhs)
#define ACE_DEBUG(X)
#define ACE_ERROR(X)
int setsockopt(ACE_HANDLE handle, int level, int optname, const char *optval, int optlen)
const LogLevel::Value value
Definition: debug.cpp:61
std::string String
const long LOCATOR_KIND_INVALID
bool good_bit(void) const
#define PF_UNSPEC
String addr_
The address in string format. e.g. ip:port, hostname:port.
int ipv6_enabled(void)
#define OpenDDS_Dcps_Export
Definition: dcps_export.h:24
int strncmp(const char *s, const char *t, size_t len)
int locator_to_address(ACE_INET_Addr &dest, const DCPS::Locator_t &locator, bool map)
int get_size(void) const
bool next(void)
#define ACE_CDR_BYTE_ORDER
#define AI_V4MAPPED
int release(void)
int set_option(int level, int option, void *optval, int optlen) const
ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_CDR::Boolean operator<<(ACE_OutputCDR &outCdr, OpenDDS::DCPS::NetworkResource &value)
Marshal into a buffer.
int get_type(void) const
#define SOL_SOCKET
int inet_pton(int family, const char *strptr, void *addrptr)
OpenDDS_Dcps_Export void address_to_locator(Locator_t &locator, const ACE_INET_Addr &addr)
ACE_HANDLE socket(int protocol_family, int type, int proto)
static TimePoint_T< SystemClock > now()
Definition: TimePoint_T.inl:41
int getaddrinfo(const char *name, const char *service, const addrinfo *hints, addrinfo **result)
void set_type(int type)
#define AF_UNSPEC
bool verify_hostname(const String &hostname, ACE_INET_Addr *addr_array, size_t addr_count, bool prefer_loopback, bool allow_ipv4_fallback)
LM_DEBUG
const char * strchr(const char *s, int c)
ACE_CDR::Boolean operator>>(ACE_InputCDR &inCdr, OpenDDS::DCPS::NetworkResource &value)
Demarshal from a buffer.
bool set_socket_multicast_ttl(const ACE_SOCK_Dgram &socket, const unsigned char &ttl)
static const String host(const ACE_INET_Addr &addr)
Definition: LogAddr.cpp:26
#define VDBG(DBG_ARGS)
#define MAXHOSTNAMELEN
ACE_CDR::Boolean Boolean
int hostname(char name[], size_t maxnamelen)
int get_fqdn(ACE_INET_Addr const &addr, char hostname[], size_t len)
ACE_INET_Addr choose_single_coherent_address(const ACE_INET_Addr &address, bool prefer_loopback)
int get_ip_interfaces(size_t &count, ACE_INET_Addr *&addr_array)
virtual void * get_addr(void) const
void set_handle(ACE_HANDLE handle)
int set_address(const char *ip_addr, int len, int encode=1, int map=0)
Defines a wrapper around address info which is used for advertise.
void get_interface_addrs(OPENDDS_VECTOR(ACE_INET_Addr)&addrs)
const char * c_str() const
Definition: LogAddr.h:32
#define ACE_END_VERSIONED_NAMESPACE_DECL
int get_local_addr(ACE_Addr &) const
#define AF_INET
#define PF_INET
#define IP_MULTICAST_TTL
#define TTL
int bind(ACE_HANDLE s, struct sockaddr *name, int namelen)
ACE_HANDLE get_handle(void) const
LM_WARNING
const long LOCATOR_KIND_UDPv6
void freeaddrinfo(addrinfo *result)
const char *const name
Definition: debug.cpp:60
#define PF_UNIX
#define IPPROTO_IP
ACE_TEXT("TCP_Factory")
#define SO_REUSEADDR
static const ACE_Addr sap_any
bool open_appropriate_socket_type(ACE_SOCK_Dgram &socket, const ACE_INET_Addr &local_address, int *proto_family)
u_short get_port_number(void) const
virtual void set_addr(const void *, int len)
DDS::ReturnCode_t copy(DDS::DynamicData_ptr dest, DDS::DynamicData_ptr src)
#define VDBG_LVL(DBG_ARGS, LEVEL)
int get_addr_size(void) const
int bind_port(ACE_HANDLE handle, ACE_UINT32 ip_addr=INADDR_ANY, int address_family=AF_UNSPEC)
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
int open(const ACE_Addr &local, int protocol_family=ACE_PROTOCOL_FAMILY_INET, int protocol=0, int reuse_addr=0, int ipv6_only=0)
#define ACE_NTOHS(x)
void set_port_number(u_short, int encode=1)
String get_fully_qualified_hostname(ACE_INET_Addr *addr)
const long LOCATOR_KIND_UDPv4
#define ACE_ERROR_RETURN(X, Y)
typedef OPENDDS_VECTOR(ActionConnectionRecord) ConnectionRecords
static const String ip(const ACE_INET_Addr &addr)
Definition: LogAddr.cpp:15
#define ACE_PROTOCOL_FAMILY_INET
#define SOCK_STREAM
unsigned long inet_addr(const char *name)
bool Boolean
LM_ERROR
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28
bool is_loopback(void) const
#define INADDR_ANY
typedef OPENDDS_MAP(OPENDDS_STRING, OPENDDS_STRING) ValueMap
Helper types and functions for config file parsing.
int close(void)
DDS::OctetArray16 address
#define SOCK_DGRAM
void reset_byte_order(int byte_order)
typedef OPENDDS_SET(NetworkAddress) AddrSet