Line data Source code
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 :
27 : ACE_BEGIN_VERSIONED_NAMESPACE_DECL
28 :
29 : ACE_CDR::Boolean
30 0 : operator<< (ACE_OutputCDR& outCdr, OpenDDS::DCPS::NetworkResource& value)
31 : {
32 0 : return (outCdr << ACE_OutputCDR::from_boolean(ACE_CDR_BYTE_ORDER)) &&
33 0 : (outCdr << ACE_OutputCDR::from_octet(value.reserved_)) &&
34 0 : (outCdr << value.addr_.c_str());
35 : }
36 :
37 : ACE_CDR::Boolean
38 0 : operator>> (ACE_InputCDR& inCdr, OpenDDS::DCPS::NetworkResource& value)
39 : {
40 : CORBA::Boolean byte_order;
41 :
42 0 : if (!(inCdr >> ACE_InputCDR::to_boolean(byte_order)))
43 0 : return false;
44 :
45 0 : inCdr.reset_byte_order(byte_order);
46 :
47 0 : if (!(inCdr >> ACE_InputCDR::to_octet(value.reserved_)))
48 0 : return false;
49 :
50 0 : char* buf = 0;
51 :
52 0 : if (!(inCdr >> buf))
53 0 : return false;
54 :
55 0 : value.addr_ = buf;
56 :
57 0 : delete[] buf;
58 :
59 0 : return inCdr.good_bit();
60 : }
61 :
62 : ACE_END_VERSIONED_NAMESPACE_DECL
63 :
64 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
65 :
66 : namespace OpenDDS {
67 : namespace DCPS {
68 :
69 2 : 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 2 : const ACE_INET_Addr addr = choose_single_coherent_address(hostname, prefer_loopback, allow_ipv4_fallback);
73 3 : for (size_t i = 0; i < addr_count; ++i) {
74 3 : if (addr == addr_array[i]) {
75 2 : return true;
76 : }
77 : }
78 0 : return false;
79 2 : }
80 :
81 2 : String get_fully_qualified_hostname(ACE_INET_Addr* addr)
82 : {
83 : // cache the determined fully qualified hostname and its
84 : // address to be used on subsequent calls
85 2 : static String fullname;
86 2 : static ACE_INET_Addr selected_address;
87 :
88 2 : if (fullname.length() == 0) {
89 : size_t addr_count;
90 1 : ACE_INET_Addr *addr_array = 0;
91 1 : OpenDDS::DCPS::HostnameInfoVector nonFQDN;
92 :
93 1 : const int result = ACE::get_ip_interfaces(addr_count, addr_array);
94 :
95 : struct Array_Guard {
96 1 : Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
97 1 : ~Array_Guard() {
98 12 : delete [] ptr_;
99 1 : }
100 : ACE_INET_Addr* const ptr_;
101 1 : } guardObject(addr_array);
102 :
103 1 : if (result != 0 || addr_count < 1) {
104 0 : ACE_ERROR((LM_ERROR,
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 0 : } else {
109 5 : for (size_t i = 0; i < addr_count; i++) {
110 4 : 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 2 : for (size_t i = 0; i < addr_count; i++) {
128 2 : char hostname[MAXHOSTNAMELEN+1] = "";
129 :
130 : // Discover the fully qualified hostname
131 2 : if (ACE::get_fqdn(addr_array[i], hostname, MAXHOSTNAMELEN+1) == 0) {
132 2 : 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 3 : if (!addr_array[i].is_loopback() && ACE_OS::strchr(hostname, '.') != 0 &&
135 3 : verify_hostname(hostname, addr_array, addr_count, false, false)) {
136 1 : 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 1 : selected_address = addr_array[i];
138 1 : fullname = hostname;
139 1 : if (addr) {
140 0 : *addr = selected_address;
141 : }
142 2 : return fullname;
143 : } else {
144 1 : 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 1 : if (ACE_OS::strncmp(hostname, "localhost", 9) == 0) {
148 1 : addr_array[i].get_host_addr(hostname, MAXHOSTNAMELEN);
149 : }
150 :
151 1 : if (verify_hostname(hostname, addr_array, addr_count, false, true)) {
152 1 : OpenDDS::DCPS::HostnameInfo info;
153 1 : info.index_ = i;
154 1 : info.hostname_ = hostname;
155 1 : nonFQDN.push_back(info);
156 1 : }
157 : }
158 : }
159 : }
160 : }
161 :
162 0 : OpenDDS::DCPS::HostnameInfoVector::iterator itBegin = nonFQDN.begin();
163 0 : OpenDDS::DCPS::HostnameInfoVector::iterator itEnd = nonFQDN.end();
164 :
165 0 : for (OpenDDS::DCPS::HostnameInfoVector::iterator it = itBegin; it != itEnd; ++it) {
166 0 : if (!addr_array[it->index_].is_loopback()) {
167 0 : 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 0 : selected_address = addr_array[it->index_];
171 0 : fullname = it->hostname_;
172 0 : if (addr) {
173 0 : *addr = selected_address;
174 : }
175 0 : 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 0 : for (size_t i = 0; i < addr_count; ++i) {
182 0 : if (!addr_array[i].is_loopback()) {
183 0 : char addr_str[MAXHOSTNAMELEN+1] = "";
184 0 : addr_array[i].get_host_addr(addr_str, MAXHOSTNAMELEN);
185 0 : 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 0 : selected_address = addr_array[i];
189 0 : fullname = addr_str;
190 0 : if (addr) {
191 0 : *addr = selected_address;
192 : }
193 0 : return fullname;
194 : }
195 : }
196 :
197 : // As a last resort, return the first loopback address from the non-FQDNs list if not empty.
198 0 : if (itBegin != itEnd) {
199 0 : 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 0 : selected_address = addr_array[itBegin->index_];
203 0 : fullname = itBegin->hostname_;
204 0 : if (addr) {
205 0 : *addr = selected_address;
206 : }
207 0 : 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
219 0 : ACE_ERROR((LM_ERROR,
220 : "(%P|%t) ERROR: get_fully_qualified_hostname: Failed to discover the fully qualified hostname\n"));
221 : #endif
222 2 : }
223 :
224 1 : if (addr) {
225 0 : *addr = selected_address;
226 : }
227 1 : return fullname;
228 : }
229 :
230 0 : void get_interface_addrs(OPENDDS_VECTOR(ACE_INET_Addr)& addrs)
231 : {
232 0 : ACE_INET_Addr *if_addrs = 0;
233 0 : size_t if_cnt = 0;
234 0 : size_t endpoint_count = 0;
235 :
236 : int result =
237 : #ifdef OPENDDS_SAFETY_PROFILE
238 : -1;
239 : #else
240 0 : ACE::get_ip_interfaces(if_cnt, if_addrs);
241 : #endif
242 :
243 : struct Array_Guard {
244 0 : Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
245 0 : ~Array_Guard() {
246 0 : delete[] ptr_;
247 0 : }
248 : ACE_INET_Addr* const ptr_;
249 0 : } guardObject(if_addrs);
250 :
251 0 : if (!result) {
252 0 : 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 0 : 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 0 : if (if_addrs[j].is_loopback())
263 0 : ++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 0 : 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 0 : ignore_lo = if_cnt != lo_cnt;
320 0 : if (!ignore_lo)
321 0 : endpoint_count = if_cnt;
322 : else
323 0 : endpoint_count = if_cnt - lo_cnt;
324 : #endif /* !ACE_HAS_IPV6 */
325 0 : if (endpoint_count == 0) {
326 0 : VDBG_LVL((LM_DEBUG,
327 : ACE_TEXT("(%P|%t) get_interface_addrs() - ")
328 : ACE_TEXT("found no usable addresses\n")), 2);
329 : }
330 :
331 0 : for (size_t i = 0; i < if_cnt; ++i) {
332 : // Ignore any non-IPv4 interfaces when so required.
333 0 : if (ipv4_only && (if_addrs[i].get_type() != AF_INET))
334 0 : 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 0 : if (ignore_lo && if_addrs[i].is_loopback())
352 0 : continue;
353 : #endif /* !ACE_HAS_IPV6 */
354 0 : 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 0 : if (addrs.empty()) {
383 0 : ACE_ERROR((LM_ERROR,
384 : "(%P|%t) ERROR: failed to find usable interface address\n"));
385 : }
386 : #endif
387 0 : }
388 :
389 0 : bool set_socket_multicast_ttl(const ACE_SOCK_Dgram& socket, const unsigned char& ttl)
390 : {
391 0 : ACE_HANDLE handle = socket.get_handle();
392 0 : const void* ttlp = &ttl;
393 : #if defined(ACE_LINUX) || defined(__linux__) || defined(ACE_HAS_MAC_OSX)
394 0 : int ttl_2 = ttl;
395 0 : 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))) {
412 : ACE_ERROR_RETURN((LM_ERROR,
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 0 : if (0 != ACE_OS::setsockopt(handle,
423 : IPPROTO_IP,
424 : IP_MULTICAST_TTL,
425 : static_cast<const char*>(ttlp),
426 : sizeof(TTL))) {
427 0 : ACE_ERROR_RETURN((LM_ERROR,
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 0 : return true;
436 : }
437 :
438 0 : 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) {
456 : ACE_ERROR_RETURN((LM_WARNING,
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();
468 : ACE_ERROR_RETURN((LM_WARNING,
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))) {
482 : ACE_ERROR_RETURN((LM_WARNING,
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 0 : if (proto_family) {
517 0 : *proto_family = PF_INET;
518 : }
519 0 : return socket.open(local_address) == 0;
520 : #endif
521 : }
522 :
523 0 : 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 0 : ACE_INET_Addr copy(address);
528 0 : OPENDDS_VECTOR(ACE_INET_Addr) addresses;
529 : do {
530 0 : ACE_INET_Addr temp;
531 0 : temp.set_addr(copy.get_addr(), copy.get_addr_size());
532 0 : addresses.push_back(temp);
533 0 : } while (copy.next());
534 0 : 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 0 : }
540 :
541 : namespace {
542 :
543 : template <typename T>
544 7 : ACE_INET_Addr tie_breaker(const T& addrs, const String& name)
545 : {
546 7 : if (!name.empty()) {
547 5 : for (typename T::const_iterator it = addrs.begin(); it != addrs.end(); ++it) {
548 5 : if (name.compare(LogAddr::host(*it)) == 0) {
549 5 : VDBG((LM_DEBUG, "(%P|%t) tie_breaker - Choosing Address %C\n",
550 : LogAddr(*it, LogAddr::IpPortHost).c_str()));
551 10 : return *it;
552 : }
553 : }
554 : }
555 2 : VDBG((LM_DEBUG, "(%P|%t) tie_breaker - Choosing Address %C\n", LogAddr(*(addrs.begin())).c_str()));
556 4 : return *addrs.begin();
557 : }
558 :
559 : }
560 :
561 7 : 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;
567 : OPENDDS_SET(ACE_INET_Addr) set6;
568 : #endif // ACE_HAS_IPV6
569 7 : OPENDDS_SET(ACE_INET_Addr) set4_loopback;
570 7 : OPENDDS_SET(ACE_INET_Addr) set4;
571 :
572 20 : 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 13 : if (it->get_type() == AF_INET && !it->is_multicast()) {
597 13 : if (it->is_loopback()) {
598 4 : 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 4 : set4_loopback.insert(*it);
601 : } else {
602 9 : 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 9 : 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 7 : if (prefer_loopback && !set4_loopback.empty()) {
616 2 : 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 5 : if (!set4.empty()) {
632 4 : 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 1 : if (!set4_loopback.empty()) {
645 1 : return tie_breaker(set4_loopback, name);
646 : }
647 :
648 0 : if (!addresses.empty()) {
649 0 : return tie_breaker(addresses, name);
650 : }
651 :
652 0 : return ACE_INET_Addr();
653 7 : }
654 :
655 9 : ACE_INET_Addr choose_single_coherent_address(const String& address, bool prefer_loopback, bool allow_ipv4_fallback)
656 : {
657 9 : ACE_INET_Addr result;
658 :
659 9 : if (address.empty()) {
660 0 : return ACE_INET_Addr();
661 : }
662 :
663 9 : String host_name_str;
664 9 : 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 9 : const String::size_type port_div = address.find_last_of(':');
677 : #endif
678 :
679 9 : 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 6 : host_name_str = address.substr(0, port_div);
687 : }
688 6 : 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 3 : host_name_str = address;
697 : }
698 : }
699 :
700 9 : if (host_name_str.empty()) {
701 0 : return ACE_INET_Addr();
702 : }
703 :
704 9 : 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 9 : std::memset(&inet_addr, 0, sizeof inet_addr);
714 :
715 9 : 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 9 : address_family = AF_INET;
740 : #endif /* ACE_HAS_IPV6 */
741 :
742 9 : 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 4 : inet_addr.in4_.sin_family = AF_INET;
747 4 : result.set_addr(&inet_addr, sizeof inet_addr);
748 4 : result.set_port_number(port_number, 1 /*encode*/);
749 4 : return result;
750 : }
751 :
752 : addrinfo hints;
753 5 : std::memset(&hints, 0, sizeof hints);
754 5 : 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 5 : hints.ai_socktype = SOCK_STREAM;
777 :
778 5 : addrinfo *res = 0;
779 5 : const int error = ACE_OS::getaddrinfo(host_name, 0, &hints, &res);
780 :
781 5 : if (error) {
782 0 : VDBG((LM_WARNING, "(%P|%t) WARNING: choose_single_coherent_address: Call to getaddrinfo for hostname %C returned error: %d\n", host_name, error));
783 0 : return ACE_INET_Addr();
784 : }
785 :
786 : struct AddrInfoGuard {
787 5 : AddrInfoGuard(addrinfo* ptr) : ptr_(ptr) {}
788 5 : ~AddrInfoGuard() {
789 5 : ACE_OS::freeaddrinfo(ptr_);
790 5 : }
791 : addrinfo* const ptr_;
792 5 : } guard(res);
793 :
794 5 : 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_);
802 : const SystemTimePoint now = SystemTimePoint::now();
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 10 : for (addrinfo* curr = res; curr; curr = curr->ai_next) {
818 5 : if (curr->ai_family != AF_INET && curr->ai_family != AF_INET6) {
819 0 : continue;
820 : }
821 : ip46 addr;
822 5 : std::memset(&addr, 0, sizeof addr);
823 5 : 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 5 : addr.in4_.sin_port = ACE_NTOHS(port_number);;
830 : #ifdef ACE_HAS_IPV6
831 : }
832 : #endif /* ACE_HAS_IPV6 */
833 :
834 5 : ACE_INET_Addr temp;
835 5 : temp.set_addr(&addr, sizeof addr);
836 5 : 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 5 : }
847 :
848 : #ifdef ACE_WIN32
849 : g.release();
850 : #endif /* ACE_WIN32 */
851 :
852 5 : result = choose_single_coherent_address(addresses, prefer_loopback, host_name);
853 5 : result.set_port_number(port_number, 1 /*encode*/);
854 5 : return result;
855 9 : }
856 :
857 16 : int locator_to_address(ACE_INET_Addr& dest,
858 : const DCPS::Locator_t& locator,
859 : bool map /*map IPV4 to IPV6 addr*/)
860 : {
861 16 : 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 10 : case LOCATOR_KIND_UDPv4:
873 : #if !defined (ACE_HAS_IPV6) || !defined (IPV6_V6ONLY)
874 : ACE_UNUSED_ARG(map);
875 : #endif
876 10 : dest.set_type(AF_INET);
877 10 : 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 10 : ) == -1) {
883 0 : return -1;
884 : }
885 10 : dest.set_port_number(locator.port);
886 10 : return 0;
887 6 : default:
888 6 : return -1; // Unknown kind
889 : }
890 :
891 : return -1;
892 : }
893 :
894 : OpenDDS_Dcps_Export
895 0 : void address_to_locator(Locator_t& locator,
896 : const ACE_INET_Addr& addr)
897 : {
898 0 : const void* raw = addr.get_addr();
899 0 : switch (addr.get_type()) {
900 0 : case AF_INET:
901 : {
902 0 : locator.kind = LOCATOR_KIND_UDPv4;
903 0 : const sockaddr_in* in = static_cast<const sockaddr_in*>(raw);
904 0 : std::memset(&locator.address[0], 0, 12);
905 0 : std::memcpy(&locator.address[12], &in->sin_addr, 4);
906 : }
907 0 : 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 0 : default:
918 0 : locator.kind = LOCATOR_KIND_INVALID;
919 0 : std::memset(&locator.address[0], 0, 16);
920 0 : break;
921 : }
922 0 : locator.port = addr.get_port_number();
923 0 : }
924 :
925 : }
926 : }
927 :
928 : OPENDDS_END_VERSIONED_NAMESPACE_DECL
|