Merge pull request #2317 from jwillemsen/jwi-deleteop
[ACE_TAO.git] / TAO / tao / Strategies / DIOP_Profile.cpp
blob7bb6c2e3cd48015ceee5310082635822b1e7c50d
1 #include "tao/Strategies/DIOP_Profile.h"
3 #if defined (TAO_HAS_DIOP) && (TAO_HAS_DIOP != 0)
5 #include "tao/CDR.h"
6 #include "tao/SystemException.h"
7 #include "tao/ORB.h"
8 #include "tao/ORB_Core.h"
9 #include "tao/debug.h"
10 #include "tao/IIOP_EndpointsC.h"
12 #include "ace/OS_NS_stdio.h"
13 #include "ace/OS_NS_string.h"
14 #include "ace/os_include/os_netdb.h"
15 #include "ace/Truncate.h"
16 #include <cstring>
18 static const char the_prefix[] = "diop";
20 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
22 const char TAO_DIOP_Profile::object_key_delimiter_ = '/';
24 char
25 TAO_DIOP_Profile::object_key_delimiter () const
27 return TAO_DIOP_Profile::object_key_delimiter_;
31 TAO_DIOP_Profile::TAO_DIOP_Profile (const ACE_INET_Addr &addr,
32 const TAO::ObjectKey &object_key,
33 const TAO_GIOP_Message_Version &version,
34 TAO_ORB_Core *orb_core)
35 : TAO_Profile (TAO_TAG_DIOP_PROFILE,
36 orb_core,
37 object_key,
38 version),
39 endpoint_ (addr,
40 orb_core->orb_params ()->use_dotted_decimal_addresses ()),
41 count_ (1)
45 TAO_DIOP_Profile::TAO_DIOP_Profile (const char* host,
46 CORBA::UShort port,
47 const TAO::ObjectKey &object_key,
48 const ACE_INET_Addr &addr,
49 const TAO_GIOP_Message_Version &version,
50 TAO_ORB_Core *orb_core)
51 : TAO_Profile (TAO_TAG_DIOP_PROFILE,
52 orb_core,
53 object_key,
54 version),
55 endpoint_ (host, port, addr),
56 count_ (1)
60 TAO_DIOP_Profile::TAO_DIOP_Profile (TAO_ORB_Core *orb_core)
61 : TAO_Profile (TAO_TAG_DIOP_PROFILE,
62 orb_core,
63 TAO_GIOP_Message_Version (TAO_DEF_GIOP_MAJOR, TAO_DEF_GIOP_MINOR)),
64 endpoint_ (),
65 count_ (1)
69 TAO_DIOP_Profile::~TAO_DIOP_Profile ()
71 // Clean up the list of endpoints since we own it.
72 // Skip the head, since it is not dynamically allocated.
73 TAO_Endpoint *tmp = 0;
75 for (TAO_Endpoint *next = this->endpoint ()->next ();
76 next != 0;
77 next = tmp)
79 tmp = next->next ();
80 delete next;
84 // return codes:
85 // -1 -> error
86 // 0 -> can't understand this version
87 // 1 -> success.
89 int
90 TAO_DIOP_Profile::decode_profile (TAO_InputCDR& cdr)
92 // @@ NOTE: This code is repeated thrice. Need to factor out in a
93 // better manner.
94 // Decode host and port into the <endpoint_>.
95 if (cdr.read_string (this->endpoint_.host_.out ()) == 0
96 || cdr.read_ushort (this->endpoint_.port_) == 0)
98 if (TAO_debug_level > 0)
99 TAOLIB_DEBUG ((LM_DEBUG,
100 ACE_TEXT ("TAO (%P|%t) - DIOP_Profile::decode_profile, ")
101 ACE_TEXT ("error while decoding host/port\n")));
102 return -1;
105 if (cdr.good_bit ())
107 // Invalidate the object_addr_ until first access.
108 this->endpoint_.object_addr_.set_type (-1);
110 return 1;
113 return -1;
116 void
117 TAO_DIOP_Profile::parse_string_i (const char *ior)
119 // Pull off the "hostname:port/" part of the objref
120 // Copy the string because we are going to modify it...
121 const char *okd = std::strchr (ior, this->object_key_delimiter_);
123 if (okd == 0 || okd == ior)
125 // No object key delimiter or no hostname specified.
126 throw ::CORBA::INV_OBJREF (
127 CORBA::SystemException::_tao_minor_code (
128 TAO::VMCID,
129 EINVAL),
130 CORBA::COMPLETED_NO);
133 // Length of host string.
134 CORBA::ULong length_host = 0;
136 const char *cp_pos = std::strchr (ior, ':'); // Look for a port
137 #if defined (ACE_HAS_IPV6)
138 // IPv6 numeric address in host string?
139 bool ipv6_in_host = false;
141 // Check if this is a (possibly) IPv6 supporting profile containing a
142 // decimal IPv6 address representation.
143 if ((this->version ().major > TAO_MIN_IPV6_IIOP_MAJOR ||
144 this->version ().minor >= TAO_MIN_IPV6_IIOP_MINOR) &&
145 ior[0] == '[')
147 // In this case we have to find the end of the numeric address and
148 // start looking for the port separator from there.
149 const char *cp_pos_a = std::strchr (ior, ']');
150 if (cp_pos_a == 0)
152 // No valid IPv6 address specified.
153 if (TAO_debug_level > 0)
155 TAOLIB_DEBUG ((LM_ERROR,
156 ACE_TEXT ("\nTAO (%P|%t) - DIOP_Profile::parse_string_i, ")
157 ACE_TEXT ("invalid IPv6 decimal address specified.\n")));
160 throw ::CORBA::INV_OBJREF (
161 CORBA::SystemException::_tao_minor_code (
163 EINVAL),
164 CORBA::COMPLETED_NO);
166 else
168 if (cp_pos_a[1] == ':') // Look for a port
169 cp_pos = cp_pos_a + 1;
170 else
171 cp_pos = 0;
172 ipv6_in_host = true; // host string contains full IPv6 numeric address
175 #endif /* ACE_HAS_IPV6 */
177 if (cp_pos == ior)
179 if (TAO_debug_level > 0)
181 TAOLIB_ERROR ((LM_ERROR,
182 ACE_TEXT ("\nTAO (%P|%t) DIOP_Profile: ")
183 ACE_TEXT ("Host address may be omited only when no port has been specified.\n")));
185 // No hostname specified! It is required by the spec.
186 throw ::CORBA::INV_OBJREF (
187 CORBA::SystemException::_tao_minor_code (
188 TAO::VMCID,
189 EINVAL),
190 CORBA::COMPLETED_NO);
192 else if (cp_pos != 0)
194 // A port number or port name was specified.
195 CORBA::ULong length_port = ACE_Utils::truncate_cast<CORBA::ULong> (okd - cp_pos - 1);
197 CORBA::String_var tmp = CORBA::string_alloc (length_port);
199 ACE_OS::strncpy (tmp.inout (), cp_pos + 1, length_port);
200 tmp[length_port] = '\0';
202 if (ACE_OS::strspn (tmp.in (), "1234567890") == length_port)
204 this->endpoint_.port_ =
205 static_cast<CORBA::UShort> (ACE_OS::atoi (tmp.in ()));
207 else
209 ACE_INET_Addr ia;
210 if (ia.string_to_addr (tmp.in ()) == -1)
212 throw ::CORBA::INV_OBJREF (
213 CORBA::SystemException::_tao_minor_code (
215 EINVAL),
216 CORBA::COMPLETED_NO);
218 else
220 this->endpoint_.port_ = ia.get_port_number ();
224 length_host = ACE_Utils::truncate_cast<CORBA::ULong> (cp_pos - ior);
226 else
227 length_host = ACE_Utils::truncate_cast<CORBA::ULong> (okd - ior);
229 #if defined (ACE_HAS_IPV6)
230 if (ipv6_in_host)
231 length_host -= 2; // don't store '[' and ']'
232 #endif /* ACE_HAS_IPV6 */
234 CORBA::String_var tmp = CORBA::string_alloc (length_host);
236 #if defined (ACE_HAS_IPV6)
237 if (ipv6_in_host)
238 ACE_OS::strncpy (tmp.inout (), ior + 1, length_host);
239 else
240 #endif /* ACE_HAS_IPV6 */
241 // Skip the trailing '/'
242 ACE_OS::strncpy (tmp.inout (), ior, length_host);
243 tmp[length_host] = '\0';
245 this->endpoint_.host_ = tmp._retn ();
246 #if defined (ACE_HAS_IPV6)
247 this->endpoint_.is_ipv6_decimal_ = ipv6_in_host;
248 #endif /* ACE_HAS_IPV6 */
250 if (ACE_OS::strcmp (this->endpoint_.host_.in (), "") == 0)
252 ACE_INET_Addr host_addr;
254 char tmp_host [MAXHOSTNAMELEN + 1];
256 // If no host is specified: assign the default host, i.e. the
257 // local host.
258 if (host_addr.get_host_name (tmp_host,
259 sizeof (tmp_host)) != 0)
261 // Can't get the IP address since the INET_Addr wasn't
262 // initialized. Just throw an exception.
264 if (TAO_debug_level > 0)
265 TAOLIB_DEBUG ((LM_DEBUG,
266 ACE_TEXT ("TAO (%P|%t) - ")
267 ACE_TEXT ("DIOP_Profile::parse_string_i, ")
268 ACE_TEXT ("%p\n\n"),
269 ACE_TEXT ("cannot determine hostname")));
271 // @@ What's the right exception to throw here?
272 throw ::CORBA::INV_OBJREF (
273 CORBA::SystemException::_tao_minor_code (
274 TAO::VMCID,
275 EINVAL),
276 CORBA::COMPLETED_NO);
278 else
279 this->endpoint_.host_ = CORBA::string_dup (tmp_host);
282 TAO::ObjectKey ok;
283 TAO::ObjectKey::decode_string_to_sequence (ok,
284 okd + 1);
286 (void) this->orb_core ()->object_key_table ().bind (ok,
287 this->ref_object_key_);
290 CORBA::Boolean
291 TAO_DIOP_Profile::do_is_equivalent (const TAO_Profile *other_profile)
293 const TAO_DIOP_Profile *op =
294 dynamic_cast<const TAO_DIOP_Profile *> (other_profile);
296 // Make sure we have a TAO_DIOP_Profile.
297 if (op == 0)
298 return 0;
300 // Check endpoints equivalence.
301 const TAO_DIOP_Endpoint *other_endp = &op->endpoint_;
302 for (TAO_DIOP_Endpoint *endp = &this->endpoint_;
303 endp != 0;
304 endp = endp->next_)
306 if (endp->is_equivalent (other_endp))
307 other_endp = other_endp->next_;
308 else
309 return false;
312 return true;
315 CORBA::ULong
316 TAO_DIOP_Profile::hash (CORBA::ULong max)
318 // Get the hashvalue for all endpoints.
319 CORBA::ULong hashval = 0;
320 for (TAO_DIOP_Endpoint *endp = &this->endpoint_;
321 endp != 0;
322 endp = endp->next_)
324 hashval += endp->hash ();
327 hashval += this->version_.minor;
328 hashval += this->tag ();
330 const TAO::ObjectKey &ok =
331 this->ref_object_key_->object_key ();
333 if (ok.length () >= 4)
335 hashval += ok[1];
336 hashval += ok[3];
339 hashval += this->hash_service_i (max);
341 return hashval % max;
344 TAO_Endpoint*
345 TAO_DIOP_Profile::endpoint ()
347 return &this->endpoint_;
350 CORBA::ULong
351 TAO_DIOP_Profile::endpoint_count () const
353 return this->count_;
356 void
357 TAO_DIOP_Profile::add_endpoint (TAO_DIOP_Endpoint *endp)
359 endp->next_ = this->endpoint_.next_;
360 this->endpoint_.next_ = endp;
362 this->count_++;
365 char *
366 TAO_DIOP_Profile::to_string () const
368 // corbaloc:diop:1.2@host:port,diop:1.2@host:port,.../key
370 CORBA::String_var key;
371 TAO::ObjectKey::encode_sequence_to_string (key.inout (),
372 this->ref_object_key_->object_key ());
374 size_t buflen = (
375 8 /* "corbaloc" */ +
376 1 /* colon separator */ +
377 1 /* object key separator */ +
378 ACE_OS::strlen (key.in ()));
379 size_t pfx_len = (
380 ACE_OS::strlen (::the_prefix) /* "diop" */ +
381 1 /* colon separator */);
383 const TAO_DIOP_Endpoint *endp = 0;
384 for (endp = &this->endpoint_; endp != 0; endp = endp->next_)
386 buflen += (
387 pfx_len +
388 1 /* major version */ +
389 1 /* decimal point */ +
390 1 /* minor version */ +
391 1 /* `@' character */ +
392 ACE_OS::strlen (endp->host ()) +
393 1 /* colon separator */ +
394 5 /* port number */ +
395 1 /* comma */);
396 #if defined (ACE_HAS_IPV6)
397 if (endp->is_ipv6_decimal_)
398 buflen += 2; // room for '[' and ']'
399 #endif /* ACE_HAS_IPV6 */
402 static const char digits [] = "0123456789";
404 char * buf = CORBA::string_alloc (static_cast<CORBA::ULong> (buflen));
406 ACE_OS::strcpy (buf, "corbaloc:");
408 for (endp = &this->endpoint_; endp != 0; endp = endp->next_)
410 if (&this->endpoint_ != endp)
411 ACE_OS::strcat (buf, ",");
413 #if defined (ACE_HAS_IPV6)
414 if (endp->is_ipv6_decimal_)
416 // Don't publish scopeid if included.
417 ACE_CString tmp (endp->host ());
418 ACE_CString::size_type pos = tmp.find ('%');
419 if (pos != ACE_CString::npos)
421 tmp = tmp.substr (0, pos + 1);
422 tmp[pos] = '\0';
424 ACE_OS::sprintf (buf + ACE_OS::strlen (buf),
425 "%s:%c.%c@[%s]:%d",
426 ::the_prefix,
427 digits [this->version_.major],
428 digits [this->version_.minor],
429 tmp.c_str (),
430 endp->port ());
432 else
433 #endif
434 ACE_OS::sprintf (buf + ACE_OS::strlen (buf),
435 "%s:%c.%c@%s:%d",
436 ::the_prefix,
437 digits [this->version_.major],
438 digits [this->version_.minor],
439 endp->host (),
440 endp->port ());
442 ACE_OS::sprintf (buf + ACE_OS::strlen (buf),
443 "%c%s",
444 this->object_key_delimiter_,
445 key.in ());
447 return buf;
450 const char *
451 TAO_DIOP_Profile::prefix ()
453 return ::the_prefix;
456 void
457 TAO_DIOP_Profile::create_profile_body (TAO_OutputCDR &encap) const
459 encap.write_octet (TAO_ENCAP_BYTE_ORDER);
461 // The GIOP version
462 encap.write_octet (this->version_.major);
463 encap.write_octet (this->version_.minor);
465 // STRING hostname from profile
466 #if defined (ACE_HAS_IPV6)
467 // For IPv6 decimal addresses make sure the possibly included scopeid
468 // is not published as this has only local meaning.
469 const char* host;
470 const char* pos;
471 if (this->endpoint_.is_ipv6_decimal_ &&
472 (pos = std::strchr (host = this->endpoint_.host (), '%')) != 0)
474 ACE_CString tmp;
475 size_t len = pos - host;
476 tmp.set (this->endpoint_.host (), len, 1);
477 encap.write_string (tmp.c_str ());
479 else
480 #endif /* ACE_HAS_IPV6 */
481 encap.write_string (this->endpoint_.host ());
483 // UNSIGNED SHORT port number
484 encap.write_ushort (this->endpoint_.port ());
486 // OCTET SEQUENCE for object key
487 if (this->ref_object_key_)
488 encap << this->ref_object_key_->object_key ();
489 else
491 TAOLIB_ERROR ((LM_ERROR,
492 "TAO (%P|%t) - DIOP_Profile::create_profile_body, "
493 "no object key marshalled\n"));
496 if (this->version_.major > 1
497 || this->version_.minor > 0)
498 this->tagged_components ().encode (encap);
502 TAO_DIOP_Profile::encode_endpoints ()
504 // Create a data structure and fill it with endpoint info for wire
505 // transfer.
506 // We include information for the head of the list
507 // together with other endpoints because even though its addressing
508 // info is transmitted using standard ProfileBody components, its
509 // priority is not!
511 TAO::IIOPEndpointSequence endpoints;
512 endpoints.length (this->count_);
514 const TAO_DIOP_Endpoint *endpoint = &this->endpoint_;
515 for (CORBA::ULong i = 0;
516 i < this->count_;
517 ++i)
519 #if defined (ACE_HAS_IPV6)
520 if (endpoint->is_ipv6_decimal_)
522 // Don't publish scopeid if included.
523 ACE_CString tmp (endpoint->host ());
524 ACE_CString::size_type pos = tmp.find ('%');
525 if (pos != ACE_CString::npos)
527 tmp = tmp.substr (0, pos + 1);
528 tmp[pos] = '\0';
529 endpoints[i].host = tmp.c_str ();
531 else
532 endpoints[i].host = tmp.c_str ();
534 else
535 #endif /* ACE_HAS_IPV6 */
536 endpoints[i].host = endpoint->host ();
537 endpoints[i].port = endpoint->port ();
538 endpoints[i].priority = endpoint->priority ();
540 endpoint = endpoint->next_;
543 // Encode the data structure.
544 TAO_OutputCDR out_cdr;
545 if ((out_cdr << ACE_OutputCDR::from_boolean (TAO_ENCAP_BYTE_ORDER)) == 0
546 || (out_cdr << endpoints) == 0)
547 return -1;
549 this->set_tagged_components (out_cdr);
551 return 0;
555 TAO_DIOP_Profile::decode_endpoints ()
557 IOP::TaggedComponent tagged_component;
558 tagged_component.tag = TAO_TAG_ENDPOINTS;
560 if (this->tagged_components_.get_component (tagged_component))
562 const CORBA::Octet *buf =
563 tagged_component.component_data.get_buffer ();
565 TAO_InputCDR in_cdr (reinterpret_cast<const char*> (buf),
566 tagged_component.component_data.length ());
568 // Extract the Byte Order.
569 CORBA::Boolean byte_order;
570 if ((in_cdr >> ACE_InputCDR::to_boolean (byte_order)) == 0)
571 return -1;
572 in_cdr.reset_byte_order (static_cast<int> (byte_order));
574 // Extract endpoints sequence.
575 TAO::IIOPEndpointSequence endpoints;
577 if (! (in_cdr >> endpoints))
578 return -1;
580 // Get the priority of the first endpoint (head of the list.
581 // It's other data is extracted as part of the standard profile
582 // decoding.
583 this->endpoint_.priority (endpoints[0].priority);
585 // Use information extracted from the tagged component to
586 // populate the profile. Skip the first endpoint, since it is
587 // always extracted through standard profile body. Also, begin
588 // from the end of the sequence to preserve endpoint order,
589 // since <add_endpoint> method reverses the order of endpoints
590 // in the list.
591 for (CORBA::ULong i = endpoints.length () - 1;
592 i > 0;
593 --i)
595 TAO_DIOP_Endpoint *endpoint = 0;
596 ACE_NEW_RETURN (endpoint,
597 TAO_DIOP_Endpoint (endpoints[i].host,
598 endpoints[i].port,
599 endpoints[i].priority),
600 -1);
602 this->add_endpoint (endpoint);
606 return 0;
609 TAO_END_VERSIONED_NAMESPACE_DECL
611 #endif /* TAO_HAS_DIOP && TAO_HAS_DIOP != 0 */