DIOP_Profile.cpp

Go to the documentation of this file.
00001 // $Id: DIOP_Profile.cpp 78867 2007-07-13 03:29:33Z johnnyw $
00002 
00003 #include "tao/Strategies/DIOP_Profile.h"
00004 
00005 #if defined (TAO_HAS_DIOP) && (TAO_HAS_DIOP != 0)
00006 
00007 #include "tao/CDR.h"
00008 #include "tao/SystemException.h"
00009 #include "tao/ORB.h"
00010 #include "tao/ORB_Core.h"
00011 #include "tao/debug.h"
00012 #include "tao/IIOP_EndpointsC.h"
00013 
00014 #include "ace/OS_NS_stdio.h"
00015 #include "ace/OS_NS_string.h"
00016 #include "ace/os_include/os_netdb.h"
00017 
00018 ACE_RCSID (Strategies,
00019            DIOP_Profile,
00020            "$Id: DIOP_Profile.cpp 78867 2007-07-13 03:29:33Z johnnyw $")
00021 
00022 static const char the_prefix[] = "diop";
00023 
00024 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00025 
00026 const char TAO_DIOP_Profile::object_key_delimiter_ = '/';
00027 
00028 char
00029 TAO_DIOP_Profile::object_key_delimiter (void) const
00030 {
00031   return TAO_DIOP_Profile::object_key_delimiter_;
00032 }
00033 
00034 
00035 TAO_DIOP_Profile::TAO_DIOP_Profile (const ACE_INET_Addr &addr,
00036                                     const TAO::ObjectKey &object_key,
00037                                     const TAO_GIOP_Message_Version &version,
00038                                     TAO_ORB_Core *orb_core)
00039   : TAO_Profile (TAO_TAG_DIOP_PROFILE,
00040                  orb_core,
00041                  object_key,
00042                  version),
00043     endpoint_ (addr,
00044                orb_core->orb_params ()->use_dotted_decimal_addresses ()),
00045     count_ (1)
00046 {
00047 }
00048 
00049 TAO_DIOP_Profile::TAO_DIOP_Profile (const char* host,
00050                                     CORBA::UShort port,
00051                                     const TAO::ObjectKey &object_key,
00052                                     const ACE_INET_Addr &addr,
00053                                     const TAO_GIOP_Message_Version &version,
00054                                     TAO_ORB_Core *orb_core)
00055   : TAO_Profile (TAO_TAG_DIOP_PROFILE,
00056                  orb_core,
00057                  object_key,
00058                  version),
00059     endpoint_ (host, port, addr),
00060     count_ (1)
00061 {
00062 }
00063 
00064 TAO_DIOP_Profile::TAO_DIOP_Profile (TAO_ORB_Core *orb_core)
00065   : TAO_Profile (TAO_TAG_DIOP_PROFILE,
00066                  orb_core,
00067                  TAO_GIOP_Message_Version (TAO_DEF_GIOP_MAJOR, TAO_DEF_GIOP_MINOR)),
00068     endpoint_ (),
00069     count_ (1)
00070 {
00071 }
00072 
00073 TAO_DIOP_Profile::~TAO_DIOP_Profile (void)
00074 {
00075   // Clean up the list of endpoints since we own it.
00076   // Skip the head, since it is not dynamically allocated.
00077   TAO_Endpoint *tmp = 0;
00078 
00079   for (TAO_Endpoint *next = this->endpoint ()->next ();
00080        next != 0;
00081        next = tmp)
00082     {
00083       tmp = next->next ();
00084       delete next;
00085     }
00086 }
00087 
00088 // return codes:
00089 // -1 -> error
00090 //  0 -> can't understand this version
00091 //  1 -> success.
00092 
00093 int
00094 TAO_DIOP_Profile::decode_profile (TAO_InputCDR& cdr)
00095 {
00096   // @@ NOTE: This code is repeated thrice. Need to factor out in a
00097   // better manner.
00098   // Decode host and port into the <endpoint_>.
00099   if (cdr.read_string (this->endpoint_.host_.out ()) == 0
00100       || cdr.read_ushort (this->endpoint_.port_) == 0)
00101     {
00102       if (TAO_debug_level > 0)
00103         ACE_DEBUG ((LM_DEBUG,
00104                     ACE_TEXT ("TAO (%P|%t) - DIOP_Profile::decode_profile, ")
00105                     ACE_TEXT ("error while decoding host/port\n")));
00106       return -1;
00107     }
00108 
00109   if (cdr.good_bit ())
00110     {
00111       // Invalidate the object_addr_ until first access.
00112       this->endpoint_.object_addr_.set_type (-1);
00113 
00114       return 1;
00115     }
00116 
00117   return -1;
00118 }
00119 
00120 void
00121 TAO_DIOP_Profile::parse_string_i (const char *ior)
00122 {
00123   // Pull off the "hostname:port/" part of the objref
00124   // Copy the string because we are going to modify it...
00125   const char *okd =
00126     ACE_OS::strchr (ior, this->object_key_delimiter_);
00127 
00128   if (okd == 0 || okd == ior)
00129     {
00130       // No object key delimiter or no hostname specified.
00131       throw ::CORBA::INV_OBJREF (
00132                    CORBA::SystemException::_tao_minor_code (
00133                      TAO::VMCID,
00134                      EINVAL),
00135                    CORBA::COMPLETED_NO);
00136     }
00137 
00138   // Length of host string.
00139   CORBA::ULong length_host = 0;
00140 
00141   const char *cp_pos = ACE_OS::strchr (ior, ':');  // Look for a port
00142 #if defined (ACE_HAS_IPV6)
00143   // IPv6 numeric address in host string?
00144   bool ipv6_in_host = false;
00145 
00146   // Check if this is a (possibly) IPv6 supporting profile containing a
00147   // decimal IPv6 address representation.
00148   if ((this->version ().major > TAO_MIN_IPV6_IIOP_MAJOR ||
00149        this->version ().minor >= TAO_MIN_IPV6_IIOP_MINOR) &&
00150       ior[0] == '[')
00151     {
00152       // In this case we have to find the end of the numeric address and
00153       // start looking for the port separator from there.
00154       const char *cp_pos_a = ACE_OS::strchr (ior, ']');
00155       if (cp_pos_a == 0)
00156         {
00157           // No valid IPv6 address specified.
00158           if (TAO_debug_level > 0)
00159             {
00160               ACE_DEBUG ((LM_ERROR,
00161                           ACE_TEXT ("\nTAO (%P|%t) - DIOP_Profile::parse_string_i, ")
00162                           ACE_TEXT ("invalid IPv6 decimal address specified.\n")));
00163             }
00164 
00165           throw ::CORBA::INV_OBJREF (
00166                          CORBA::SystemException::_tao_minor_code (
00167                                                                   0,
00168                                                                   EINVAL),
00169                          CORBA::COMPLETED_NO);
00170         }
00171       else
00172         {
00173           if (cp_pos_a[1] == ':')    // Look for a port
00174             cp_pos = cp_pos_a + 1;
00175           else
00176             cp_pos = 0;
00177           ipv6_in_host = true; // host string contains full IPv6 numeric address
00178         }
00179     }
00180 #endif /* ACE_HAS_IPV6 */
00181 
00182   if (cp_pos == ior)
00183     {
00184       // No hostname specified!  It is required by the spec.
00185       throw ::CORBA::INV_OBJREF (
00186                    CORBA::SystemException::_tao_minor_code (
00187                      TAO::VMCID,
00188                      EINVAL),
00189                    CORBA::COMPLETED_NO);
00190     }
00191   else if (cp_pos != 0)
00192     {
00193       // A port number or port name was specified.
00194       CORBA::ULong length_port = okd - cp_pos - 1;
00195 
00196       CORBA::String_var tmp = CORBA::string_alloc (length_port);
00197 
00198       ACE_OS::strncpy (tmp.inout (), cp_pos + 1, length_port);
00199       tmp[length_port] = '\0';
00200 
00201       if (ACE_OS::strspn (tmp.in (), "1234567890") == length_port)
00202         {
00203           this->endpoint_.port_ =
00204             static_cast<CORBA::UShort> (ACE_OS::atoi (tmp.in ()));
00205         }
00206       else
00207         {
00208           ACE_INET_Addr ia;
00209           if (ia.string_to_addr (tmp.in ()) == -1)
00210             {
00211               throw ::CORBA::INV_OBJREF (
00212                              CORBA::SystemException::_tao_minor_code (
00213                                0,
00214                                EINVAL),
00215                              CORBA::COMPLETED_NO);
00216             }
00217           else
00218             {
00219               this->endpoint_.port_ = ia.get_port_number ();
00220             }
00221         }
00222 
00223       length_host = cp_pos - ior;
00224     }
00225   else
00226     length_host = okd - ior;
00227 
00228 #if defined (ACE_HAS_IPV6)
00229   if (ipv6_in_host)
00230     length_host -= 2; // don't store '[' and ']'
00231 #endif /* ACE_HAS_IPV6 */
00232 
00233   CORBA::String_var tmp = CORBA::string_alloc (length_host);
00234 
00235 #if defined (ACE_HAS_IPV6)
00236   if (ipv6_in_host)
00237     ACE_OS::strncpy (tmp.inout (), ior + 1, length_host);
00238   else
00239 #endif /* ACE_HAS_IPV6 */
00240   // Skip the trailing '/'
00241   ACE_OS::strncpy (tmp.inout (), ior, length_host);
00242   tmp[length_host] = '\0';
00243 
00244   this->endpoint_.host_ = tmp._retn ();
00245 #if defined (ACE_HAS_IPV6)
00246   this->endpoint_.is_ipv6_decimal_ = ipv6_in_host;
00247 #endif /* ACE_HAS_IPV6 */
00248 
00249   if (ACE_OS::strcmp (this->endpoint_.host_.in (), "") == 0)
00250     {
00251       ACE_INET_Addr host_addr;
00252 
00253       char tmp_host [MAXHOSTNAMELEN + 1];
00254 
00255       // If no host is specified: assign the default host, i.e. the
00256       // local host.
00257       if (host_addr.get_host_name (tmp_host,
00258                                    sizeof (tmp_host)) != 0)
00259         {
00260           // Can't get the IP address since the INET_Addr wasn't
00261           // initialized.  Just throw an exception.
00262 
00263           if (TAO_debug_level > 0)
00264             ACE_DEBUG ((LM_DEBUG,
00265                         ACE_TEXT ("TAO (%P|%t) - ")
00266                         ACE_TEXT ("DIOP_Profile::parse_string_i, ")
00267                         ACE_TEXT ("%p\n\n"),
00268                         ACE_TEXT ("cannot determine hostname")));
00269 
00270           // @@ What's the right exception to throw here?
00271           throw ::CORBA::INV_OBJREF (
00272                        CORBA::SystemException::_tao_minor_code (
00273                          TAO::VMCID,
00274                          EINVAL),
00275                        CORBA::COMPLETED_NO);
00276         }
00277       else
00278         this->endpoint_.host_ = CORBA::string_dup (tmp_host);
00279     }
00280 
00281   TAO::ObjectKey ok;
00282   TAO::ObjectKey::decode_string_to_sequence (ok,
00283                                              okd + 1);
00284 
00285   (void) this->orb_core ()->object_key_table ().bind (ok,
00286                                                       this->ref_object_key_);
00287 }
00288 
00289 CORBA::Boolean
00290 TAO_DIOP_Profile::do_is_equivalent (const TAO_Profile *other_profile)
00291 {
00292   const TAO_DIOP_Profile *op =
00293     dynamic_cast<const TAO_DIOP_Profile *> (other_profile);
00294 
00295   // Make sure we have a TAO_DIOP_Profile.
00296   if (op == 0)
00297     return 0;
00298 
00299   // Check endpoints equivalence.
00300   const TAO_DIOP_Endpoint *other_endp = &op->endpoint_;
00301   for (TAO_DIOP_Endpoint *endp = &this->endpoint_;
00302        endp != 0;
00303        endp = endp->next_)
00304     {
00305       if (endp->is_equivalent (other_endp))
00306         other_endp = other_endp->next_;
00307       else
00308         return false;
00309     }
00310 
00311   return true;
00312 }
00313 
00314 CORBA::ULong
00315 TAO_DIOP_Profile::hash (CORBA::ULong max)
00316 {
00317   // Get the hashvalue for all endpoints.
00318   CORBA::ULong hashval = 0;
00319   for (TAO_DIOP_Endpoint *endp = &this->endpoint_;
00320        endp != 0;
00321        endp = endp->next_)
00322     {
00323       hashval += endp->hash ();
00324     }
00325 
00326   hashval += this->version_.minor;
00327   hashval += this->tag ();
00328 
00329   const TAO::ObjectKey &ok =
00330     this->ref_object_key_->object_key ();
00331 
00332   if (ok.length () >= 4)
00333     {
00334       hashval += ok[1];
00335       hashval += ok[3];
00336     }
00337 
00338   hashval += this->hash_service_i (max);
00339 
00340   return hashval % max;
00341 }
00342 
00343 TAO_Endpoint*
00344 TAO_DIOP_Profile::endpoint (void)
00345 {
00346   return &this->endpoint_;
00347 }
00348 
00349 CORBA::ULong
00350 TAO_DIOP_Profile::endpoint_count (void) const
00351 {
00352   return this->count_;
00353 }
00354 
00355 void
00356 TAO_DIOP_Profile::add_endpoint (TAO_DIOP_Endpoint *endp)
00357 {
00358   endp->next_ = this->endpoint_.next_;
00359   this->endpoint_.next_ = endp;
00360 
00361   this->count_++;
00362 }
00363 
00364 char *
00365 TAO_DIOP_Profile::to_string (void)
00366 {
00367   // corbaloc:diop:1.2@host:port,diop:1.2@host:port,.../key
00368 
00369   CORBA::String_var key;
00370   TAO::ObjectKey::encode_sequence_to_string (key.inout (),
00371                                              this->ref_object_key_->object_key ());
00372 
00373   size_t buflen = (
00374        8 /* "corbaloc" */ +
00375        1 /* colon separator */ +
00376        1 /* object key separator */ +
00377        ACE_OS::strlen (key.in ()));
00378   size_t pfx_len = (
00379        ACE_OS::strlen (::the_prefix) /* "diop" */ +
00380        1 /* colon separator */);
00381 
00382  const TAO_DIOP_Endpoint *endp = 0;
00383  for (endp = &this->endpoint_; endp != 0; endp = endp->next_)
00384    {
00385       buflen += (
00386           pfx_len +
00387           1 /* major version */ +
00388           1 /* decimal point */ +
00389           1 /* minor version */ +
00390           1 /* `@' character */ +
00391           ACE_OS::strlen (endp->host ()) +
00392           1 /* colon separator */ +
00393           5 /* port number */ +
00394           1 /* comma */);
00395 #if defined (ACE_HAS_IPV6)
00396       if (endp->is_ipv6_decimal_)
00397         buflen += 2; // room for '[' and ']'
00398 #endif /* ACE_HAS_IPV6 */
00399    }
00400 
00401   static const char digits [] = "0123456789";
00402 
00403   char * buf = CORBA::string_alloc (static_cast<CORBA::ULong> (buflen));
00404 
00405   ACE_OS::strcpy (buf, "corbaloc:");
00406 
00407   for (endp = &this->endpoint_; endp != 0; endp = endp->next_)
00408     {
00409       if (&this->endpoint_ != endp)
00410       ACE_OS::strcat (buf, ",");
00411 
00412 #if defined (ACE_HAS_IPV6)
00413       if (endp->is_ipv6_decimal_)
00414         {
00415           // Don't publish scopeid if included.
00416           ACE_CString tmp (endp->host ());
00417           ACE_CString::size_type pos = tmp.find ('%');
00418           if (pos != ACE_CString::npos)
00419             {
00420               tmp = tmp.substr (0, pos + 1);
00421               tmp[pos] = '\0';
00422             }
00423           ACE_OS::sprintf (buf + ACE_OS::strlen (buf),
00424                   "%s:%c.%c@[%s]:%d",
00425                   ::the_prefix,
00426                   digits [this->version_.major],
00427                   digits [this->version_.minor],
00428                   tmp.c_str (),
00429                   endp->port ());
00430         }
00431       else
00432 #endif
00433       ACE_OS::sprintf (buf + ACE_OS::strlen (buf),
00434               "%s:%c.%c@%s:%d",
00435               ::the_prefix,
00436               digits [this->version_.major],
00437               digits [this->version_.minor],
00438               endp->host (),
00439               endp->port ());
00440 
00441   }
00442   ACE_OS::sprintf (buf + ACE_OS::strlen (buf),
00443                    "%c%s",
00444                    this->object_key_delimiter_,
00445                    key.in ());
00446 
00447   return buf;
00448 }
00449 
00450 const char *
00451 TAO_DIOP_Profile::prefix (void)
00452 {
00453   return ::the_prefix;
00454 }
00455 
00456 void
00457 TAO_DIOP_Profile::create_profile_body (TAO_OutputCDR &encap) const
00458 {
00459   encap.write_octet (TAO_ENCAP_BYTE_ORDER);
00460 
00461   // The GIOP version
00462   encap.write_octet (this->version_.major);
00463   encap.write_octet (this->version_.minor);
00464 
00465   // STRING hostname from profile
00466 #if defined (ACE_HAS_IPV6)
00467   // For IPv6 decimal addresses make sure the possibly included scopeid
00468   // is not published as this has only local meaning.
00469   const char* host;
00470   const char* pos;
00471   if (this->endpoint_.is_ipv6_decimal_ &&
00472       (pos = ACE_OS::strchr (host = this->endpoint_.host (), '%')) != 0)
00473     {
00474       ACE_CString tmp;
00475       size_t len = pos - host;
00476       tmp.set (this->endpoint_.host (), len, 1);
00477       encap.write_string (tmp.c_str ());
00478     }
00479   else
00480 #endif /* ACE_HAS_IPV6 */
00481   encap.write_string (this->endpoint_.host ());
00482 
00483   // UNSIGNED SHORT port number
00484   encap.write_ushort (this->endpoint_.port ());
00485 
00486   // OCTET SEQUENCE for object key
00487   if (this->ref_object_key_)
00488     encap << this->ref_object_key_->object_key ();
00489   else
00490     {
00491       ACE_ERROR ((LM_ERROR,
00492                   "TAO (%P|%t) - DIOP_Profile::create_profile_body, "
00493                   "no object key marshalled\n"));
00494     }
00495 
00496   if (this->version_.major > 1
00497       || this->version_.minor > 0)
00498     this->tagged_components ().encode (encap);
00499 }
00500 
00501 int
00502 TAO_DIOP_Profile::encode_endpoints (void)
00503 {
00504   // Create a data structure and fill it with endpoint info for wire
00505   // transfer.
00506   // We include information for the head of the list
00507   // together with other endpoints because even though its addressing
00508   // info is transmitted using standard ProfileBody components, its
00509   // priority is not!
00510 
00511   TAO::IIOPEndpointSequence endpoints;
00512   endpoints.length (this->count_);
00513 
00514   const TAO_DIOP_Endpoint *endpoint = &this->endpoint_;
00515   for (CORBA::ULong i = 0;
00516        i < this->count_;
00517        ++i)
00518     {
00519 #if defined (ACE_HAS_IPV6)
00520       if (endpoint->is_ipv6_decimal_)
00521         {
00522           // Don't publish scopeid if included.
00523           ACE_CString tmp (endpoint->host ());
00524           ACE_CString::size_type pos = tmp.find ('%');
00525           if (pos != ACE_CString::npos)
00526             {
00527               tmp = tmp.substr (0, pos + 1);
00528               tmp[pos] = '\0';
00529               endpoints[i].host = tmp.c_str ();
00530             }
00531           else
00532             endpoints[i].host = tmp.c_str ();
00533         }
00534       else
00535 #endif /* ACE_HAS_IPV6 */
00536       endpoints[i].host = endpoint->host ();
00537       endpoints[i].port = endpoint->port ();
00538       endpoints[i].priority = endpoint->priority ();
00539 
00540       endpoint = endpoint->next_;
00541     }
00542 
00543   // Encode the data structure.
00544   TAO_OutputCDR out_cdr;
00545   if ((out_cdr << ACE_OutputCDR::from_boolean (TAO_ENCAP_BYTE_ORDER)
00546        == 0)
00547       || (out_cdr << endpoints) == 0)
00548     return -1;
00549 
00550   this->set_tagged_components (out_cdr);
00551 
00552   return  0;
00553 }
00554 
00555 int
00556 TAO_DIOP_Profile::decode_endpoints (void)
00557 {
00558   IOP::TaggedComponent tagged_component;
00559   tagged_component.tag = TAO_TAG_ENDPOINTS;
00560 
00561   if (this->tagged_components_.get_component (tagged_component))
00562     {
00563       const CORBA::Octet *buf =
00564         tagged_component.component_data.get_buffer ();
00565 
00566       TAO_InputCDR in_cdr (reinterpret_cast<const char*> (buf),
00567                            tagged_component.component_data.length ());
00568 
00569       // Extract the Byte Order.
00570       CORBA::Boolean byte_order;
00571       if ((in_cdr >> ACE_InputCDR::to_boolean (byte_order)) == 0)
00572         return -1;
00573       in_cdr.reset_byte_order (static_cast<int> (byte_order));
00574 
00575       // Extract endpoints sequence.
00576       TAO::IIOPEndpointSequence endpoints;
00577 
00578       if (! (in_cdr >> endpoints))
00579         return -1;
00580 
00581       // Get the priority of the first endpoint (head of the list.
00582       // It's other data is extracted as part of the standard profile
00583       // decoding.
00584       this->endpoint_.priority (endpoints[0].priority);
00585 
00586       // Use information extracted from the tagged component to
00587       // populate the profile.  Skip the first endpoint, since it is
00588       // always extracted through standard profile body.  Also, begin
00589       // from the end of the sequence to preserve endpoint order,
00590       // since <add_endpoint> method reverses the order of endpoints
00591       // in the list.
00592       for (CORBA::ULong i = endpoints.length () - 1;
00593            i > 0;
00594            --i)
00595         {
00596           TAO_DIOP_Endpoint *endpoint = 0;
00597           ACE_NEW_RETURN (endpoint,
00598                           TAO_DIOP_Endpoint (endpoints[i].host,
00599                                              endpoints[i].port,
00600                                              endpoints[i].priority),
00601                           -1);
00602 
00603           this->add_endpoint (endpoint);
00604         }
00605     }
00606 
00607   return 0;
00608 }
00609 
00610 TAO_END_VERSIONED_NAMESPACE_DECL
00611 
00612 #endif /* TAO_HAS_DIOP && TAO_HAS_DIOP != 0 */

Generated on Tue Feb 2 17:47:18 2010 for TAO_Strategies by  doxygen 1.4.7