diff options
Diffstat (limited to 'TAO/tao/IIOP_Endpoint.cpp')
-rw-r--r-- | TAO/tao/IIOP_Endpoint.cpp | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/TAO/tao/IIOP_Endpoint.cpp b/TAO/tao/IIOP_Endpoint.cpp new file mode 100644 index 00000000000..4538689ce28 --- /dev/null +++ b/TAO/tao/IIOP_Endpoint.cpp @@ -0,0 +1,608 @@ +/* + * Add all include files within the following + * two markers. + */ +//@@ TAO_ENDPOINT_SPL_COPY_HOOK_START + +#include "tao/IIOP_Endpoint.h" + +#if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0) + +#include "tao/IOP_IORC.h" +#include "tao/debug.h" +#include "tao/ORB_Core.h" + +#include "ace/Log_Msg.h" +#include "ace/Guard_T.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_strings.h" + +ACE_RCSID (tao, + IIOP_Endpoint, + "$Id$") + +#if !defined (__ACE_INLINE__) +# include "tao/IIOP_Endpoint.i" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_NS_stdio.h" +#include "ace/os_include/os_netdb.h" + +#include "ace/Vector_T.h" +#include "ace/ACE.h" +#include "ace/INET_Addr.h" +#include "ace/Sock_Connect.h" + +//@@ TAO_ENDPOINT_SPL_COPY_HOOK_END + +TAO_BEGIN_VERSIONED_NAMESPACE_DECL + +//@@ TAO_ENDPOINT_SPL_COPY_HOOK_START +TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const ACE_INET_Addr &addr, + int use_dotted_decimal_addresses) + : TAO_Endpoint (IOP::TAG_INTERNET_IOP) + , host_ () + , port_ (683) // default port (IANA assigned) +#if defined (ACE_HAS_IPV6) + , is_ipv6_decimal_ (false) +#endif /* ACE_HAS_IPV6 */ + , is_encodable_ (true) + , object_addr_set_ (false) + , object_addr_ (addr) + , preferred_path_ () + , next_ (0) +{ + this->set (addr, use_dotted_decimal_addresses); +} + +TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host, + CORBA::UShort port, + const ACE_INET_Addr &addr, + CORBA::Short priority) + : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority) + , host_ () + , port_ (port) +#if defined (ACE_HAS_IPV6) + , is_ipv6_decimal_ (false) +#endif /* ACE_HAS_IPV6 */ + , is_encodable_ (true) + , object_addr_set_ (false) + , object_addr_ (addr) + , preferred_path_ () + , next_ (0) +{ + this->host(host); // With IPv6 performs check for decimal address +} + +TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (void) + : TAO_Endpoint (IOP::TAG_INTERNET_IOP) + , host_ () + , port_ (683) // default port (IANA assigned) +#if defined (ACE_HAS_IPV6) + , is_ipv6_decimal_ (false) +#endif /* ACE_HAS_IPV6 */ + , is_encodable_ (true) + , object_addr_set_ (false) + , object_addr_ () + , preferred_path_ () + , next_ (0) +{ +} + +TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host, + CORBA::UShort port, + CORBA::Short priority) + : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority) + , host_ () + , port_ (port) +#if defined (ACE_HAS_IPV6) + , is_ipv6_decimal_ (false) +#endif /* ACE_HAS_IPV6 */ + , is_encodable_ (true) + , object_addr_set_ (false) + , object_addr_ () + , preferred_path_ () + , next_ (0) +{ + this->host(host); // With IPv6 performs check for decimal address +} +//@@ TAO_ENDPOINT_SPL_COPY_HOOK_END + + +TAO_IIOP_Endpoint & +TAO_IIOP_Endpoint::operator= (const TAO_IIOP_Endpoint &other) +{ + this->host_ = other.host_; + this->port_ = other.port_; +#if defined (ACE_HAS_IPV6) + this->is_ipv6_decimal_ = other.is_ipv6_decimal_; +#endif /* ACE_HAS_IPV6 */ + this->is_encodable_ = other.is_encodable_; + this->object_addr_set_ = other.object_addr_set_; + this->object_addr_ = other.object_addr_; + this->preferred_path_ = other.preferred_path_; + this->next_ = 0; // do not copy list membership, since we are only cloning the values + return *this; +} + +TAO_IIOP_Endpoint::~TAO_IIOP_Endpoint (void) +{ +} + +//@@ TAO_ENDPOINT_SPL_COPY_HOOK_START + +TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const TAO_IIOP_Endpoint &rhs) + : TAO_Endpoint (rhs.tag_, rhs.priority_) + , host_ (rhs.host_) + , port_ (rhs.port_) +#if defined (ACE_HAS_IPV6) + , is_ipv6_decimal_ (rhs.is_ipv6_decimal_) +#endif /* ACE_HAS_IPV6 */ + , is_encodable_ (rhs.is_encodable_) + , object_addr_set_ (rhs.object_addr_set_) + , object_addr_ (rhs.object_addr_) + , preferred_path_ (rhs.preferred_path_) + , next_ (0) +{ +} + +int +TAO_IIOP_Endpoint::set (const ACE_INET_Addr &addr, + int use_dotted_decimal_addresses) +{ + char tmp_host[MAXHOSTNAMELEN + 1]; + +#if defined (ACE_HAS_IPV6) + this->is_ipv6_decimal_ = false; // Reset +#endif /* ACE_HAS_IPV6 */ + + if (use_dotted_decimal_addresses + || addr.get_host_name (tmp_host, sizeof (tmp_host)) != 0) + { + if (use_dotted_decimal_addresses == 0 && TAO_debug_level > 5) + { + ACE_DEBUG ((LM_DEBUG, + ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ") + ACE_TEXT ("%p\n"), + ACE_TEXT ("cannot determine hostname"))); + } + + const char *tmp = addr.get_host_addr (); + if (tmp == 0) + { + if (TAO_debug_level > 0) + { + ACE_ERROR ((LM_ERROR, + ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ") + ACE_TEXT ("%p\n"), + ACE_TEXT ("cannot determine hostname and hostaddr"))); + } + return -1; + } + else + { + this->host_ = tmp; +#if defined (ACE_HAS_IPV6) + if (addr.get_type () == PF_INET6) + this->is_ipv6_decimal_ = true; +#endif /* ACE_HAS_IPV6 */ + } + } + else + this->host_ = CORBA::string_dup (tmp_host); + + this->port_ = addr.get_port_number(); + + return 0; +} + +int +TAO_IIOP_Endpoint::addr_to_string (char *buffer, size_t length) +{ + size_t actual_len = + ACE_OS::strlen (this->host_.in ()) // chars in host name + + sizeof (':') // delimiter + + ACE_OS::strlen ("65536") // max port + + sizeof ('\0'); + +#if defined (ACE_HAS_IPV6) + if (this->is_ipv6_decimal_) + actual_len += 2; // '[' + ']' +#endif /* ACE_HAS_IPV6 */ + + if (length < actual_len) + return -1; + +#if defined (ACE_HAS_IPV6) + if (this->is_ipv6_decimal_) + ACE_OS::sprintf (buffer, "[%s]:%d", + this->host_.in (), this->port_); + else +#endif /* ACE_HAS_IPV6 */ + ACE_OS::sprintf (buffer, "%s:%d", + this->host_.in (), this->port_); + + return 0; +} + +const char * +TAO_IIOP_Endpoint::host (const char *h) +{ + this->host_ = h; +#if defined (ACE_HAS_IPV6) + if (ACE_OS::strchr (h, ':') != 0) + this->is_ipv6_decimal_ = true; +#endif /* ACE_HAS_IPV6 */ + + return this->host_.in (); +} + +TAO_Endpoint * +TAO_IIOP_Endpoint::next (void) +{ + return this->next_; +} + +TAO_Endpoint * +TAO_IIOP_Endpoint::next_filtered (TAO_ORB_Core * orb_core, TAO_Endpoint *root) +{ + bool want_ipv6 = false; + bool ipv6_only = false; + bool prefer_ipv6 = false; +#if defined (ACE_HAS_IPV6) + want_ipv6 = true; + ipv6_only = orb_core->orb_params()->connect_ipv6_only(); + prefer_ipv6 = orb_core->orb_params()->prefer_ipv6_interfaces(); +#else + ACE_UNUSED_ARG (orb_core); +#endif /* ACE_HAS_IPV6 */ + return + this->next_filtered_i (static_cast<TAO_IIOP_Endpoint *>(root), + ipv6_only, + prefer_ipv6, + want_ipv6); +} + +TAO_IIOP_Endpoint* +TAO_IIOP_Endpoint::next_filtered_i (TAO_IIOP_Endpoint *root, + bool ipv6_only, + bool prefer_ipv6, + bool want_ipv6) +{ + // the candidate is nominally the next entry in the list, but since + // the list may loop back on itself, the root of the list needs to be + // initialized. + TAO_IIOP_Endpoint *candidate = (root == 0) ? this : next_; + if (root == 0) + root = this; + +#if defined (ACE_HAS_IPV6) + if (ipv6_only) + { + if (candidate == 0 || candidate->is_ipv6_decimal()) + return candidate; + const ACE_INET_Addr &addr = candidate->object_addr (); + bool allowed = addr.get_type () == AF_INET6 && + !addr.is_ipv4_mapped_ipv6(); + + return allowed ? candidate : + candidate->next_filtered_i(root, ipv6_only, prefer_ipv6, true); + } + if (prefer_ipv6) + { + if (candidate == 0) + return !want_ipv6 ? candidate : + root->next_filtered_i(root, ipv6_only, prefer_ipv6, false); + + if (want_ipv6 == candidate->is_ipv6_decimal()) + return candidate; + + const ACE_INET_Addr &addr = candidate->object_addr (); + bool really_ipv6 = addr.get_type () == AF_INET6 && + !addr.is_ipv4_mapped_ipv6(); + return (want_ipv6 == really_ipv6) ? candidate : + candidate->next_filtered_i(root, ipv6_only, prefer_ipv6, want_ipv6); + } +#else + ACE_UNUSED_ARG (want_ipv6); + ACE_UNUSED_ARG (ipv6_only); + ACE_UNUSED_ARG (prefer_ipv6); +#endif + + return candidate; +} + +TAO_Endpoint * +TAO_IIOP_Endpoint::duplicate (void) +{ + TAO_IIOP_Endpoint *endpoint = 0; + + // @@ NOTE: Not exception safe.. + ACE_NEW_RETURN (endpoint, TAO_IIOP_Endpoint (*this), 0); + + return endpoint; +} + +const ACE_INET_Addr & +TAO_IIOP_Endpoint::object_addr (void) const +{ + // The object_addr_ is initialized here, rather than at IOR decode + // time for several reasons: + // 1. A request on the object may never be invoked. + // 2. The DNS setup may have changed dynamically. + // ...etc.. + + // Double checked locking optimization. + if (!this->object_addr_set_) + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->addr_lookup_lock_, + this->object_addr_); + + if (!this->object_addr_set_) + { + (void) this->object_addr_i (); + } + } + + return this->object_addr_; +} + +void +TAO_IIOP_Endpoint::object_addr_i (void) const +{ + // We should have already held the lock + +#if defined (ACE_HAS_IPV6) + bool is_ipv4_decimal_ = false; + if (!this->is_ipv6_decimal_) + is_ipv4_decimal_ = + ACE_OS::strspn (this->host_.in (), ".0123456789") == + ACE_OS::strlen (this->host_.in ()); + + // If this is *not* an IPv4 decimal address at first try to + // resolve the address as an IPv6 address; if that fails + // (or it's an IPv4 address) and the address is *not* an IPv6 + // decimal address try to resolve it as an IPv4 address. + if ((is_ipv4_decimal_ || + this->object_addr_.set (this->port_, + this->host_.in (), + 1, + AF_INET6) == -1) && + (this->is_ipv6_decimal_ || + this->object_addr_.set (this->port_, + this->host_.in (), + 1, + AF_INET) == -1)) +#else + if (this->object_addr_.set (this->port_, + this->host_.in ()) == -1) +#endif + { + // If this call fails, it most likely due a hostname + // lookup failure caused by a DNS misconfiguration. If + // a request is made to the object at the given host and + // port, then a CORBA::TRANSIENT() exception should be + // thrown. + + // Invalidate the ACE_INET_Addr. This is used as a flag + // to denote that ACE_INET_Addr initialization failed. + this->object_addr_.set_type (-1); + } + else + { + this->object_addr_set_ = true; + } +} + +static ACE_CString find_local(const ACE_Vector<ACE_CString>& local_ips, + const ACE_CString& pattern) +{ + for (size_t i = 0; i < local_ips.size(); ++i) + { + ACE_CString ret = local_ips[i]; + if (ACE::wild_match(ret.c_str(), pattern.c_str())) + return ret; + } + return ""; +} + +TAO_IIOP_Endpoint* +TAO_IIOP_Endpoint::add_local_endpoint(TAO_IIOP_Endpoint* ep, const char* local) +{ + TAO_Endpoint* tmp = ep->duplicate(); + ep->next_ = static_cast<TAO_IIOP_Endpoint*>(tmp); + ep->next_->is_encodable_ = true; + ep->next_->preferred_path_.host = CORBA::string_dup(local); + return ep->next_; +} + +static void +get_ip_interfaces(ACE_Vector<ACE_CString>& local_ips) +{ + ACE_INET_Addr* tmp = 0; + size_t cnt = 0; + int err = ACE::get_ip_interfaces (cnt, tmp); + if (err != 0) + return; +#if defined (ACE_HAS_IPV6) + char buf[64]; +#else /* ACE_HAS_IPV6 */ + char buf[32]; +#endif /* !ACE_HAS_IPV6 */ + for (size_t i = 0; i < cnt; ++i) + { + const char *s_if = tmp[i].get_host_addr(buf, sizeof (buf)); + ACE_ASSERT(s_if != 0); + ACE_CString tmp(s_if); + //ssize_t pos = tmp.find(':'); + //if (pos != ACE_CString::npos) + // tmp = tmp.substr(0, pos); + local_ips.push_back(tmp); + } + delete[] tmp; +} + +// Given a comma separated list of preferred interface directives, which +// are of the form <wild_remote>=<wild_local>, this function will retrieve +// the list of preferred local ip addresses by matching wild_local against +// the list of all local ip interfaces, for any directive where wild_remote +// matches the host from our endpoint. +static void find_preferred_interfaces (const ACE_CString& host, + const ACE_CString& csvPreferred, + ACE_Vector<ACE_CString>& preferred) +{ + ACE_Vector<ACE_CString> local_ips; + get_ip_interfaces(local_ips); + if (local_ips.size() == 0) + return; + + // The outer loop steps through each preferred interface directive + // and chains a new endpoint if the remote interface matches the + // current endpoint. + ACE_CString::size_type index = 0; + while (index < csvPreferred.length()) + { + ACE_CString::size_type comma = csvPreferred.find(',', index); + ACE_CString::size_type assign = csvPreferred.find('=', index); + + if (assign == ACE_CString::npos) + { + assign = csvPreferred.find(':', index); + if (assign == ACE_CString::npos) + { + ACE_ASSERT(assign != ACE_CString::npos); + return; + } + } + + ACE_CString wild_local; + if (comma == ACE_CString::npos) + wild_local = csvPreferred.substr(assign + 1); + else + wild_local = csvPreferred.substr(assign + 1, comma - assign - 1); + ACE_CString wild_remote = csvPreferred.substr(index, assign - index); + + index = comma + 1; + + // For now, we just try to match against the host literally. In + // the future it might be worthwhile to resolve some aliases for + // this->host_ using DNS (and possibly reverse DNS) lookups. Then we + // could try matching against those too. + if (ACE::wild_match(host.c_str(), wild_remote.c_str(), false)) + { + // If it's a match, then it means we need to use a + // local interface that matches wild_local. + ACE_CString local = find_local(local_ips, wild_local); + if (local.length() > 0) + { + preferred.push_back(local); + } + else + { + // There is no matching local interface, so we can skip + // to the next preferred interface directive. + } + } + else + { + // The preferred interface directive is for a different + // remote endpoint. + } + if (comma == ACE_CString::npos) + break; + } +} + +CORBA::ULong +TAO_IIOP_Endpoint::preferred_interfaces (const char* csv, bool enforce) +{ + ACE_Vector<ACE_CString> preferred; + find_preferred_interfaces(this->host_.in(), csv, preferred); + CORBA::ULong count = preferred.size(); + if (count > 0) + { + this->is_encodable_ = true; + this->preferred_path_.host = CORBA::string_dup(preferred[0].c_str()); + TAO_IIOP_Endpoint* ep = this; + for (size_t i = 1; i < count; ++i) + { + ep = add_local_endpoint(ep, preferred[i].c_str()); + } + + // If we're not enforcing the preferred interfaces, then we can just add + // a new non-preferred endpoint to the end with a default local addr. + if (! enforce) + { + ep = add_local_endpoint(ep, ""); + } + else + { + --count; + } + } + return count; +} + +CORBA::Boolean +TAO_IIOP_Endpoint::is_equivalent (const TAO_Endpoint *other_endpoint) +{ + const TAO_IIOP_Endpoint *endpoint = + dynamic_cast<const TAO_IIOP_Endpoint *> (other_endpoint); + + if (endpoint == 0) + return 0; + + return (this->port_ == endpoint->port_ + && (ACE_OS::strcmp (this->host (), endpoint->host ()) == 0)); +} + +CORBA::ULong +TAO_IIOP_Endpoint::hash (void) +{ + if (this->hash_val_ != 0) + return this->hash_val_; + + { + ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, + guard, + this->addr_lookup_lock_, + this->hash_val_); + // .. DCL + if (this->hash_val_ != 0) + return this->hash_val_; + + // A few comments about this optimization. The call below will + // deadlock if the object_addr_set is false. If you don't belive + + if (!this->object_addr_set_) + { + // Set the object_addr first + (void) this->object_addr_i (); + } + + this->hash_val_ = this->object_addr_.hash (); + } + + return this->hash_val_; +} + +bool +TAO_IIOP_Endpoint::is_preferred_network (void) const +{ + return (this->preferred_path_.host.in () != 0 && + this->preferred_path_.host.in ()[0] != 0); +} + +const char * +TAO_IIOP_Endpoint::preferred_network (void) const +{ + return this->preferred_path_.host.in (); +} + +//@@ TAO_ENDPOINT_SPL_COPY_HOOK_END + +TAO_END_VERSIONED_NAMESPACE_DECL + +#endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */ |