2 #include "tao/IIOP_Connector.h"
4 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
6 #include "tao/IIOP_Profile.h"
8 #include "tao/ORB_Core.h"
9 #include "tao/Protocols_Hooks.h"
10 #include "tao/Connect_Strategy.h"
11 #include "tao/Thread_Lane_Resources.h"
12 #include "tao/Profile_Transport_Resolver.h"
13 #include "tao/Base_Transport_Property.h"
14 #include "tao/Transport.h"
15 #include "tao/Wait_Strategy.h"
16 #include "tao/SystemException.h"
17 #include "tao/LF_Multi_Event.h"
18 #include "ace/OS_NS_strings.h"
19 #include "ace/OS_NS_string.h"
20 #include "ace/OS_NS_time.h"
21 #include "ace/CORBA_macros.h"
24 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
26 // Uncomment *one* of the the following defines if you want to explicitly induce
27 // the race condition defined in Bug 2654. These enable the introduction of a
28 // slight delay during connection completion processing.
29 // A - before checking the connection_pending status
30 // B - after A but before checking the connection error result
31 // C - acter B but before caching
33 //#define INDUCE_BUG_2654_A
34 //#define INDUCE_BUG_2654_B
35 //#define INDUCE_BUG_2654_C
36 //#define INDUCE_BUG_2654_D
38 //-----------------------------------------------------------------------------
41 * @class TAO_Event_Handler_Array_var
43 * @brief Unique pointer like class for an array of Event Handlers.
45 * Used to manage lifecycle of handlers. This class calls
46 * ACE_Event_Handler::remove_reference() on each handler in its destructor
47 * This class started out life as a replacement for the ACE_Event_Handle_var
48 * but is now pared down to be very specific in its role..
50 class TAO_IIOP_Connection_Handler_Array_Guard
53 TAO_IIOP_Connection_Handler_Array_Guard (TAO_IIOP_Connection_Handler
**p
, unsigned count
);
54 ~TAO_IIOP_Connection_Handler_Array_Guard ();
58 TAO_IIOP_Connection_Handler
**ptr_
;
62 TAO_IIOP_Connection_Handler_Array_Guard::TAO_IIOP_Connection_Handler_Array_Guard (
63 TAO_IIOP_Connection_Handler
**p
,
70 TAO_IIOP_Connection_Handler_Array_Guard::~TAO_IIOP_Connection_Handler_Array_Guard ()
72 ACE_Errno_Guard
eguard (errno
);
73 if (this->ptr_
!= nullptr)
75 for (unsigned i
= 0; i
< this->count_
; i
++)
76 this->ptr_
[i
]->remove_reference ();
80 //---------------------------------------------------------------------------
83 TAO_IIOP_Connector::~TAO_IIOP_Connector ()
87 TAO_IIOP_Connector::TAO_IIOP_Connector ()
88 : TAO_Connector (IOP::TAG_INTERNET_IOP
)
89 , connect_strategy_ ()
90 , base_connector_ (nullptr)
95 TAO_IIOP_Connector::open (TAO_ORB_Core
*orb_core
)
97 // @todo: The functionality of the following two statements could
98 // be done in the constructor, but that involves changing the
99 // interface of the pluggable transport factory.
102 this->orb_core (orb_core
);
104 // Create our connect strategy
105 if (this->create_connect_strategy () == -1)
108 /// Our connect creation strategy
109 TAO_IIOP_CONNECT_CREATION_STRATEGY
*connect_creation_strategy
= nullptr;
111 ACE_NEW_RETURN (connect_creation_strategy
,
112 TAO_IIOP_CONNECT_CREATION_STRATEGY
113 (orb_core
->thr_mgr (),
117 /// Our activation strategy
118 TAO_IIOP_CONNECT_CONCURRENCY_STRATEGY
*concurrency_strategy
= nullptr;
120 ACE_NEW_RETURN (concurrency_strategy
,
121 TAO_IIOP_CONNECT_CONCURRENCY_STRATEGY (orb_core
),
124 return this->base_connector_
.open (this->orb_core ()->reactor (),
125 connect_creation_strategy
,
126 &this->connect_strategy_
,
127 concurrency_strategy
);
131 TAO_IIOP_Connector::close ()
133 delete this->base_connector_
.concurrency_strategy ();
134 delete this->base_connector_
.creation_strategy ();
135 return this->base_connector_
.close ();
139 TAO_IIOP_Connector::supports_parallel_connects() const
145 TAO_IIOP_Connector::set_validate_endpoint (TAO_Endpoint
*endpoint
)
147 TAO_IIOP_Endpoint
*iiop_endpoint
= this->remote_endpoint (endpoint
);
149 if (iiop_endpoint
== nullptr)
152 const ACE_INET_Addr
&remote_address
= iiop_endpoint
->object_addr ();
154 // Verify that the remote ACE_INET_Addr was initialized properly.
155 // Failure can occur if hostname lookup failed when initializing the
156 // remote ACE_INET_Addr.
157 #if defined (ACE_HAS_IPV6)
158 if (remote_address
.get_type () != AF_INET
&&
159 remote_address
.get_type () != AF_INET6
)
160 #else /* ACE_HAS_IPV6 */
161 if (remote_address
.get_type () != AF_INET
)
162 #endif /* !ACE_HAS_IPV6 */
164 if (TAO_debug_level
> 0)
166 TAOLIB_DEBUG ((LM_DEBUG
,
167 ACE_TEXT ("TAO (%P|%t) - IIOP connection failed.\n")
168 ACE_TEXT (" This is most likely ")
169 ACE_TEXT ("due to a hostname lookup ")
170 ACE_TEXT ("failure.\n")));
180 TAO_IIOP_Connector::make_connection (TAO::Profile_Transport_Resolver
*r
,
181 TAO_Transport_Descriptor_Interface
&desc
,
182 ACE_Time_Value
*timeout
)
184 TAO_IIOP_Connection_Handler
*svc_handler
= nullptr;
185 TAO_IIOP_Endpoint
*iiop_endpoint
=
186 this->remote_endpoint (desc
.endpoint());
187 if (iiop_endpoint
== nullptr)
191 this->begin_connection (svc_handler
, r
, iiop_endpoint
, timeout
);
193 // Make sure that we always do a remove_reference
194 ACE_Event_Handler_var
svc_handler_auto_ptr (svc_handler
);
196 if (result
== -1 && errno
!= EWOULDBLOCK
)
198 // Give users a clue to the problem.
199 if (TAO_debug_level
> 1)
201 TAOLIB_ERROR ((LM_ERROR
,
202 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::make_connection, ")
203 ACE_TEXT("connection to <%C:%d> failed (%p)\n"),
204 iiop_endpoint
->host (),
205 iiop_endpoint
->port (),
211 TAO_IIOP_Connection_Handler
**sh_ptr
= &svc_handler
;
212 TAO_IIOP_Endpoint
**ep_ptr
= &iiop_endpoint
;
213 TAO_LF_Multi_Event mev
;
214 mev
.add_event (svc_handler
);
216 TAO_Transport
*transport
=
217 this->complete_connection (result
,
226 // If complete_connection was unsuccessful then remove
227 // the last reference that we have to the svc_handler.
228 if (transport
== nullptr)
230 if (TAO_debug_level
> 1)
232 TAOLIB_ERROR ((LM_ERROR
,
233 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::make_connection, ")
234 ACE_TEXT ("connection to <%C:%d> completed unsuccessfully\n"),
235 iiop_endpoint
->host (),
236 iiop_endpoint
->port ()));
241 svc_handler_auto_ptr
.release ();
246 TAO_IIOP_Connector::make_parallel_connection (
247 TAO::Profile_Transport_Resolver
* r
,
248 TAO_Transport_Descriptor_Interface
& desc
,
249 ACE_Time_Value
* timeout
)
251 TAO_Endpoint
*root_ep
= desc
.endpoint();
252 unsigned max_count
= 1;
254 this->orb_core ()->orb_params ()->parallel_connect_delay ();
255 time_t sec_stagger
= ns_stagger
/1000;
256 ns_stagger
= (ns_stagger
% 1000) * 1000000;
257 for (TAO_Endpoint
*ep
= root_ep
->next_filtered (this->orb_core(), nullptr);
259 ep
= ep
->next_filtered (this->orb_core(), root_ep
))
262 if (TAO_debug_level
> 2)
263 TAOLIB_DEBUG ((LM_DEBUG
,
264 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::")
265 ACE_TEXT ("make_parallel_connection, ")
266 ACE_TEXT ("to %d endpoints\n"), max_count
));
267 TAO_IIOP_Endpoint
**eplist
= nullptr;
268 TAO_IIOP_Connection_Handler
**shlist
= nullptr;
269 ACE_NEW_RETURN (shlist
, TAO_IIOP_Connection_Handler
*[max_count
], nullptr);
270 ACE_NEW_RETURN (eplist
, TAO_IIOP_Endpoint
*[max_count
], nullptr);
272 TAO_LF_Multi_Event mev
;
275 for (TAO_Endpoint
*ep
= root_ep
->next_filtered (this->orb_core(),nullptr);
277 ep
= ep
->next_filtered(this->orb_core(),root_ep
))
279 eplist
[count
] = this->remote_endpoint (ep
);
280 shlist
[count
] = nullptr;
281 result
= this->begin_connection (shlist
[count
],
286 // The connection may fail because it is slow, or for other reasons.
287 // If it was an incomplete non-blocking connection, add it to the list
288 // to be waited on, otherwise remove the reference to the handler and
289 // move on to the next endpoint.
292 if (errno
== EWOULDBLOCK
)
294 mev
.add_event(shlist
[count
++]);
295 if (ep
->next() != nullptr)
297 struct timespec nsleep
= {sec_stagger
, ns_stagger
};
298 ACE_OS::nanosleep (&nsleep
);
299 result
= this->active_connect_strategy_
->poll (&mev
);
306 shlist
[count
]->remove_reference(); // done bump the list count
311 if (result
!= -1) // we have a winner!
314 break; // no waiting involved since a connection is completed
318 TAO_Transport
*winner
= nullptr;
319 if (count
> 0) // only complete if at least one pending or success
321 // Make sure that we always do a remove_reference for every member
323 TAO_IIOP_Connection_Handler_Array_Guard
svc_handler_auto_ptr (shlist
, count
);
325 winner
= this->complete_connection (result
,
333 // We add here an extra reference so that when svc_handler_auto_ptr
334 // will go out of scope the winner will be still alive.
336 winner
->add_reference ();
339 delete [] shlist
; // reference reductions should have been done already
345 TAO_IIOP_Connector::begin_connection (TAO_IIOP_Connection_Handler
*&svc_handler
,
346 TAO::Profile_Transport_Resolver
*r
,
347 TAO_IIOP_Endpoint
*iiop_endpoint
,
348 ACE_Time_Value
*timeout
)
350 const ACE_INET_Addr
&remote_address
= iiop_endpoint
->object_addr ();
352 u_short port
= this->orb_core ()->orb_params ()->iiop_client_port_base ();
353 ACE_UINT32
const ia_any
= INADDR_ANY
;
354 ACE_INET_Addr
local_addr(port
, ia_any
);
356 if (iiop_endpoint
->is_preferred_network ())
358 local_addr
.set (port
, iiop_endpoint
->preferred_network ());
360 #if defined (ACE_HAS_IPV6)
361 else if (remote_address
.get_type () == AF_INET6
)
363 local_addr
.set (port
, ACE_IPV6_ANY
);
365 #endif /* ACE_HAS_IPV6 */
367 if (TAO_debug_level
> 2)
369 TAOLIB_DEBUG ((LM_DEBUG
,
370 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::begin_connection, ")
371 ACE_TEXT ("to <%C:%d> which should %s\n"),
372 iiop_endpoint
->host(),
373 iiop_endpoint
->port(),
374 r
->blocked_connect () ? ACE_TEXT("block") : ACE_TEXT("nonblock")));
377 // Get the right synch options
378 ACE_Synch_Options synch_options
;
380 this->active_connect_strategy_
->synch_options (timeout
, synch_options
);
382 // The code used to set the timeout to zero, with the intent of
383 // polling the reactor for connection completion. However, the side-effect
384 // was to cause the connection to timeout immediately.
385 svc_handler
= nullptr;
388 u_short span
= this->orb_core ()->orb_params ()->iiop_client_port_span ();
389 for (u_short offset
= 0; offset
<= span
; ++offset
)
391 local_addr
.set_port_number (port
+ offset
);
392 if (TAO_debug_level
> 0 && (port
+ offset
) > 0 )
394 TAOLIB_DEBUG ((LM_DEBUG
,
395 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::begin_connection, ")
396 ACE_TEXT ("trying local port %d\n"),
399 result
= this->base_connector_
.connect (svc_handler
,
403 if (result
== 0 || (errno
!= EADDRINUSE
&& errno
!= EINVAL
))
409 if (svc_handler
!= nullptr)
411 svc_handler
->remove_reference ();
412 svc_handler
= nullptr;
422 /// RAII holder for a TAO_Transport list
426 TList_Holder (size_t count
)
429 // Resources are acquired during initialization (RAII)
430 ACE_NEW (tlist_
, TAO_Transport
*[count
]);
435 // Resources are unacquired during uninitialization
439 operator TAO_Transport
** ()
445 TAO_Transport
** tlist_
;
447 void operator= (const TList_Holder
&) = delete;
448 TList_Holder (const TList_Holder
&) = delete;
453 TAO_IIOP_Connector::complete_connection (int result
,
454 TAO_Transport_Descriptor_Interface
&desc
,
455 TAO_IIOP_Connection_Handler
**&sh_list
,
456 TAO_IIOP_Endpoint
**ep_list
,
458 TAO::Profile_Transport_Resolver
*r
,
459 TAO_LF_Multi_Event
*mev
,
460 ACE_Time_Value
*timeout
)
462 TAO_IIOP::TList_Holder
tlist(count
);
464 TAO_Transport
*transport
= nullptr;
466 // populate the transport list
467 for (unsigned i
= 0; i
< count
; i
++)
468 tlist
[i
] = sh_list
[i
]->transport();
472 // We received a completed connection and 0 or more pending.
473 // the winner is the last member of the list, because the
474 // iterator stopped on a successful connect.
475 transport
= tlist
[count
-1];
477 this->cleanup_pending (transport
, tlist
, count
);
479 desc
.reset_endpoint (ep_list
[count
-1]);
480 TAO::Transport_Cache_Manager
&tcm
=
481 this->orb_core ()->lane_resources ().transport_cache ();
482 if (tcm
.cache_transport (&desc
, transport
) == -1)
484 // Cache is full, so close the connection again
485 sh_list
[count
-1]->close ();
493 transport
= tlist
[0];
494 desc
.reset_endpoint(ep_list
[0]);
495 if (!this->wait_for_connection_completion (r
,
500 if (TAO_debug_level
> 2)
501 TAOLIB_ERROR ((LM_ERROR
,
502 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::")
503 ACE_TEXT ("complete_connection, wait for completion ")
504 ACE_TEXT ("failed for 1 pending connect\n")));
509 if (!this->wait_for_connection_completion (r
,
516 if (TAO_debug_level
> 2)
517 TAOLIB_ERROR ((LM_ERROR
,
518 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::")
519 ACE_TEXT ("complete_connection, wait for completion ")
520 ACE_TEXT ("failed for %d pending connects\n"),
526 #if defined (INDUCE_BUG_2654_A)
527 // This is where the fatal error would occur. A pending asynch
528 // connection would fail, the failure handled by another thread,
529 // closing the connection. However the remainder of this method
530 // only checked to see if the keep_waiting status was true, and bump
531 // the refcount then. However if the status was really
532 // error_detected, then no bump in refcount occurred allowing the
533 // connection_handler's close_handler method to effectively steal
534 // the reference to be handed back to the caller. That would then
535 // trigger an abort as the profile_transport_resolver (our caller)
536 // to delete the transport while it is still cached.
537 ACE_Time_Value
udelay(0,600);
538 struct timespec ts
= udelay
;
539 ACE_OS::nanosleep (&ts
);
540 #endif // INDUCE_BUG_2654_A
542 // At this point, the connection has been successfully created
543 // connected or not connected, but we have a connection.
544 TAO_IIOP_Connection_Handler
*svc_handler
= nullptr;
545 TAO_IIOP_Endpoint
*iiop_endpoint
= nullptr;
547 if (transport
!= nullptr)
549 for (unsigned i
= 0; i
< count
; i
++)
551 if (transport
== tlist
[i
])
553 svc_handler
= sh_list
[i
];
554 iiop_endpoint
= ep_list
[i
];
561 // In case of errors transport is zero
562 // Give users a clue to the problem.
563 if (TAO_debug_level
> 3)
565 for (unsigned i
= 0; i
< count
; i
++)
567 TAOLIB_ERROR ((LM_ERROR
,
568 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::complete_connection,")
569 ACE_TEXT (" connection to <%C:%d> failed (%p)\n"),
578 TAO_Leader_Follower
&leader_follower
= this->orb_core ()->leader_follower ();
580 if (svc_handler
->keep_waiting(leader_follower
))
582 svc_handler
->connection_pending();
585 #if defined (INDUCE_BUG_2654_B)
586 // It is possible for the connection failure to be processed after bumping
587 // the reference count and before we plan to cache the connection. Prior to
588 // fixing bug 2654, this would lead to a failed connection in the cache.
589 // Though not a fatal condition, it was certainly wasteful of resources.
590 ACE_Time_Value
udelay(0,600);
591 struct timespec ts
= udelay
;
592 ACE_OS::nanosleep (&ts
);
593 #endif // INDUCE_BUG_2654_B
596 if (transport
->connection_handler()->error_detected(leader_follower
))
598 if (TAO_debug_level
> 0)
599 TAOLIB_DEBUG((LM_DEBUG
,
600 ACE_TEXT("TAO (%P|%t) - IIOP_Connector::make_connection, ")
601 ACE_TEXT("transport in error before cache!\n")));
602 transport
->connection_handler()->cancel_pending_connection();
606 if (TAO_debug_level
> 2)
608 TAOLIB_DEBUG ((LM_DEBUG
,
609 ACE_TEXT ("TAO (%P|%t) - IIOP_Connector::make_connection, ")
610 ACE_TEXT ("new %s connection to <%C:%d> on Transport[%d]\n"),
611 transport
->is_connected() ?
612 ACE_TEXT("connected") : ACE_TEXT("not connected"),
613 iiop_endpoint
->host (),
614 iiop_endpoint
->port (),
615 svc_handler
->peer ().get_handle ()));
618 #if defined (INDUCE_BUG_2654_C)
619 // This sets up the possibility that a failed connection is detected after we
620 // checked the connection status but before we cached the connection. This
621 // will allow a failed connection to be cached
622 ACE_Time_Value
udelay(0,600);
623 struct timespec ts
= udelay
;
624 ACE_OS::nanosleep (&ts
);
625 #endif // INDUCE_BUG_2654_C
628 // Only for parallel connect, update the cache to show this in idle state
629 if (count
> 1 && desc
.reset_endpoint (iiop_endpoint
))
631 retval
= this->orb_core ()->
632 lane_resources ().transport_cache ().cache_transport (&desc
,
636 // Failure in adding to cache
639 // Close the handler.
640 svc_handler
->close ();
642 if (TAO_debug_level
> 0)
644 TAOLIB_ERROR ((LM_ERROR
,
645 ACE_TEXT ("TAO (%P|%t) IIOP_Connector::make_connection, ")
646 ACE_TEXT ("could not add new connection to cache\n")));
652 // Other part of fix for bug 2654.
653 // It is possible that after checking for a connection failure but
654 // before caching, the connection really failed, thus an invalid
655 // connection is put into the cache. Thus we do one last status
656 // check before handing the connection back to the caller.
657 if (svc_handler
->error_detected(leader_follower
))
659 if (TAO_debug_level
> 0)
660 TAOLIB_DEBUG((LM_DEBUG
,
661 ACE_TEXT("TAO (%P|%t) - IIOP_Connector::make_connection, ")
662 ACE_TEXT("transport in error after cache!\n")));
663 svc_handler
->cancel_pending_connection();
664 transport
->purge_entry();
669 #if defined (INDUCE_BUG_2654_D)
670 // at this point the connection handler's close connection will manage
671 // purging the entry from the cache so we are fine there.
672 ACE_Time_Value
udelay(0,600);
673 struct timespec ts
= udelay
;
674 ACE_OS::nanosleep (&ts
);
675 #endif // INDUCE_BUG_2654_D
677 // Have the transport register itself with the wait strategy and
678 // deal with the transport cache if there is a failure.
679 if (!transport
->register_if_necessary ())
688 TAO_IIOP_Connector::create_profile (TAO_InputCDR
& cdr
)
690 TAO_Profile
*pfile
= nullptr;
691 ACE_NEW_RETURN (pfile
,
692 TAO_IIOP_Profile (this->orb_core ()),
695 int const r
= pfile
->decode (cdr
);
698 pfile
->_decr_refcnt ();
706 TAO_IIOP_Connector::make_profile ()
708 // The endpoint should be of the form:
709 // N.n@host:port/object_key
711 // host:port/object_key
713 TAO_Profile
*profile
= nullptr;
714 ACE_NEW_THROW_EX (profile
,
715 TAO_IIOP_Profile (this->orb_core ()),
717 CORBA::SystemException::_tao_minor_code (
720 CORBA::COMPLETED_NO
));
726 TAO_IIOP_Connector::check_prefix (const char *endpoint
)
728 // Check for a valid string
729 if (!endpoint
|| !*endpoint
)
730 return -1; // Failure
732 static const char *protocol
[] = { "iiop", "iioploc" };
734 size_t const slot
= std::strchr (endpoint
, ':') - endpoint
;
735 if (slot
== 0) // an empty string is valid for corbaloc.
738 size_t const len0
= std::strlen (protocol
[0]);
739 size_t const len1
= std::strlen (protocol
[1]);
741 // Check for the proper prefix in the IOR. If the proper prefix
742 // isn't in the IOR then it is not an IOR we can use.
743 if (slot
== len0
&& ACE_OS::strncasecmp (endpoint
, protocol
[0], len0
) == 0)
745 else if (slot
== len1
&& ACE_OS::strncasecmp (endpoint
, protocol
[1], len1
) == 0)
749 // Failure: not an IIOP IOR
750 // DO NOT throw an exception here.
754 TAO_IIOP_Connector::object_key_delimiter () const
756 return TAO_IIOP_Profile::object_key_delimiter_
;
760 TAO_IIOP_Connector::remote_endpoint (TAO_Endpoint
*endpoint
)
762 if (endpoint
->tag () != IOP::TAG_INTERNET_IOP
)
765 TAO_IIOP_Endpoint
*iiop_endpoint
=
766 dynamic_cast<TAO_IIOP_Endpoint
*> (endpoint
);
768 if (iiop_endpoint
== nullptr)
771 return iiop_endpoint
;
775 TAO_IIOP_Connector::cancel_svc_handler (
776 TAO_Connection_Handler
* svc_handler
)
778 TAO_IIOP_Connection_Handler
* handler
=
779 dynamic_cast<TAO_IIOP_Connection_Handler
*>(svc_handler
);
781 // Cancel from the connector
785 return this->base_connector_
.cancel (handler
);
791 TAO_END_VERSIONED_NAMESPACE_DECL
793 #endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */