Merge pull request #1551 from DOCGroup/plm_jira_333
[ACE_TAO.git] / TAO / tao / IIOP_Endpoint.cpp
blobee036dfc7e3425b9f028787b89e0e79be32d1132
1 // -*- C++ -*-
2 /*
3 * Add all include files within the following
4 * two markers.
5 */
6 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_START
8 #include "tao/IIOP_Endpoint.h"
10 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
12 #include "tao/IOPC.h"
13 #include "tao/debug.h"
14 #include "tao/ORB_Core.h"
15 #include "tao/IIOP_Profile.h"
17 #include "ace/Log_Msg.h"
18 #include "ace/Guard_T.h"
19 #include "ace/OS_NS_string.h"
20 #include "ace/OS_NS_strings.h"
22 #if !defined (__ACE_INLINE__)
23 # include "tao/IIOP_Endpoint.inl"
24 #endif /* __ACE_INLINE__ */
26 #include "ace/OS_NS_stdio.h"
27 #include "ace/os_include/os_netdb.h"
29 #include "ace/Vector_T.h"
30 #include "ace/ACE.h"
31 #include "ace/INET_Addr.h"
32 #include "ace/Sock_Connect.h"
34 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_END
36 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
38 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_START
39 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const ACE_INET_Addr &addr,
40 int use_dotted_decimal_addresses)
41 : TAO_Endpoint (IOP::TAG_INTERNET_IOP)
42 , host_ ()
43 , port_ (683) // default port (IANA assigned)
44 #if defined (ACE_HAS_IPV6)
45 , is_ipv6_decimal_ (false)
46 #endif /* ACE_HAS_IPV6 */
47 , is_encodable_ (true)
48 , object_addr_set_ (false)
49 , object_addr_ (addr)
50 , preferred_path_ ()
51 , next_ (0)
53 this->set (addr, use_dotted_decimal_addresses);
56 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host,
57 CORBA::UShort port,
58 const ACE_INET_Addr &addr,
59 CORBA::Short priority)
60 : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority)
61 , host_ ()
62 , port_ (port)
63 #if defined (ACE_HAS_IPV6)
64 , is_ipv6_decimal_ (false)
65 #endif /* ACE_HAS_IPV6 */
66 , is_encodable_ (true)
67 , object_addr_set_ (false)
68 , object_addr_ (addr)
69 , preferred_path_ ()
70 , next_ (0)
72 this->host(host); // With IPv6 performs check for decimal address
75 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (void)
76 : TAO_Endpoint (IOP::TAG_INTERNET_IOP)
77 , host_ ()
78 , port_ (683) // default port (IANA assigned)
79 #if defined (ACE_HAS_IPV6)
80 , is_ipv6_decimal_ (false)
81 #endif /* ACE_HAS_IPV6 */
82 , is_encodable_ (true)
83 , object_addr_set_ (false)
84 , object_addr_ ()
85 , preferred_path_ ()
86 , next_ (0)
90 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host,
91 CORBA::UShort port,
92 CORBA::Short priority)
93 : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority)
94 , host_ ()
95 , port_ (port)
96 #if defined (ACE_HAS_IPV6)
97 , is_ipv6_decimal_ (false)
98 #endif /* ACE_HAS_IPV6 */
99 , is_encodable_ (true)
100 , object_addr_set_ (false)
101 , object_addr_ ()
102 , preferred_path_ ()
103 , next_ (0)
105 this->host(host); // With IPv6 performs check for decimal address
107 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_END
110 TAO_IIOP_Endpoint &
111 TAO_IIOP_Endpoint::operator= (const TAO_IIOP_Endpoint &other)
113 if (this != &other)
115 this->host_ = other.host_;
116 this->port_ = other.port_;
117 #if defined (ACE_HAS_IPV6)
118 this->is_ipv6_decimal_ = other.is_ipv6_decimal_;
119 #endif /* ACE_HAS_IPV6 */
120 this->is_encodable_ = other.is_encodable_;
121 this->object_addr_set_ = other.object_addr_set_;
122 this->object_addr_ = other.object_addr_;
123 this->preferred_path_ = other.preferred_path_;
124 this->next_ = 0; // do not copy list membership, since we are only cloning the values
126 return *this;
129 TAO_IIOP_Endpoint::~TAO_IIOP_Endpoint (void)
133 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_START
135 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const TAO_IIOP_Endpoint &rhs)
136 : TAO_Endpoint (rhs.tag_, rhs.priority_)
137 , host_ (rhs.host_)
138 , port_ (rhs.port_)
139 #if defined (ACE_HAS_IPV6)
140 , is_ipv6_decimal_ (rhs.is_ipv6_decimal_)
141 #endif /* ACE_HAS_IPV6 */
142 , is_encodable_ (rhs.is_encodable_)
143 , object_addr_set_ (rhs.object_addr_set_)
144 , object_addr_ (rhs.object_addr_)
145 , preferred_path_ (rhs.preferred_path_)
146 , next_ (0)
151 TAO_IIOP_Endpoint::set (const ACE_INET_Addr &addr,
152 int use_dotted_decimal_addresses)
154 char tmp_host[MAXHOSTNAMELEN + 1];
156 #if defined (ACE_HAS_IPV6)
157 this->is_ipv6_decimal_ = false; // Reset
158 #endif /* ACE_HAS_IPV6 */
160 if (use_dotted_decimal_addresses
161 || addr.get_host_name (tmp_host, sizeof (tmp_host)) != 0)
163 if (use_dotted_decimal_addresses == 0 && TAO_debug_level > 5)
165 TAOLIB_DEBUG ((LM_DEBUG,
166 ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ")
167 ACE_TEXT ("%p\n"),
168 ACE_TEXT ("cannot determine hostname")));
171 const char *tmp = addr.get_host_addr ();
172 if (tmp == 0)
174 if (TAO_debug_level > 0)
176 TAOLIB_ERROR ((LM_ERROR,
177 ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ")
178 ACE_TEXT ("%p\n"),
179 ACE_TEXT ("cannot determine hostname and hostaddr")));
181 return -1;
183 else
185 this->host_ = tmp;
186 #if defined (ACE_HAS_IPV6)
187 if (addr.get_type () == PF_INET6)
188 this->is_ipv6_decimal_ = true;
189 #endif /* ACE_HAS_IPV6 */
192 else
193 this->host_ = CORBA::string_dup (tmp_host);
195 this->port_ = addr.get_port_number();
197 return 0;
201 TAO_IIOP_Endpoint::addr_to_string (char *buffer, size_t length)
203 size_t actual_len =
204 ACE_OS::strlen (this->host_.in ()) // chars in host name
205 + sizeof (':') // delimiter
206 + ACE_OS::strlen ("65536") // max port
207 + sizeof ('\0');
209 #if defined (ACE_HAS_IPV6)
210 if (this->is_ipv6_decimal_)
211 actual_len += 2; // '[' + ']'
212 #endif /* ACE_HAS_IPV6 */
214 if (length < actual_len)
215 return -1;
217 #if defined (ACE_HAS_IPV6)
218 if (this->is_ipv6_decimal_)
219 ACE_OS::sprintf (buffer, "[%s]:%d",
220 this->host_.in (), this->port_);
221 else
222 #endif /* ACE_HAS_IPV6 */
223 ACE_OS::sprintf (buffer, "%s:%d",
224 this->host_.in (), this->port_);
226 return 0;
229 const char *
230 TAO_IIOP_Endpoint::host (const char *h)
232 this->host_ = h;
233 #if defined (ACE_HAS_IPV6)
234 if (ACE_OS::strchr (h, ':') != 0)
235 this->is_ipv6_decimal_ = true;
236 #endif /* ACE_HAS_IPV6 */
238 return this->host_.in ();
241 TAO_Endpoint *
242 TAO_IIOP_Endpoint::next (void)
244 return this->next_;
247 TAO_Endpoint *
248 TAO_IIOP_Endpoint::next_filtered (TAO_ORB_Core * orb_core, TAO_Endpoint *root)
250 bool want_ipv6 = false;
251 bool ipv6_only = false;
252 bool prefer_ipv6 = false;
253 #if defined (ACE_HAS_IPV6)
254 want_ipv6 = root == 0 || this->is_ipv6_decimal();
255 ipv6_only = orb_core->orb_params()->connect_ipv6_only();
256 prefer_ipv6 = orb_core->orb_params()->prefer_ipv6_interfaces();
257 #else
258 ACE_UNUSED_ARG (orb_core);
259 #endif /* ACE_HAS_IPV6 */
260 return
261 this->next_filtered_i (static_cast<TAO_IIOP_Endpoint *>(root),
262 ipv6_only,
263 prefer_ipv6,
264 want_ipv6);
267 TAO_IIOP_Endpoint*
268 TAO_IIOP_Endpoint::next_filtered_i (TAO_IIOP_Endpoint *root,
269 bool ipv6_only,
270 bool prefer_ipv6,
271 bool want_ipv6)
273 // the candidate is nominally the next entry in the list, but since
274 // the list may loop back on itself, the root of the list needs to be
275 // initialized.
276 TAO_IIOP_Endpoint *candidate = (root == 0) ? this : next_;
277 if (root == 0)
278 root = this;
280 #if defined (ACE_HAS_IPV6)
281 if (ipv6_only)
283 if (candidate == 0 || candidate->is_ipv6_decimal())
284 return candidate;
285 const ACE_INET_Addr &addr = candidate->object_addr ();
286 bool allowed = addr.get_type () == AF_INET6 &&
287 !addr.is_ipv4_mapped_ipv6();
289 return allowed ? candidate :
290 candidate->next_filtered_i(root, ipv6_only, prefer_ipv6, true);
292 if (prefer_ipv6)
294 if (candidate == 0)
295 return !want_ipv6 ? candidate :
296 root->next_filtered_i(0, ipv6_only, prefer_ipv6, false);
298 if (want_ipv6 == candidate->is_ipv6_decimal())
299 return candidate;
301 const ACE_INET_Addr &addr = candidate->object_addr ();
302 bool really_ipv6 = addr.get_type () == AF_INET6 &&
303 !addr.is_ipv4_mapped_ipv6();
304 return (want_ipv6 == really_ipv6) ? candidate :
305 candidate->next_filtered_i(root, ipv6_only, prefer_ipv6, want_ipv6);
307 #else
308 ACE_UNUSED_ARG (want_ipv6);
309 ACE_UNUSED_ARG (ipv6_only);
310 ACE_UNUSED_ARG (prefer_ipv6);
311 #endif
313 return candidate;
316 TAO_Endpoint *
317 TAO_IIOP_Endpoint::duplicate (void)
319 TAO_IIOP_Endpoint *endpoint = 0;
321 // @@ NOTE: Not exception safe..
322 ACE_NEW_RETURN (endpoint, TAO_IIOP_Endpoint (*this), 0);
324 return endpoint;
327 const ACE_INET_Addr &
328 TAO_IIOP_Endpoint::object_addr (void) const
330 // The object_addr_ is initialized here, rather than at IOR decode
331 // time for several reasons:
332 // 1. A request on the object may never be invoked.
333 // 2. The DNS setup may have changed dynamically.
334 // ...etc..
336 // Double checked locking optimization.
337 if (!this->object_addr_set_)
339 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX,
340 guard,
341 this->addr_lookup_lock_,
342 this->object_addr_);
344 if (!this->object_addr_set_)
346 (void) this->object_addr_i ();
350 return this->object_addr_;
353 void
354 TAO_IIOP_Endpoint::object_addr_i (void) const
356 // We should have already held the lock
358 #if defined (ACE_HAS_IPV6)
359 bool is_ipv4_decimal_ = false;
360 if (!this->is_ipv6_decimal_)
361 is_ipv4_decimal_ =
362 ACE_OS::strspn (this->host_.in (), ".0123456789") ==
363 ACE_OS::strlen (this->host_.in ());
365 // If this is *not* an IPv4 decimal address at first try to
366 // resolve the address as an IPv6 address; if that fails
367 // (or it's an IPv4 address) and the address is *not* an IPv6
368 // decimal address try to resolve it as an IPv4 address.
369 if ((is_ipv4_decimal_ ||
370 (!ACE::ipv6_enabled () ||
371 this->object_addr_.set (this->port_,
372 this->host_.in (),
374 AF_INET6) == -1)) &&
375 (this->is_ipv6_decimal_ ||
376 this->object_addr_.set (this->port_,
377 this->host_.in (),
379 AF_INET) == -1))
380 #else
381 if (this->object_addr_.set (this->port_,
382 this->host_.in ()) == -1)
383 #endif
385 // If this call fails, it most likely due a hostname
386 // lookup failure caused by a DNS misconfiguration. If
387 // a request is made to the object at the given host and
388 // port, then a CORBA::TRANSIENT() exception should be
389 // thrown.
391 // Invalidate the ACE_INET_Addr. This is used as a flag
392 // to denote that ACE_INET_Addr initialization failed.
393 this->object_addr_.set_type (-1);
395 else
397 this->object_addr_set_ = true;
401 TAO_IIOP_Endpoint *
402 TAO_IIOP_Endpoint::add_local_endpoint (TAO_IIOP_Endpoint *ep,
403 const char *local,
404 TAO_IIOP_Profile &profile)
406 TAO_IIOP_Endpoint *tmp = static_cast<TAO_IIOP_Endpoint *> (ep->duplicate ());
407 tmp->is_encodable_ = true;
408 tmp->preferred_path_.host = local;
409 profile.add_endpoint (tmp);
410 return tmp;
413 // local helper function for TAO_IIOP_Endpoint::find_preferred_interfaces
414 static void
415 TAO_IIOP_Endpoint_get_ip_interfaces (ACE_Vector<ACE_CString> &local_ips)
417 ACE_INET_Addr* tmp = 0;
418 size_t cnt = 0u;
419 int err = ACE::get_ip_interfaces (cnt, tmp);
420 if (err != 0)
421 return;
422 #if defined (ACE_HAS_IPV6)
423 char buf[64];
424 #else /* ACE_HAS_IPV6 */
425 char buf[32];
426 #endif /* !ACE_HAS_IPV6 */
427 for (size_t i = 0u; i < cnt; ++i)
429 const char *s_if = tmp[i].get_host_addr (buf, sizeof (buf));
430 ACE_ASSERT (s_if != 0);
431 ACE_CString tmp (s_if);
432 local_ips.push_back (tmp);
434 delete[] tmp;
437 // local helper function for TAO_IIOP_Endpoint::find_preferred_interfaces
438 static void
439 TAO_IIOP_Endpoint_none_duplicate_insert (
440 const ACE_CString &value,
441 ACE_Vector<ACE_CString> &vector)
443 bool found= false;
444 for (size_t x= 0u; x < vector.size (); ++x)
445 if (vector[x] == value)
447 found= true;
448 break;
450 if (!found)
451 vector.push_back (value);
454 // Given a comma separated list of preferred interface directives, which
455 // are of the form <wild_remote>=<wild_local>, this function will retrieve
456 // the list of preferred local ip addresses by matching wild_local against
457 // the list of all local ip interfaces, for any directive where wild_remote
458 // matches the host from our endpoint.
459 void
460 TAO_IIOP_Endpoint::find_preferred_interfaces (
461 const ACE_CString &host,
462 const ACE_CString &csvPreferred,
463 ACE_Vector<ACE_CString> &preferred)
465 ACE_Vector<ACE_CString> local_ips;
466 TAO_IIOP_Endpoint_get_ip_interfaces (local_ips);
467 if (local_ips.size () == 0)
468 return;
470 // The outer loop steps through each preferred interface directive
471 // and chains a new endpoint if the remote interface matches the
472 // current endpoint.
473 ACE_CString::size_type index = 0;
474 while (index < csvPreferred.length ())
476 ACE_CString::size_type comma = csvPreferred.find (',', index);
477 ACE_CString::size_type assign = csvPreferred.find ('=', index);
479 if (assign == ACE_CString::npos)
481 assign = csvPreferred.find (':', index);
482 if (assign == ACE_CString::npos)
484 ACE_ASSERT (assign != ACE_CString::npos);
485 return;
489 ACE_CString wild_local;
490 if (comma == ACE_CString::npos)
491 wild_local = csvPreferred.substr (assign + 1);
492 else
493 wild_local = csvPreferred.substr (assign + 1, comma - assign - 1);
494 ACE_CString wild_remote = csvPreferred.substr (index, assign - index);
495 index = comma + 1;
497 // For now, we just try to match against the host literally. In
498 // the future it might be worthwhile to resolve some aliases for
499 // this->host_ using DNS (and possibly reverse DNS) lookups. Then we
500 // could try matching against those too.
501 if (ACE::wild_match (host.c_str (), wild_remote.c_str (), false))
503 // If it's a match, then it means we need to use any/all
504 // local interface(s) that matches wild_local.
505 const char *const wild_local_cstr = wild_local.c_str ();
506 bool found= false;
507 for (size_t i = 0u; i < local_ips.size (); ++i)
509 ACE_CString &ret = local_ips[i];
510 if (ACE::wild_match (ret.c_str (), wild_local_cstr))
512 found= true;
513 TAO_IIOP_Endpoint_none_duplicate_insert (ret, preferred);
517 if (!found)
519 #if defined (ACE_HAS_IPV6)
520 // We interpret the preferred wild_local as an actual interface name/id.
521 // This is useful for link local IPv6 multicast
523 ACE_CString if_name ("if=");
524 if_name += wild_local;
525 TAO_IIOP_Endpoint_none_duplicate_insert (if_name, preferred);
526 #else
527 // There is no matching local interface, so we can skip
528 // to the next preferred interface directive.
529 #endif
532 else
534 // The preferred interface directive is for a different
535 // remote endpoint.
537 if (comma == ACE_CString::npos)
538 break;
542 CORBA::ULong
543 TAO_IIOP_Endpoint::preferred_interfaces (const char *csv,
544 bool enforce,
545 TAO_IIOP_Profile &profile)
547 ACE_Vector<ACE_CString> preferred;
548 find_preferred_interfaces(this->host_.in(), csv, preferred);
549 CORBA::ULong count = static_cast<CORBA::ULong> (preferred.size());
550 size_t i = 0;
551 while (i < count && ACE_OS::strstr (preferred[i].c_str(), "if=") != 0)
553 // For now we disregard these with IIOP
554 ++i;
556 if (i < count)
558 this->is_encodable_ = true;
559 this->preferred_path_.host = CORBA::string_dup(preferred[i].c_str());
560 TAO_IIOP_Endpoint* ep = this;
561 for (++i; i < count; ++i)
563 if (ACE_OS::strstr (preferred[i].c_str(), "if=") == 0)
564 ep = add_local_endpoint (ep, preferred[i].c_str(), profile);
567 // If we're not enforcing the preferred interfaces, then we can just add
568 // a new non-preferred endpoint to the end with a default local addr.
569 if (! enforce)
571 ep = add_local_endpoint (ep, "", profile);
573 else
575 --count;
578 return count;
581 CORBA::Boolean
582 TAO_IIOP_Endpoint::is_equivalent (const TAO_Endpoint *other_endpoint)
584 const TAO_IIOP_Endpoint *endpoint =
585 dynamic_cast<const TAO_IIOP_Endpoint *> (other_endpoint);
587 if (endpoint == 0)
588 return 0;
590 return (this->port_ == endpoint->port_
591 && (ACE_OS::strcmp (this->host (), endpoint->host ()) == 0));
594 CORBA::ULong
595 TAO_IIOP_Endpoint::hash (void)
597 if (this->hash_val_ != 0)
598 return this->hash_val_;
601 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX,
602 guard,
603 this->addr_lookup_lock_,
604 this->hash_val_);
605 // .. DCL
606 if (this->hash_val_ != 0)
607 return this->hash_val_;
609 // A few comments about this optimization. The call below will
610 // deadlock if the object_addr_set is false. If you don't belive
612 if (!this->object_addr_set_)
614 // Set the object_addr first
615 (void) this->object_addr_i ();
618 this->hash_val_ = this->object_addr_.hash ();
621 return this->hash_val_;
624 bool
625 TAO_IIOP_Endpoint::is_preferred_network (void) const
627 return (this->preferred_path_.host.in () != 0 &&
628 this->preferred_path_.host.in ()[0] != 0);
631 const char *
632 TAO_IIOP_Endpoint::preferred_network (void) const
634 return this->preferred_path_.host.in ();
637 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_END
639 TAO_END_VERSIONED_NAMESPACE_DECL
641 #endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */