Merge pull request #2303 from jwillemsen/jwi-803
[ACE_TAO.git] / TAO / tao / IIOP_Endpoint.cpp
blob3389f4e5459a0f4867fec8708f1862c383056a4e
1 // -*- C++ -*-
2 #include "tao/IIOP_Endpoint.h"
4 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
6 #include "tao/IOPC.h"
7 #include "tao/debug.h"
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"
24 #include "ace/ACE.h"
25 #include "ace/INET_Addr.h"
26 #include "ace/Sock_Connect.h"
27 #include <cstring>
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)
34 , host_ ()
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)
41 , object_addr_ (addr)
42 , preferred_path_ ()
43 , next_ (nullptr)
45 this->set (addr, use_dotted_decimal_addresses);
48 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host,
49 CORBA::UShort port,
50 const ACE_INET_Addr &addr,
51 CORBA::Short priority)
52 : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority)
53 , host_ ()
54 , port_ (port)
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)
60 , object_addr_ (addr)
61 , preferred_path_ ()
62 , next_ (nullptr)
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)
69 , host_ ()
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)
76 , object_addr_ ()
77 , preferred_path_ ()
78 , next_ (nullptr)
82 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host,
83 CORBA::UShort port,
84 CORBA::Short priority)
85 : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority)
86 , host_ ()
87 , port_ (port)
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)
93 , object_addr_ ()
94 , preferred_path_ ()
95 , next_ (nullptr)
97 this->host(host); // With IPv6 performs check for decimal address
100 TAO_IIOP_Endpoint &
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
116 return *this;
119 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const TAO_IIOP_Endpoint &rhs)
120 : TAO_Endpoint (rhs.tag_, rhs.priority_)
121 , host_ (rhs.host_)
122 , port_ (rhs.port_)
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_)
130 , next_ (nullptr)
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, ")
151 ACE_TEXT ("%p\n"),
152 ACE_TEXT ("cannot determine hostname")));
155 const char *tmp = addr.get_host_addr ();
156 if (tmp == nullptr)
158 if (TAO_debug_level > 0)
160 TAOLIB_ERROR ((LM_ERROR,
161 ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ")
162 ACE_TEXT ("%p\n"),
163 ACE_TEXT ("cannot determine hostname and hostaddr")));
165 return -1;
167 else
169 this->host_ = tmp;
170 #if defined (ACE_HAS_IPV6)
171 if (addr.get_type () == PF_INET6)
172 this->is_ipv6_decimal_ = true;
173 #endif /* ACE_HAS_IPV6 */
176 else
177 this->host_ = CORBA::string_dup (tmp_host);
179 this->port_ = addr.get_port_number();
181 return 0;
185 TAO_IIOP_Endpoint::addr_to_string (char *buffer, size_t length)
187 size_t actual_len =
188 ACE_OS::strlen (this->host_.in ()) // chars in host name
189 + sizeof (':') // delimiter
190 + std::strlen ("65536") // max port
191 + sizeof ('\0');
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)
199 return -1;
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_);
205 else
206 #endif /* ACE_HAS_IPV6 */
207 ACE_OS::sprintf (buffer, "%s:%d",
208 this->host_.in (), this->port_);
210 return 0;
213 const char *
214 TAO_IIOP_Endpoint::host (const char *h)
216 this->host_ = 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 ();
225 TAO_Endpoint *
226 TAO_IIOP_Endpoint::next ()
228 return this->next_;
231 TAO_Endpoint *
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();
241 #else
242 ACE_UNUSED_ARG (orb_core);
243 #endif /* ACE_HAS_IPV6 */
244 return
245 this->next_filtered_i (static_cast<TAO_IIOP_Endpoint *>(root),
246 ipv6_only,
247 prefer_ipv6,
248 want_ipv6);
251 TAO_IIOP_Endpoint*
252 TAO_IIOP_Endpoint::next_filtered_i (TAO_IIOP_Endpoint *root,
253 bool ipv6_only,
254 bool prefer_ipv6,
255 bool want_ipv6)
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
259 // initialized.
260 TAO_IIOP_Endpoint *candidate = (root == nullptr) ? this : next_;
261 if (root == nullptr)
262 root = this;
264 #if defined (ACE_HAS_IPV6)
265 if (ipv6_only)
267 if (candidate == 0 || candidate->is_ipv6_decimal())
268 return candidate;
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);
276 if (prefer_ipv6)
278 if (candidate == 0)
279 return !want_ipv6 ? candidate :
280 root->next_filtered_i(0, ipv6_only, prefer_ipv6, false);
282 if (want_ipv6 == candidate->is_ipv6_decimal())
283 return candidate;
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);
291 #else
292 ACE_UNUSED_ARG (want_ipv6);
293 ACE_UNUSED_ARG (ipv6_only);
294 ACE_UNUSED_ARG (prefer_ipv6);
295 #endif
297 return candidate;
300 TAO_Endpoint *
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);
308 return endpoint;
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.
318 // ...etc..
320 // Double checked locking optimization.
321 if (!this->object_addr_set_)
323 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX,
324 guard,
325 this->addr_lookup_lock_,
326 this->object_addr_);
328 if (!this->object_addr_set_)
330 (void) this->object_addr_i ();
334 return this->object_addr_;
337 void
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_)
345 is_ipv4_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_,
356 this->host_.in (),
358 AF_INET6) == -1)) &&
359 (this->is_ipv6_decimal_ ||
360 this->object_addr_.set (this->port_,
361 this->host_.in (),
363 AF_INET) == -1))
364 #else
365 if (this->object_addr_.set (this->port_,
366 this->host_.in ()) == -1)
367 #endif
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
373 // thrown.
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);
379 else
381 this->object_addr_set_ = true;
385 TAO_IIOP_Endpoint *
386 TAO_IIOP_Endpoint::add_local_endpoint (TAO_IIOP_Endpoint *ep,
387 const char *local,
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);
394 return tmp;
397 // local helper function for TAO_IIOP_Endpoint::find_preferred_interfaces
398 static void
399 TAO_IIOP_Endpoint_get_ip_interfaces (ACE_Vector<ACE_CString> &local_ips)
401 ACE_INET_Addr* tmp = nullptr;
402 size_t cnt = 0u;
403 int err = ACE::get_ip_interfaces (cnt, tmp);
404 if (err != 0)
405 return;
406 #if defined (ACE_HAS_IPV6)
407 char buf[64];
408 #else /* ACE_HAS_IPV6 */
409 char buf[32];
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);
418 delete[] tmp;
421 // local helper function for TAO_IIOP_Endpoint::find_preferred_interfaces
422 static void
423 TAO_IIOP_Endpoint_none_duplicate_insert (
424 const ACE_CString &value,
425 ACE_Vector<ACE_CString> &vector)
427 bool found= false;
428 for (size_t x= 0u; x < vector.size (); ++x)
429 if (vector[x] == value)
431 found= true;
432 break;
434 if (!found)
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.
443 void
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)
452 return;
454 // The outer loop steps through each preferred interface directive
455 // and chains a new endpoint if the remote interface matches the
456 // current endpoint.
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);
469 return;
473 ACE_CString wild_local;
474 if (comma == ACE_CString::npos)
475 wild_local = csvPreferred.substr (assign + 1);
476 else
477 wild_local = csvPreferred.substr (assign + 1, comma - assign - 1);
478 ACE_CString wild_remote = csvPreferred.substr (index, assign - index);
479 index = comma + 1;
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 ();
490 bool found= false;
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))
496 found= true;
497 TAO_IIOP_Endpoint_none_duplicate_insert (ret, preferred);
501 if (!found)
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);
510 #else
511 // There is no matching local interface, so we can skip
512 // to the next preferred interface directive.
513 #endif
516 else
518 // The preferred interface directive is for a different
519 // remote endpoint.
521 if (comma == ACE_CString::npos)
522 break;
526 CORBA::ULong
527 TAO_IIOP_Endpoint::preferred_interfaces (const char *csv,
528 bool enforce,
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());
534 size_t i = 0;
535 while (i < count && ACE_OS::strstr (preferred[i].c_str(), "if=") != nullptr)
537 // For now we disregard these with IIOP
538 ++i;
540 if (i < count)
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.
553 if (! enforce)
555 ep = add_local_endpoint (ep, "", profile);
557 else
559 --count;
562 return count;
565 CORBA::Boolean
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)
572 return 0;
574 return (this->port_ == endpoint->port_
575 && (ACE_OS::strcmp (this->host (), endpoint->host ()) == 0));
578 CORBA::ULong
579 TAO_IIOP_Endpoint::hash ()
581 if (this->hash_val_ != 0)
582 return this->hash_val_;
585 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX,
586 guard,
587 this->addr_lookup_lock_,
588 this->hash_val_);
589 // .. DCL
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_;
608 bool
609 TAO_IIOP_Endpoint::is_preferred_network () const
611 return (this->preferred_path_.host.in () != nullptr &&
612 this->preferred_path_.host.in ()[0] != 0);
615 const char *
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 */