IIOP_Endpoint.cpp

Go to the documentation of this file.
00001 /*
00002  * Add all include files within the following
00003  * two markers.
00004  */
00005 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_START
00006 
00007 #include "tao/IIOP_Endpoint.h"
00008 
00009 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
00010 
00011 #include "tao/IOP_IORC.h"
00012 #include "tao/debug.h"
00013 #include "tao/ORB_Core.h"
00014 
00015 #include "ace/Log_Msg.h"
00016 #include "ace/Guard_T.h"
00017 #include "ace/OS_NS_string.h"
00018 #include "ace/OS_NS_strings.h"
00019 
00020 ACE_RCSID (tao,
00021            IIOP_Endpoint,
00022            "IIOP_Endpoint.cpp,v 1.44 2006/04/27 14:22:45 mesnier_p Exp")
00023 
00024 #if !defined (__ACE_INLINE__)
00025 # include "tao/IIOP_Endpoint.i"
00026 #endif /* __ACE_INLINE__ */
00027 
00028 #include "ace/OS_NS_stdio.h"
00029 #include "ace/os_include/os_netdb.h"
00030 
00031 #include "ace/Vector_T.h"
00032 #include "ace/ACE.h"
00033 #include "ace/INET_Addr.h"
00034 #include "ace/Sock_Connect.h"
00035 
00036 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_END
00037 
00038 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00039 
00040 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_START
00041 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const ACE_INET_Addr &addr,
00042                                       int use_dotted_decimal_addresses)
00043   : TAO_Endpoint (IOP::TAG_INTERNET_IOP)
00044   , host_ ()
00045   , port_ (683) // default port (IANA assigned)
00046 #if defined (ACE_HAS_IPV6)
00047   , is_ipv6_decimal_ (false)
00048 #endif /* ACE_HAS_IPV6 */
00049   , is_encodable_ (true)
00050   , object_addr_set_ (false)
00051   , object_addr_ (addr)
00052   , preferred_path_ ()
00053   , next_ (0)
00054 {
00055   this->set (addr, use_dotted_decimal_addresses);
00056 }
00057 
00058 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host,
00059                                       CORBA::UShort port,
00060                                       const ACE_INET_Addr &addr,
00061                                       CORBA::Short priority)
00062   : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority)
00063   , host_ ()
00064   , port_ (port)
00065 #if defined (ACE_HAS_IPV6)
00066   , is_ipv6_decimal_ (false)
00067 #endif /* ACE_HAS_IPV6 */
00068   , is_encodable_ (true)
00069   , object_addr_set_ (false)
00070   , object_addr_ (addr)
00071   , preferred_path_ ()
00072   , next_ (0)
00073 {
00074   this->host(host); // With IPv6 performs check for decimal address
00075 }
00076 
00077 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (void)
00078   : TAO_Endpoint (IOP::TAG_INTERNET_IOP)
00079   , host_ ()
00080   , port_ (683)  // default port (IANA assigned)
00081 #if defined (ACE_HAS_IPV6)
00082   , is_ipv6_decimal_ (false)
00083 #endif /* ACE_HAS_IPV6 */
00084   , is_encodable_ (true)
00085   , object_addr_set_ (false)
00086   , object_addr_ ()
00087   , preferred_path_ ()
00088   , next_ (0)
00089 {
00090 }
00091 
00092 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const char *host,
00093                                       CORBA::UShort port,
00094                                       CORBA::Short priority)
00095   : TAO_Endpoint (IOP::TAG_INTERNET_IOP, priority)
00096   , host_ ()
00097   , port_ (port)
00098 #if defined (ACE_HAS_IPV6)
00099   , is_ipv6_decimal_ (false)
00100 #endif /* ACE_HAS_IPV6 */
00101   , is_encodable_ (true)
00102   , object_addr_set_ (false)
00103   , object_addr_ ()
00104   , preferred_path_ ()
00105   , next_ (0)
00106 {
00107   this->host(host); // With IPv6 performs check for decimal address
00108 }
00109 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_END
00110 
00111 
00112 TAO_IIOP_Endpoint &
00113 TAO_IIOP_Endpoint::operator= (const TAO_IIOP_Endpoint &other)
00114 {
00115   this->host_ = other.host_;
00116   this->port_ = other.port_;
00117 #if defined (ACE_HAS_IPV6)
00118   this->is_ipv6_decimal_ = other.is_ipv6_decimal_;
00119 #endif /* ACE_HAS_IPV6 */
00120   this->is_encodable_  = other.is_encodable_;
00121   this->object_addr_set_ = other.object_addr_set_;
00122   this->object_addr_ = other.object_addr_;
00123   this->preferred_path_ = other.preferred_path_;
00124   this->next_ = 0; // do not copy list membership, since we are only cloning the values
00125   return *this;
00126 }
00127 
00128 TAO_IIOP_Endpoint::~TAO_IIOP_Endpoint (void)
00129 {
00130 }
00131 
00132 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_START
00133 
00134 TAO_IIOP_Endpoint::TAO_IIOP_Endpoint (const TAO_IIOP_Endpoint &rhs)
00135   : TAO_Endpoint (rhs.tag_, rhs.priority_)
00136   , host_ (rhs.host_)
00137   , port_ (rhs.port_)
00138 #if defined (ACE_HAS_IPV6)
00139   , is_ipv6_decimal_ (rhs.is_ipv6_decimal_)
00140 #endif /* ACE_HAS_IPV6 */
00141   , is_encodable_ (rhs.is_encodable_)
00142   , object_addr_set_ (rhs.object_addr_set_)
00143   , object_addr_ (rhs.object_addr_)
00144   , preferred_path_  (rhs.preferred_path_)
00145   , next_ (0)
00146 {
00147 }
00148 
00149 int
00150 TAO_IIOP_Endpoint::set (const ACE_INET_Addr &addr,
00151                         int use_dotted_decimal_addresses)
00152 {
00153   char tmp_host[MAXHOSTNAMELEN + 1];
00154 
00155 #if defined (ACE_HAS_IPV6)
00156   this->is_ipv6_decimal_ = false; // Reset
00157 #endif /* ACE_HAS_IPV6 */
00158 
00159   if (use_dotted_decimal_addresses
00160       || addr.get_host_name (tmp_host, sizeof (tmp_host)) != 0)
00161     {
00162       if (use_dotted_decimal_addresses == 0 && TAO_debug_level > 5)
00163         {
00164           ACE_DEBUG ((LM_DEBUG,
00165                       ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ")
00166                       ACE_TEXT ("%p\n"),
00167                       ACE_TEXT ("cannot determine hostname")));
00168         }
00169 
00170       const char *tmp = addr.get_host_addr ();
00171       if (tmp == 0)
00172         {
00173           if (TAO_debug_level > 0)
00174             {
00175               ACE_ERROR ((LM_ERROR,
00176                           ACE_TEXT ("TAO (%P|%t) - IIOP_Endpoint::set, ")
00177                           ACE_TEXT ("%p\n"),
00178                           ACE_TEXT ("cannot determine hostname and hostaddr")));
00179             }
00180           return -1;
00181         }
00182       else
00183         {
00184           this->host_ = tmp;
00185 #if defined (ACE_HAS_IPV6)
00186           if (addr.get_type () == PF_INET6)
00187             this->is_ipv6_decimal_ = true;
00188 #endif /* ACE_HAS_IPV6 */
00189         }
00190     }
00191   else
00192     this->host_ = CORBA::string_dup (tmp_host);
00193 
00194   this->port_ = addr.get_port_number();
00195 
00196   return 0;
00197 }
00198 
00199 int
00200 TAO_IIOP_Endpoint::addr_to_string (char *buffer, size_t length)
00201 {
00202   size_t actual_len =
00203     ACE_OS::strlen (this->host_.in ()) // chars in host name
00204     + sizeof (':')                     // delimiter
00205     + ACE_OS::strlen ("65536")         // max port
00206     + sizeof ('\0');
00207 
00208 #if defined (ACE_HAS_IPV6)
00209   if (this->is_ipv6_decimal_)
00210     actual_len += 2; // '[' + ']'
00211 #endif /* ACE_HAS_IPV6 */
00212 
00213   if (length < actual_len)
00214     return -1;
00215 
00216 #if defined (ACE_HAS_IPV6)
00217   if (this->is_ipv6_decimal_)
00218     ACE_OS::sprintf (buffer, "[%s]:%d",
00219                      this->host_.in (), this->port_);
00220   else
00221 #endif /* ACE_HAS_IPV6 */
00222   ACE_OS::sprintf (buffer, "%s:%d",
00223                    this->host_.in (), this->port_);
00224 
00225   return 0;
00226 }
00227 
00228 const char *
00229 TAO_IIOP_Endpoint::host (const char *h)
00230 {
00231   this->host_ = h;
00232 #if defined (ACE_HAS_IPV6)
00233   if (ACE_OS::strchr (h, ':') != 0)
00234     this->is_ipv6_decimal_ = true;
00235 #endif /* ACE_HAS_IPV6 */
00236 
00237   return this->host_.in ();
00238 }
00239 
00240 TAO_Endpoint *
00241 TAO_IIOP_Endpoint::next (void)
00242 {
00243   return this->next_;
00244 }
00245 
00246 TAO_Endpoint *
00247 TAO_IIOP_Endpoint::next_filtered (TAO_ORB_Core * orb_core, TAO_Endpoint *root)
00248 {
00249   bool want_ipv6 = false;
00250   bool ipv6_only = false;
00251   bool prefer_ipv6 = false;
00252 #if defined (ACE_HAS_IPV6)
00253   want_ipv6 = true;
00254   ipv6_only = orb_core->orb_params()->connect_ipv6_only();
00255   prefer_ipv6 = orb_core->orb_params()->prefer_ipv6_interfaces();
00256 #else
00257   ACE_UNUSED_ARG (orb_core);
00258 #endif /* ACE_HAS_IPV6 */
00259   return
00260     this->next_filtered_i (static_cast<TAO_IIOP_Endpoint *>(root),
00261                            ipv6_only,
00262                            prefer_ipv6,
00263                            want_ipv6);
00264 }
00265 
00266 TAO_IIOP_Endpoint*
00267 TAO_IIOP_Endpoint::next_filtered_i (TAO_IIOP_Endpoint *root,
00268                                     bool ipv6_only,
00269                                     bool prefer_ipv6,
00270                                     bool want_ipv6)
00271 {
00272   // the candidate is nominally the next entry in the list, but since
00273   // the list may loop back on itself, the root of the list needs to be
00274   // initialized.
00275   TAO_IIOP_Endpoint *candidate = (root == 0) ? this : next_;
00276   if (root == 0)
00277     root = this;
00278 
00279 #if defined (ACE_HAS_IPV6)
00280   if (ipv6_only)
00281     {
00282       if (candidate == 0 || candidate->is_ipv6_decimal())
00283         return candidate;
00284       const ACE_INET_Addr &addr = candidate->object_addr ();
00285       bool allowed = addr.get_type () == AF_INET6 &&
00286         !addr.is_ipv4_mapped_ipv6();
00287 
00288       return allowed ? candidate :
00289         candidate->next_filtered_i(root, ipv6_only, prefer_ipv6, true);
00290     }
00291   if (prefer_ipv6)
00292     {
00293       if (candidate == 0)
00294         return !want_ipv6 ? candidate :
00295           root->next_filtered_i(root, ipv6_only, prefer_ipv6, false);
00296 
00297       if (want_ipv6 == candidate->is_ipv6_decimal())
00298         return candidate;
00299 
00300       const ACE_INET_Addr &addr = candidate->object_addr ();
00301       bool really_ipv6 = addr.get_type () == AF_INET6 &&
00302                          !addr.is_ipv4_mapped_ipv6();
00303       return (want_ipv6 == really_ipv6) ? candidate :
00304         candidate->next_filtered_i(root, ipv6_only, prefer_ipv6, want_ipv6);
00305     }
00306 #else
00307   ACE_UNUSED_ARG (want_ipv6);
00308   ACE_UNUSED_ARG (ipv6_only);
00309   ACE_UNUSED_ARG (prefer_ipv6);
00310 #endif
00311 
00312   return candidate;
00313 }
00314 
00315 TAO_Endpoint *
00316 TAO_IIOP_Endpoint::duplicate (void)
00317 {
00318   TAO_IIOP_Endpoint *endpoint = 0;
00319 
00320   // @@ NOTE: Not exception safe..
00321   ACE_NEW_RETURN (endpoint, TAO_IIOP_Endpoint (*this), 0);
00322 
00323   return endpoint;
00324 }
00325 
00326 const ACE_INET_Addr &
00327 TAO_IIOP_Endpoint::object_addr (void) const
00328 {
00329   // The object_addr_ is initialized here, rather than at IOR decode
00330   // time for several reasons:
00331   //   1. A request on the object may never be invoked.
00332   //   2. The DNS setup may have changed dynamically.
00333   //   ...etc..
00334 
00335   // Double checked locking optimization.
00336   if (!this->object_addr_set_)
00337     {
00338       ACE_GUARD_RETURN (TAO_SYNCH_MUTEX,
00339                         guard,
00340                         this->addr_lookup_lock_,
00341                         this->object_addr_);
00342 
00343       if (!this->object_addr_set_)
00344         {
00345           (void) this->object_addr_i ();
00346         }
00347     }
00348 
00349   return this->object_addr_;
00350 }
00351 
00352 void
00353 TAO_IIOP_Endpoint::object_addr_i (void) const
00354 {
00355   // We should have already held the lock
00356 
00357 #if defined (ACE_HAS_IPV6)
00358   bool is_ipv4_decimal_ = false;
00359   if (!this->is_ipv6_decimal_)
00360     is_ipv4_decimal_ =
00361       ACE_OS::strspn (this->host_.in (), ".0123456789") ==
00362                               ACE_OS::strlen (this->host_.in ());
00363 
00364   // If this is *not* an IPv4 decimal address at first try to
00365   // resolve the address as an IPv6 address; if that fails
00366   // (or it's an IPv4 address) and the address is *not* an IPv6
00367   // decimal address try to resolve it as an IPv4 address.
00368   if ((is_ipv4_decimal_ ||
00369         this->object_addr_.set (this->port_,
00370                                 this->host_.in (),
00371                                 1,
00372                                 AF_INET6) == -1) &&
00373       (this->is_ipv6_decimal_ ||
00374         this->object_addr_.set (this->port_,
00375                               this->host_.in (),
00376                               1,
00377                               AF_INET) == -1))
00378 #else
00379   if (this->object_addr_.set (this->port_,
00380                               this->host_.in ()) == -1)
00381 #endif
00382     {
00383       // If this call fails, it most likely due a hostname
00384       // lookup failure caused by a DNS misconfiguration.  If
00385       // a request is made to the object at the given host and
00386       // port, then a CORBA::TRANSIENT() exception should be
00387       // thrown.
00388 
00389       // Invalidate the ACE_INET_Addr.  This is used as a flag
00390       // to denote that ACE_INET_Addr initialization failed.
00391       this->object_addr_.set_type (-1);
00392     }
00393   else
00394     {
00395       this->object_addr_set_ = true;
00396     }
00397 }
00398 
00399 static ACE_CString find_local(const ACE_Vector<ACE_CString>& local_ips,
00400                               const ACE_CString& pattern)
00401 {
00402   for (size_t i = 0; i < local_ips.size(); ++i)
00403   {
00404     ACE_CString ret = local_ips[i];
00405     if (ACE::wild_match(ret.c_str(), pattern.c_str()))
00406       return ret;
00407   }
00408   return "";
00409 }
00410 
00411 TAO_IIOP_Endpoint*
00412 TAO_IIOP_Endpoint::add_local_endpoint(TAO_IIOP_Endpoint* ep, const char* local)
00413 {
00414   TAO_Endpoint* tmp = ep->duplicate();
00415   ep->next_ = static_cast<TAO_IIOP_Endpoint*>(tmp);
00416   ep->next_->is_encodable_ = true;
00417   ep->next_->preferred_path_.host = CORBA::string_dup(local);
00418   return ep->next_;
00419 }
00420 
00421 static void
00422 get_ip_interfaces(ACE_Vector<ACE_CString>& local_ips)
00423 {
00424   ACE_INET_Addr* tmp = 0;
00425   size_t cnt = 0;
00426   int err = ACE::get_ip_interfaces (cnt, tmp);
00427   if (err != 0)
00428     return;
00429 #if defined (ACE_HAS_IPV6)
00430   char buf[64];
00431 #else /* ACE_HAS_IPV6 */
00432   char buf[32];
00433 #endif /* !ACE_HAS_IPV6 */
00434   for (size_t i = 0; i < cnt; ++i)
00435   {
00436     const char *s_if = tmp[i].get_host_addr(buf, sizeof (buf));
00437     ACE_ASSERT(s_if != 0);
00438     ACE_CString tmp(s_if);
00439     //ssize_t pos = tmp.find(':');
00440     //if (pos != ACE_CString::npos)
00441     //  tmp = tmp.substr(0, pos);
00442     local_ips.push_back(tmp);
00443   }
00444   delete[] tmp;
00445 }
00446 
00447 // Given a comma separated list of preferred interface directives, which
00448 // are of the form <wild_remote>=<wild_local>, this function will retrieve
00449 // the list of preferred local ip addresses by matching wild_local against
00450 // the list of all local ip interfaces, for any directive where wild_remote
00451 // matches the host from our endpoint.
00452 static void find_preferred_interfaces (const ACE_CString& host,
00453                                        const ACE_CString& csvPreferred,
00454                                        ACE_Vector<ACE_CString>& preferred)
00455 {
00456   ACE_Vector<ACE_CString> local_ips;
00457   get_ip_interfaces(local_ips);
00458   if (local_ips.size() == 0)
00459     return;
00460 
00461   // The outer loop steps through each preferred interface directive
00462   // and chains a new endpoint if the remote interface matches the
00463   // current endpoint.
00464   size_t index = 0;
00465   while (index < csvPreferred.length())
00466   {
00467     ssize_t comma = csvPreferred.find(',', index);
00468     ssize_t assign = csvPreferred.find('=', index);
00469 
00470     if (assign == ACE_CString::npos)
00471     {
00472       assign = csvPreferred.find(':', index);
00473       if (assign == ACE_CString::npos)
00474       {
00475         ACE_ASSERT(assign != ACE_CString::npos);
00476         return;
00477       }
00478     }
00479 
00480     ACE_CString wild_local;
00481     if (comma == ACE_CString::npos)
00482       wild_local = csvPreferred.substr(assign + 1);
00483     else
00484       wild_local = csvPreferred.substr(assign + 1, comma - assign - 1);
00485     ACE_CString wild_remote = csvPreferred.substr(index, assign - index);
00486 
00487     index = static_cast<size_t>(comma) + 1;
00488 
00489     // For now, we just try to match against the host literally. In
00490     // the future it might be worthwhile to resolve some aliases for
00491     // this->host_ using DNS (and possibly reverse DNS) lookups. Then we
00492     // could try matching against those too.
00493     if (ACE::wild_match(host.c_str(), wild_remote.c_str(), false))
00494     {
00495       // If it's a match, then it means we need to use a
00496       // local interface that matches wild_local.
00497       ACE_CString local = find_local(local_ips, wild_local);
00498       if (local.length() > 0)
00499       {
00500         preferred.push_back(local);
00501       }
00502       else
00503       {
00504         // There is no matching local interface, so we can skip
00505         // to the next preferred interface directive.
00506       }
00507     }
00508     else
00509     {
00510       // The preferred interface directive is for a different
00511       // remote endpoint.
00512     }
00513     if (comma == ACE_CString::npos)
00514       break;
00515   }
00516 }
00517 
00518 CORBA::ULong
00519 TAO_IIOP_Endpoint::preferred_interfaces (const char* csv, bool enforce)
00520 {
00521   ACE_Vector<ACE_CString> preferred;
00522   find_preferred_interfaces(this->host_.in(), csv, preferred);
00523   CORBA::ULong count = preferred.size();
00524   if (count > 0)
00525   {
00526     this->is_encodable_ = true;
00527     this->preferred_path_.host = CORBA::string_dup(preferred[0].c_str());
00528     TAO_IIOP_Endpoint* ep = this;
00529     for (size_t i = 1; i < count; ++i)
00530     {
00531       ep = add_local_endpoint(ep, preferred[i].c_str());
00532     }
00533 
00534     // If we're not enforcing the preferred interfaces, then we can just add
00535     // a new non-preferred endpoint to the end with a default local addr.
00536     if (! enforce)
00537     {
00538       ep = add_local_endpoint(ep, "");
00539     }
00540     else
00541     {
00542       --count;
00543     }
00544   }
00545   return count;
00546 }
00547 
00548 CORBA::Boolean
00549 TAO_IIOP_Endpoint::is_equivalent (const TAO_Endpoint *other_endpoint)
00550 {
00551   const TAO_IIOP_Endpoint *endpoint =
00552     dynamic_cast<const TAO_IIOP_Endpoint *> (other_endpoint);
00553 
00554   if (endpoint == 0)
00555     return 0;
00556 
00557   return (this->port_ == endpoint->port_
00558           && (ACE_OS::strcmp (this->host (), endpoint->host ()) == 0));
00559 }
00560 
00561 CORBA::ULong
00562 TAO_IIOP_Endpoint::hash (void)
00563 {
00564   if (this->hash_val_ != 0)
00565     return this->hash_val_;
00566 
00567   {
00568     ACE_GUARD_RETURN (TAO_SYNCH_MUTEX,
00569                       guard,
00570                       this->addr_lookup_lock_,
00571                       this->hash_val_);
00572     // .. DCL
00573     if (this->hash_val_ != 0)
00574       return this->hash_val_;
00575 
00576     // A few comments about this optimization. The call below will
00577     // deadlock if the object_addr_set is false. If you don't belive
00578 
00579     if (!this->object_addr_set_)
00580       {
00581         // Set the object_addr first
00582         (void) this->object_addr_i ();
00583       }
00584 
00585     this->hash_val_ = this->object_addr_.hash ();
00586   }
00587 
00588   return this->hash_val_;
00589 }
00590 
00591 bool
00592 TAO_IIOP_Endpoint::is_preferred_network (void) const
00593 {
00594   return (this->preferred_path_.host.in () != 0 &&
00595           this->preferred_path_.host.in ()[0] != 0);
00596 }
00597 
00598 const char *
00599 TAO_IIOP_Endpoint::preferred_network (void) const
00600 {
00601   return this->preferred_path_.host.in ();
00602 }
00603 
00604 //@@ TAO_ENDPOINT_SPL_COPY_HOOK_END
00605 
00606 TAO_END_VERSIONED_NAMESPACE_DECL
00607 
00608 #endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */

Generated on Thu Nov 9 11:54:13 2006 for TAO by doxygen 1.3.6