2 #include "tao/IIOP_Endpoint.h"
4 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
8 #include "tao/ORB_Core.h"
9 #include "tao/IIOP_Profile.h"
11 #include "ace/Log_Msg.h"
12 #include "ace/Guard_T.h"
13 #include "ace/OS_NS_string.h"
14 #include "ace/OS_NS_strings.h"
16 #if !defined (__ACE_INLINE__)
17 # include "tao/IIOP_Endpoint.inl"
18 #endif /* __ACE_INLINE__ */
20 #include "ace/OS_NS_stdio.h"
21 #include "ace/os_include/os_netdb.h"
23 #include "ace/Vector_T.h"
25 #include "ace/INET_Addr.h"
26 #include "ace/Sock_Connect.h"
29 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
31 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const ACE_INET_Addr
&addr
,
32 int use_dotted_decimal_addresses
)
33 : TAO_Endpoint (IOP::TAG_INTERNET_IOP
)
35 , port_ (683) // default port (IANA assigned)
36 #if defined (ACE_HAS_IPV6)
37 , is_ipv6_decimal_ (false)
38 #endif /* ACE_HAS_IPV6 */
39 , is_encodable_ (true)
40 , object_addr_set_ (false)
45 this->set (addr
, use_dotted_decimal_addresses
);
48 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host
,
50 const ACE_INET_Addr
&addr
,
51 CORBA::Short priority
)
52 : TAO_Endpoint (IOP::TAG_INTERNET_IOP
, priority
)
55 #if defined (ACE_HAS_IPV6)
56 , is_ipv6_decimal_ (false)
57 #endif /* ACE_HAS_IPV6 */
58 , is_encodable_ (true)
59 , object_addr_set_ (false)
64 this->host(host
); // With IPv6 performs check for decimal address
67 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint ()
68 : TAO_Endpoint (IOP::TAG_INTERNET_IOP
)
70 , port_ (683) // default port (IANA assigned)
71 #if defined (ACE_HAS_IPV6)
72 , is_ipv6_decimal_ (false)
73 #endif /* ACE_HAS_IPV6 */
74 , is_encodable_ (true)
75 , object_addr_set_ (false)
82 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host
,
84 CORBA::Short priority
)
85 : TAO_Endpoint (IOP::TAG_INTERNET_IOP
, priority
)
88 #if defined (ACE_HAS_IPV6)
89 , is_ipv6_decimal_ (false)
90 #endif /* ACE_HAS_IPV6 */
91 , is_encodable_ (true)
92 , object_addr_set_ (false)
97 this->host(host
); // With IPv6 performs check for decimal address
101 TAO_IIOP_Endpoint::operator= (const TAO_IIOP_Endpoint
&other
)
103 if (this != std::addressof(other
))
105 this->host_
= other
.host_
;
106 this->port_
= other
.port_
;
107 #if defined (ACE_HAS_IPV6)
108 this->is_ipv6_decimal_
= other
.is_ipv6_decimal_
;
109 #endif /* ACE_HAS_IPV6 */
110 this->is_encodable_
= other
.is_encodable_
;
111 this->object_addr_set_
= other
.object_addr_set_
;
112 this->object_addr_
= other
.object_addr_
;
113 this->preferred_path_
= other
.preferred_path_
;
114 this->next_
= nullptr; // do not copy list membership, since we are only cloning the values
119 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const TAO_IIOP_Endpoint
&rhs
)
120 : TAO_Endpoint (rhs
.tag_
, rhs
.priority_
)
123 #if defined (ACE_HAS_IPV6)
124 , is_ipv6_decimal_ (rhs
.is_ipv6_decimal_
)
125 #endif /* ACE_HAS_IPV6 */
126 , is_encodable_ (rhs
.is_encodable_
)
127 , object_addr_set_ (rhs
.object_addr_set_
)
128 , object_addr_ (rhs
.object_addr_
)
129 , preferred_path_ (rhs
.preferred_path_
)
135 TAO_IIOP_Endpoint::set (const ACE_INET_Addr
&addr
,
136 int use_dotted_decimal_addresses
)
138 char tmp_host
[MAXHOSTNAMELEN
+ 1];
140 #if defined (ACE_HAS_IPV6)
141 this->is_ipv6_decimal_
= false; // Reset
142 #endif /* ACE_HAS_IPV6 */
144 if (use_dotted_decimal_addresses
145 || addr
.get_host_name (tmp_host
, sizeof (tmp_host
)) != 0)
147 if (use_dotted_decimal_addresses
== 0 && TAO_debug_level
> 5)
149 TAOLIB_DEBUG ((LM_DEBUG
,
150 ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ")
152 ACE_TEXT ("cannot determine hostname")));
155 const char *tmp
= addr
.get_host_addr ();
158 if (TAO_debug_level
> 0)
160 TAOLIB_ERROR ((LM_ERROR
,
161 ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ")
163 ACE_TEXT ("cannot determine hostname and hostaddr")));
170 #if defined (ACE_HAS_IPV6)
171 if (addr
.get_type () == PF_INET6
)
172 this->is_ipv6_decimal_
= true;
173 #endif /* ACE_HAS_IPV6 */
177 this->host_
= CORBA::string_dup (tmp_host
);
179 this->port_
= addr
.get_port_number();
185 TAO_IIOP_Endpoint::addr_to_string (char *buffer
, size_t length
)
188 ACE_OS::strlen (this->host_
.in ()) // chars in host name
189 + sizeof (':') // delimiter
190 + std::strlen ("65536") // max port
193 #if defined (ACE_HAS_IPV6)
194 if (this->is_ipv6_decimal_
)
195 actual_len
+= 2; // '[' + ']'
196 #endif /* ACE_HAS_IPV6 */
198 if (length
< actual_len
)
201 #if defined (ACE_HAS_IPV6)
202 if (this->is_ipv6_decimal_
)
203 ACE_OS::sprintf (buffer
, "[%s]:%d",
204 this->host_
.in (), this->port_
);
206 #endif /* ACE_HAS_IPV6 */
207 ACE_OS::sprintf (buffer
, "%s:%d",
208 this->host_
.in (), this->port_
);
214 TAO_IIOP_Endpoint::host (const char *h
)
217 #if defined (ACE_HAS_IPV6)
218 if (std::strchr (h
, ':') != 0)
219 this->is_ipv6_decimal_
= true;
220 #endif /* ACE_HAS_IPV6 */
222 return this->host_
.in ();
226 TAO_IIOP_Endpoint::next ()
232 TAO_IIOP_Endpoint::next_filtered (TAO_ORB_Core
* orb_core
, TAO_Endpoint
*root
)
234 bool want_ipv6
= false;
235 bool ipv6_only
= false;
236 bool prefer_ipv6
= false;
237 #if defined (ACE_HAS_IPV6)
238 want_ipv6
= root
== 0 || this->is_ipv6_decimal();
239 ipv6_only
= orb_core
->orb_params()->connect_ipv6_only();
240 prefer_ipv6
= orb_core
->orb_params()->prefer_ipv6_interfaces();
242 ACE_UNUSED_ARG (orb_core
);
243 #endif /* ACE_HAS_IPV6 */
245 this->next_filtered_i (static_cast<TAO_IIOP_Endpoint
*>(root
),
252 TAO_IIOP_Endpoint::next_filtered_i (TAO_IIOP_Endpoint
*root
,
257 // the candidate is nominally the next entry in the list, but since
258 // the list may loop back on itself, the root of the list needs to be
260 TAO_IIOP_Endpoint
*candidate
= (root
== nullptr) ? this : next_
;
264 #if defined (ACE_HAS_IPV6)
267 if (candidate
== 0 || candidate
->is_ipv6_decimal())
269 const ACE_INET_Addr
&addr
= candidate
->object_addr ();
270 bool allowed
= addr
.get_type () == AF_INET6
&&
271 !addr
.is_ipv4_mapped_ipv6();
273 return allowed
? candidate
:
274 candidate
->next_filtered_i(root
, ipv6_only
, prefer_ipv6
, true);
279 return !want_ipv6
? candidate
:
280 root
->next_filtered_i(0, ipv6_only
, prefer_ipv6
, false);
282 if (want_ipv6
== candidate
->is_ipv6_decimal())
285 const ACE_INET_Addr
&addr
= candidate
->object_addr ();
286 bool really_ipv6
= addr
.get_type () == AF_INET6
&&
287 !addr
.is_ipv4_mapped_ipv6();
288 return (want_ipv6
== really_ipv6
) ? candidate
:
289 candidate
->next_filtered_i(root
, ipv6_only
, prefer_ipv6
, want_ipv6
);
292 ACE_UNUSED_ARG (want_ipv6
);
293 ACE_UNUSED_ARG (ipv6_only
);
294 ACE_UNUSED_ARG (prefer_ipv6
);
301 TAO_IIOP_Endpoint::duplicate ()
303 TAO_IIOP_Endpoint
*endpoint
= nullptr;
305 // @@ NOTE: Not exception safe..
306 ACE_NEW_RETURN (endpoint
, TAO_IIOP_Endpoint (*this), nullptr);
311 const ACE_INET_Addr
&
312 TAO_IIOP_Endpoint::object_addr () const
314 // The object_addr_ is initialized here, rather than at IOR decode
315 // time for several reasons:
316 // 1. A request on the object may never be invoked.
317 // 2. The DNS setup may have changed dynamically.
320 // Double checked locking optimization.
321 if (!this->object_addr_set_
)
323 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX
,
325 this->addr_lookup_lock_
,
328 if (!this->object_addr_set_
)
330 (void) this->object_addr_i ();
334 return this->object_addr_
;
338 TAO_IIOP_Endpoint::object_addr_i () const
340 // We should have already held the lock
342 #if defined (ACE_HAS_IPV6)
343 bool is_ipv4_decimal_
= false;
344 if (!this->is_ipv6_decimal_
)
346 ACE_OS::strspn (this->host_
.in (), ".0123456789") ==
347 std::strlen (this->host_
.in ());
349 // If this is *not* an IPv4 decimal address at first try to
350 // resolve the address as an IPv6 address; if that fails
351 // (or it's an IPv4 address) and the address is *not* an IPv6
352 // decimal address try to resolve it as an IPv4 address.
353 if ((is_ipv4_decimal_
||
354 (!ACE::ipv6_enabled () ||
355 this->object_addr_
.set (this->port_
,
359 (this->is_ipv6_decimal_
||
360 this->object_addr_
.set (this->port_
,
365 if (this->object_addr_
.set (this->port_
,
366 this->host_
.in ()) == -1)
369 // If this call fails, it most likely due a hostname
370 // lookup failure caused by a DNS misconfiguration. If
371 // a request is made to the object at the given host and
372 // port, then a CORBA::TRANSIENT() exception should be
375 // Invalidate the ACE_INET_Addr. This is used as a flag
376 // to denote that ACE_INET_Addr initialization failed.
377 this->object_addr_
.set_type (-1);
381 this->object_addr_set_
= true;
386 TAO_IIOP_Endpoint::add_local_endpoint (TAO_IIOP_Endpoint
*ep
,
388 TAO_IIOP_Profile
&profile
)
390 TAO_IIOP_Endpoint
*tmp
= static_cast<TAO_IIOP_Endpoint
*> (ep
->duplicate ());
391 tmp
->is_encodable_
= true;
392 tmp
->preferred_path_
.host
= local
;
393 profile
.add_endpoint (tmp
);
397 // local helper function for TAO_IIOP_Endpoint::find_preferred_interfaces
399 TAO_IIOP_Endpoint_get_ip_interfaces (ACE_Vector
<ACE_CString
> &local_ips
)
401 ACE_INET_Addr
* tmp
= nullptr;
403 int err
= ACE::get_ip_interfaces (cnt
, tmp
);
406 #if defined (ACE_HAS_IPV6)
408 #else /* ACE_HAS_IPV6 */
410 #endif /* !ACE_HAS_IPV6 */
411 for (size_t i
= 0u; i
< cnt
; ++i
)
413 const char *s_if
= tmp
[i
].get_host_addr (buf
, sizeof (buf
));
414 ACE_ASSERT (s_if
!= nullptr);
415 ACE_CString
tmp (s_if
);
416 local_ips
.push_back (tmp
);
421 // local helper function for TAO_IIOP_Endpoint::find_preferred_interfaces
423 TAO_IIOP_Endpoint_none_duplicate_insert (
424 const ACE_CString
&value
,
425 ACE_Vector
<ACE_CString
> &vector
)
428 for (size_t x
= 0u; x
< vector
.size (); ++x
)
429 if (vector
[x
] == value
)
435 vector
.push_back (value
);
438 // Given a comma separated list of preferred interface directives, which
439 // are of the form <wild_remote>=<wild_local>, this function will retrieve
440 // the list of preferred local ip addresses by matching wild_local against
441 // the list of all local ip interfaces, for any directive where wild_remote
442 // matches the host from our endpoint.
444 TAO_IIOP_Endpoint::find_preferred_interfaces (
445 const ACE_CString
&host
,
446 const ACE_CString
&csvPreferred
,
447 ACE_Vector
<ACE_CString
> &preferred
)
449 ACE_Vector
<ACE_CString
> local_ips
;
450 TAO_IIOP_Endpoint_get_ip_interfaces (local_ips
);
451 if (local_ips
.size () == 0)
454 // The outer loop steps through each preferred interface directive
455 // and chains a new endpoint if the remote interface matches the
457 ACE_CString::size_type index
= 0;
458 while (index
< csvPreferred
.length ())
460 ACE_CString::size_type comma
= csvPreferred
.find (',', index
);
461 ACE_CString::size_type assign
= csvPreferred
.find ('=', index
);
463 if (assign
== ACE_CString::npos
)
465 assign
= csvPreferred
.find (':', index
);
466 if (assign
== ACE_CString::npos
)
468 ACE_ASSERT (assign
!= ACE_CString::npos
);
473 ACE_CString wild_local
;
474 if (comma
== ACE_CString::npos
)
475 wild_local
= csvPreferred
.substr (assign
+ 1);
477 wild_local
= csvPreferred
.substr (assign
+ 1, comma
- assign
- 1);
478 ACE_CString wild_remote
= csvPreferred
.substr (index
, assign
- index
);
481 // For now, we just try to match against the host literally. In
482 // the future it might be worthwhile to resolve some aliases for
483 // this->host_ using DNS (and possibly reverse DNS) lookups. Then we
484 // could try matching against those too.
485 if (ACE::wild_match (host
.c_str (), wild_remote
.c_str (), false))
487 // If it's a match, then it means we need to use any/all
488 // local interface(s) that matches wild_local.
489 const char *const wild_local_cstr
= wild_local
.c_str ();
491 for (size_t i
= 0u; i
< local_ips
.size (); ++i
)
493 ACE_CString
&ret
= local_ips
[i
];
494 if (ACE::wild_match (ret
.c_str (), wild_local_cstr
))
497 TAO_IIOP_Endpoint_none_duplicate_insert (ret
, preferred
);
503 #if defined (ACE_HAS_IPV6)
504 // We interpret the preferred wild_local as an actual interface name/id.
505 // This is useful for link local IPv6 multicast
507 ACE_CString
if_name ("if=");
508 if_name
+= wild_local
;
509 TAO_IIOP_Endpoint_none_duplicate_insert (if_name
, preferred
);
511 // There is no matching local interface, so we can skip
512 // to the next preferred interface directive.
518 // The preferred interface directive is for a different
521 if (comma
== ACE_CString::npos
)
527 TAO_IIOP_Endpoint::preferred_interfaces (const char *csv
,
529 TAO_IIOP_Profile
&profile
)
531 ACE_Vector
<ACE_CString
> preferred
;
532 find_preferred_interfaces(this->host_
.in(), csv
, preferred
);
533 CORBA::ULong count
= static_cast<CORBA::ULong
> (preferred
.size());
535 while (i
< count
&& ACE_OS::strstr (preferred
[i
].c_str(), "if=") != nullptr)
537 // For now we disregard these with IIOP
542 this->is_encodable_
= true;
543 this->preferred_path_
.host
= CORBA::string_dup(preferred
[i
].c_str());
544 TAO_IIOP_Endpoint
* ep
= this;
545 for (++i
; i
< count
; ++i
)
547 if (ACE_OS::strstr (preferred
[i
].c_str(), "if=") == nullptr)
548 ep
= add_local_endpoint (ep
, preferred
[i
].c_str(), profile
);
551 // If we're not enforcing the preferred interfaces, then we can just add
552 // a new non-preferred endpoint to the end with a default local addr.
555 ep
= add_local_endpoint (ep
, "", profile
);
566 TAO_IIOP_Endpoint::is_equivalent (const TAO_Endpoint
*other_endpoint
)
568 const TAO_IIOP_Endpoint
*endpoint
=
569 dynamic_cast<const TAO_IIOP_Endpoint
*> (other_endpoint
);
571 if (endpoint
== nullptr)
574 return (this->port_
== endpoint
->port_
575 && (ACE_OS::strcmp (this->host (), endpoint
->host ()) == 0));
579 TAO_IIOP_Endpoint::hash ()
581 if (this->hash_val_
!= 0)
582 return this->hash_val_
;
585 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX
,
587 this->addr_lookup_lock_
,
590 if (this->hash_val_
!= 0)
591 return this->hash_val_
;
593 // A few comments about this optimization. The call below will
594 // deadlock if the object_addr_set is false. If you don't belive
596 if (!this->object_addr_set_
)
598 // Set the object_addr first
599 (void) this->object_addr_i ();
602 this->hash_val_
= this->object_addr_
.hash ();
605 return this->hash_val_
;
609 TAO_IIOP_Endpoint::is_preferred_network () const
611 return (this->preferred_path_
.host
.in () != nullptr &&
612 this->preferred_path_
.host
.in ()[0] != 0);
616 TAO_IIOP_Endpoint::preferred_network () const
618 return this->preferred_path_
.host
.in ();
621 TAO_END_VERSIONED_NAMESPACE_DECL
623 #endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */