Revert "Minor modernization of DynamicAny code"
[ACE_TAO.git] / TAO / tao / Synch_Invocation.cpp
bloba04f5be2c25959cb2a28035b70f207d40d258044
1 #include "tao/Synch_Invocation.h"
2 #include "tao/Invocation_Retry_State.h"
3 #include "tao/Profile_Transport_Resolver.h"
4 #include "tao/Profile.h"
5 #include "tao/Synch_Reply_Dispatcher.h"
6 #include "tao/Transport.h"
7 #include "tao/Stub.h"
8 #include "tao/Bind_Dispatcher_Guard.h"
9 #include "tao/operation_details.h"
10 #include "tao/Wait_Strategy.h"
11 #include "tao/debug.h"
12 #include "tao/ORB_Constants.h"
13 #include "tao/Messaging_SyncScopeC.h"
14 #include "tao/ORB_Core.h"
15 #include "tao/Service_Context.h"
16 #include "tao/SystemException.h"
17 #include "ace/Intrusive_Auto_Ptr.h"
19 #if TAO_HAS_INTERCEPTORS == 1
20 # include "tao/PortableInterceptorC.h"
21 #endif /*TAO_HAS_INTERCEPTORS */
23 #include <memory>
24 #include "ace/OS_NS_string.h"
25 #include "tao/ORB_Time_Policy.h"
27 #if !defined (__ACE_INLINE__)
28 # include "tao/Synch_Invocation.inl"
29 #endif /* __ACE_INLINE__ */
31 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
33 namespace
35 int
36 excep_for_type (const char *tid)
38 if (ACE_OS::strcmp (tid, "IDL:omg.org/CORBA/TRANSIENT:1.0") == 0)
40 return TAO::FOE_TRANSIENT;
42 else if (ACE_OS::strcmp (tid, "IDL:omg.org/CORBA/COMM_FAILURE:1.0") == 0)
44 return TAO::FOE_COMM_FAILURE;
46 else if (ACE_OS::strcmp (tid, "IDL:omg.org/CORBA/OBJECT_NOT_EXIST:1.0") == 0)
48 return TAO::FOE_OBJECT_NOT_EXIST;
50 else if (ACE_OS::strcmp (tid, "IDL:omg.org/CORBA/INV_OBJREF:1.0") == 0)
52 return TAO::FOE_INV_OBJREF;
54 else if (ACE_OS::strcmp (tid, "IDL:omg.org/CORBA/OBJ_ADAPTER:1.0") == 0)
56 return TAO::FOE_OBJ_ADAPTER;
58 else if (ACE_OS::strcmp (tid, "IDL:omg.org/CORBA/NO_RESPONSE:1.0") == 0)
60 return TAO::FOE_NO_RESPONSE;
63 return 0;
67 namespace TAO
69 Synch_Twoway_Invocation::Synch_Twoway_Invocation (
70 CORBA::Object_ptr otarget,
71 Profile_Transport_Resolver &resolver,
72 TAO_Operation_Details &detail,
73 bool response_expected)
74 : Remote_Invocation (otarget,
75 resolver,
76 detail,
77 response_expected)
78 , retry_state_ (nullptr)
82 void
83 Synch_Twoway_Invocation::set_retry_state (Invocation_Retry_State *retry_state)
85 this->retry_state_ = retry_state;
88 Invocation_Status
89 Synch_Twoway_Invocation::remote_twoway (ACE_Time_Value *max_wait_time)
91 TAO::ORB_Countdown_Time countdown (max_wait_time);
93 TAO_Synch_Reply_Dispatcher *rd_p =
94 new (std::nothrow) TAO_Synch_Reply_Dispatcher (this->resolver_.stub ()->orb_core (),
95 this->details_.reply_service_info ());
96 if (!rd_p)
98 throw ::CORBA::NO_MEMORY ();
101 ACE_Intrusive_Auto_Ptr<TAO_Synch_Reply_Dispatcher> rd(rd_p, false);
103 Invocation_Status s = TAO_INVOKE_FAILURE;
105 #if TAO_HAS_INTERCEPTORS == 1
106 // Start the interception point here..
107 s = this->send_request_interception ();
109 if (s != TAO_INVOKE_SUCCESS)
110 return s;
112 // We have started the interception flow. We need to call the
113 // ending interception flow if things go wrong. The purpose of the
114 // try block is to do just this.
117 #endif /*TAO_HAS_INTERCEPTORS */
118 TAO_Transport* const transport = this->resolver_.transport ();
120 if (!transport)
122 if (this->retry_state_ &&
123 this->retry_state_->forward_on_exception_increment(FOE_TRANSIENT))
125 if (TAO_debug_level > 0)
126 TAOLIB_DEBUG ((LM_INFO,
127 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
128 ACE_TEXT ("remote_twoway retrying on TRANSIENT ")
129 ACE_TEXT ("exception\n")));
130 this->retry_state_->next_profile_retry (*this->stub ());
131 #if TAO_HAS_INTERCEPTORS == 1
132 s = this->receive_other_interception ();
133 #endif /* TAO_HAS_INTERCEPTORS */
134 return TAO_INVOKE_RESTART;
136 else
138 // Way back, we failed to find a profile we could connect to.
139 // We've come this far only so we reach the interception points
140 // in case they can fix things. Time to bail....
141 throw CORBA::TRANSIENT (CORBA::OMGVMCID | 2, CORBA::COMPLETED_NO);
146 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ace_mon,
147 transport->output_cdr_lock (), TAO_INVOKE_FAILURE);
149 TAO_OutputCDR &cdr = transport->out_stream ();
151 CDR_Byte_Order_Guard cdr_guard (cdr, this->_tao_byte_order ());
153 cdr.message_attributes (this->details_.request_id (),
154 this->resolver_.stub (),
155 TAO_Message_Semantics (),
156 max_wait_time);
158 this->write_header (cdr);
160 this->marshal_data (cdr);
162 // Register a reply dispatcher for this invocation. Use the
163 // preallocated reply dispatcher.
164 TAO_Bind_Dispatcher_Guard dispatch_guard (
165 this->details_.request_id (),
166 rd.get (),
167 transport->tms ());
169 if (dispatch_guard.status () != 0)
171 // @@ What is the right way to handle this error? Why should
172 // we close the connection?
173 transport->close_connection ();
175 throw ::CORBA::INTERNAL (0, CORBA::COMPLETED_NO);
178 countdown.update ();
180 s = this->send_message (cdr,
181 TAO_Message_Semantics (),
182 max_wait_time);
184 cdr_guard.reset (); // CDR_Byte_Order_Guard
186 ace_mon.release();
188 #if TAO_HAS_INTERCEPTORS == 1
189 // @@NOTE: Too much code repetition.
190 // If the above call returns a restart due to connection
191 // failure then call the receive_other interception point
192 // before we leave.
193 if (s == TAO_INVOKE_RESTART)
195 Invocation_Status const tmp = this->receive_other_interception ();
197 if (tmp != TAO_INVOKE_SUCCESS)
198 s = tmp;
200 #endif /* TAO_HAS_INTERCEPTORS */
202 if (s != TAO_INVOKE_SUCCESS)
203 return s;
205 countdown.update ();
207 // For some strategies one may want to release the transport
208 // back to cache. If the idling is successful let the
209 // resolver about that.
210 if (transport->idle_after_send ())
211 this->resolver_.transport_released ();
213 // @@ In all MT environments, there's a cancellation point lurking
214 // here; need to investigate. Client threads would frequently be
215 // canceled sometime during recv_request ... the correct action to
216 // take on being canceled is to issue a CancelRequest message to the
217 // server and then immediately let other client-side cancellation
218 // handlers do their jobs.
220 // In C++, that basically means to unwind the stack using almost
221 // normal procedures: all destructors should fire, and some "catch"
222 // blocks should probably be able to handle things like releasing
223 // pointers. (Without unwinding the C++ stack, resources that must
224 // be freed by thread cancellation won't be freed, and the process
225 // won't continue to function correctly.) The tricky part is that
226 // according to POSIX, all C stack frames must also have their
227 // (explicitly coded) handlers called. We assume a POSIX.1c/C/C++
228 // environment.
230 s = this->wait_for_reply (max_wait_time, *rd.get (), dispatch_guard);
232 #if TAO_HAS_INTERCEPTORS == 1
233 if (s == TAO_INVOKE_RESTART)
235 Invocation_Status const tmp = this->receive_other_interception ();
237 // Push the latest values for the return..
238 if (tmp != TAO_INVOKE_SUCCESS)
239 s = tmp;
241 #endif /* TAO_HAS_INTERCEPTORS */
243 if (s != TAO_INVOKE_SUCCESS)
244 return s;
246 // What happens when the above call returns an error through
247 // the return value? That would be bogus as per the contract
248 // in the interface. The call violated the contract
249 s = this->check_reply_status (*rd.get ());
251 // For some strategies one may want to release the transport
252 // back to cache after receiving the reply.
253 if (transport->idle_after_reply ())
254 this->resolver_.transport_released ();
256 #if TAO_HAS_INTERCEPTORS == 1
257 Invocation_Status tmp = TAO_INVOKE_FAILURE;
258 if (s == TAO_INVOKE_RESTART)
260 tmp = this->receive_other_interception ();
262 else if (s == TAO_INVOKE_SUCCESS)
264 tmp = this->receive_reply_interception ();
266 if (tmp != TAO_INVOKE_SUCCESS)
267 s = tmp;
269 catch ( ::CORBA::Exception& ex)
271 PortableInterceptor::ReplyStatus const status =
272 this->handle_any_exception (&ex);
274 if (status == PortableInterceptor::LOCATION_FORWARD ||
275 status == PortableInterceptor::TRANSPORT_RETRY)
276 s = TAO_INVOKE_RESTART;
277 else if (status == PortableInterceptor::SYSTEM_EXCEPTION
278 || status == PortableInterceptor::USER_EXCEPTION)
279 throw;
281 catch (...)
283 // Notify interceptors of non-CORBA exception, and propagate
284 // that exception to the caller.
286 PortableInterceptor::ReplyStatus const st =
287 this->handle_all_exception ();
289 if (st == PortableInterceptor::LOCATION_FORWARD ||
290 st == PortableInterceptor::TRANSPORT_RETRY)
291 s = TAO_INVOKE_RESTART;
292 else
293 throw;
295 #endif /* TAO_HAS_INTERCEPTORS */
297 return s;
300 Invocation_Status
301 Synch_Twoway_Invocation::wait_for_reply (ACE_Time_Value *max_wait_time,
302 TAO_Synch_Reply_Dispatcher &rd,
303 TAO_Bind_Dispatcher_Guard &bd)
306 * Precondition: The call went to the remote
307 * peer. <ACE_Thread::self> is waiting for the reply.
309 * Postcondition: Any error during a wait is marked by raising an
310 * exception. Success alone is returned through the return value.
313 bool const
314 expired = (max_wait_time && ACE_Time_Value::zero == *max_wait_time);
315 if (expired)
316 errno = ETIME;
317 int const
318 reply_error = expired ? -1 :
319 this->resolver_.transport ()->wait_strategy ()->wait (max_wait_time, rd);
321 if (TAO_debug_level > 0 && max_wait_time)
323 TAOLIB_DEBUG ((LM_DEBUG,
324 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::wait_for_reply, ")
325 ACE_TEXT ("timeout after recv is <%u> status <%d>\n"),
326 max_wait_time->msec (),
327 reply_error));
330 // Check the reply error.
331 if (reply_error == -1)
333 // Unbind the dispatcher, since its of no use at this point of
334 // time
335 if (TAO_debug_level > 3)
337 TAOLIB_DEBUG ((LM_DEBUG,
338 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
339 ACE_TEXT ("wait_for_reply, ")
340 ACE_TEXT ("recovering after an error\n")));
343 // You the smarty, don't try to moving the unbind_dispatcher
344 // () call since it looks like it is repeated twice. That
345 // could land you in trouble. If you don't believe this
346 // warning go ahead and try. Try running tests to see what is
347 // going on ;)
348 if (errno == ETIME)
350 // If the unbind succeeds then thrown an exception to the
351 // application, else just collect the reply and dispatch
352 // that to the application.
354 // NOTE: A fragile synchronization is provided when using
355 // the Muxed Transport strategy. We could infact be a
356 // follower thread getting timedout in the LF whereas the
357 // dispatching thread could be on the reply_dispatcher
358 // that we created. This would lead bad crashes. To get
359 // around that, the call to unbind_dispatcher () will wait
360 // on the lock on the Muxed_Transport_Strategy if
361 // dispatching has started. This is fragile.
362 if (bd.unbind_dispatcher () == 0)
364 // Just a timeout with completed_maybe, don't close
365 // the connection or anything
366 throw ::CORBA::TIMEOUT (
367 CORBA::SystemException::_tao_minor_code (
368 TAO_TIMEOUT_RECV_MINOR_CODE,
369 errno),
370 CORBA::COMPLETED_MAYBE);
373 else
375 (void) bd.unbind_dispatcher ();
376 this->resolver_.transport ()->close_connection ();
378 if (this->retry_state_ &&
379 this->resolver_.transport ()->connection_closed_on_read() &&
380 this->retry_state_->forward_on_reply_closed_increment ())
382 if (TAO_debug_level > 4)
383 TAOLIB_DEBUG ((LM_DEBUG,
384 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
385 ACE_TEXT ("wait_for_reply, forward profile on ")
386 ACE_TEXT ("connection closed\n")));
387 this->retry_state_->next_profile_retry (*this->stub ());
388 return TAO_INVOKE_RESTART;
393 return
394 this->stub()->orb_core ()->service_raise_comm_failure (
395 this->details_.request_service_context ().service_info (),
396 this->resolver_.profile ());
398 catch (const ::CORBA::Exception&)
400 if (this->retry_state_ == nullptr ||
401 !this->retry_state_->forward_on_exception_limit_used ())
403 this->resolver_.stub ()->reset_profiles ();
405 throw;
410 return TAO_INVOKE_SUCCESS;
413 Invocation_Status
414 Synch_Twoway_Invocation::check_reply_status (TAO_Synch_Reply_Dispatcher &rd)
417 * Precondition: We probably got a reply. <ACE_Thread::self> is
418 * checking the status of the reply
420 * Postcondition: Any error while reading the reply is marked by
421 * raising an exception. LOCATION_FORWARDED replies are marked by
422 * returning a restart since that is what needed to be done by the
423 * callee.
425 TAO_InputCDR &cdr = rd.reply_cdr ();
427 // Set the translators
428 this->resolver_.transport ()->assign_translators (&cdr, nullptr);
430 // At this point it can be assumed that the GIOP/whatever protocol
431 // header and the reply header are already handled. Further it
432 // can be assumed that the reply body contains the details
433 // required for further processing. All the other details should
434 // have been handled in the reply dispatcher/protocol framework.
435 switch (rd.reply_status ())
437 case GIOP::NO_EXCEPTION:
439 Reply_Guard mon (this, TAO_INVOKE_FAILURE);
440 if (this->details_.demarshal_args (cdr) == false)
442 throw ::CORBA::MARSHAL ();
445 mon.set_status (TAO_INVOKE_SUCCESS);
447 break;
448 case GIOP::LOCATION_FORWARD:
449 return this->location_forward (cdr);
450 case GIOP::LOCATION_FORWARD_PERM:
452 // Unmarshal the location forward object and set the
453 // variable this->forward_to_.
454 Invocation_Status const s = this->location_forward (cdr);
455 if (s != TAO_INVOKE_FAILURE)
457 // de-marshalling of permanent object reference was successfull
458 CORBA::Boolean const permanent_forward_condition =
459 this->stub ()->orb_core ()->is_permanent_forward_condition
460 (this->forwarded_to_.in (),
461 this->request_service_context ());
463 if (!permanent_forward_condition)
465 // permanent condition not given
466 if (TAO_debug_level > 3)
467 TAOLIB_DEBUG ((LM_DEBUG,
468 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
469 ACE_TEXT ("check_reply_status: unexpected ")
470 ACE_TEXT ("LOCATION_FORWARD_PERM reply\n")));
472 throw ::CORBA::INTERNAL (0, CORBA::COMPLETED_NO);
475 // This is the only place where we set in permanent forward state.
476 this->reply_status (GIOP::LOCATION_FORWARD_PERM);
479 return s;
481 case GIOP::USER_EXCEPTION:
482 return this->handle_user_exception (cdr);
483 case GIOP::SYSTEM_EXCEPTION:
484 return this->handle_system_exception (cdr);
486 case GIOP::NEEDS_ADDRESSING_MODE:
488 Reply_Guard mon (this, TAO_INVOKE_FAILURE);
489 // We have received a message with a request to change the
490 // addressing mode. First let us read the mode that the
491 // server/agent asks for.
492 CORBA::Short addr_mode = 0;
494 if (cdr.read_short (addr_mode) == 0)
496 // Could not demarshal the addressing disposition, raise an local
497 // CORBA::MARSHAL
498 throw ::CORBA::MARSHAL (0, CORBA::COMPLETED_MAYBE);
501 // Now set this addressing mode in the profile, so that
502 // the next invocation need not go through this.
503 this->resolver_.profile ()->addressing_mode (addr_mode);
505 mon.set_status (TAO_INVOKE_RESTART);
507 // Now restart the invocation
508 return TAO_INVOKE_RESTART;
511 return TAO_INVOKE_SUCCESS;
514 Invocation_Status
515 Synch_Twoway_Invocation::location_forward (TAO_InputCDR &inp_stream)
517 Reply_Guard mon (this, TAO_INVOKE_FAILURE);
519 if (TAO_debug_level > 3)
521 TAOLIB_DEBUG ((LM_DEBUG,
522 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
523 ACE_TEXT ("location_forward being handled\n")));
526 CORBA::Object_var fwd;
528 if (!(inp_stream >> fwd))
530 throw ::CORBA::MARSHAL (
531 CORBA::SystemException::_tao_minor_code (
532 TAO_INVOCATION_LOCATION_FORWARD_MINOR_CODE,
533 EINVAL),
534 CORBA::COMPLETED_NO);
537 this->forwarded_reference (fwd.in ());
539 mon.set_status (TAO_INVOKE_RESTART);
541 return TAO_INVOKE_RESTART;
544 Invocation_Status
545 Synch_Twoway_Invocation::handle_user_exception (TAO_InputCDR &cdr)
547 Reply_Guard mon (this,
548 TAO_INVOKE_FAILURE);
550 if (TAO_debug_level > 3)
551 TAOLIB_DEBUG ((LM_DEBUG,
552 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
553 ACE_TEXT ("handle_user_exception\n")));
555 // Pull the exception from the stream.
556 CORBA::String_var buf;
558 if (!(cdr >> buf.inout ()))
560 // Could not demarshal the exception id, raise an local
561 // CORBA::MARSHAL
562 throw ::CORBA::MARSHAL (0, CORBA::COMPLETED_MAYBE);
565 CORBA::Exception *exception = this->details_.corba_exception (buf.in ());
567 exception->_tao_decode (cdr);
569 if (TAO_debug_level > 5)
571 TAOLIB_DEBUG ((LM_DEBUG,
572 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
573 ACE_TEXT ("handle_user_exception - ")
574 ACE_TEXT ("raising exception %C\n"),
575 buf.in ()));
578 mon.set_status (TAO_INVOKE_USER_EXCEPTION);
580 // We must manage the memory allocated
581 // by the call above to alloc().
582 std::unique_ptr<CORBA::Exception> safety (exception);
584 exception->_raise ();
586 return TAO_INVOKE_USER_EXCEPTION;
589 Invocation_Status
590 Synch_Twoway_Invocation::handle_system_exception (TAO_InputCDR &cdr)
592 Reply_Guard mon (this, TAO_INVOKE_FAILURE);
594 if (TAO_debug_level > 3)
595 TAOLIB_DEBUG ((LM_DEBUG,
596 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
597 ACE_TEXT ("handle_system_exception\n")));
599 CORBA::String_var type_id;
601 if (!(cdr >> type_id.inout ()))
603 // Could not demarshal the exception id, raise an local
604 // CORBA::MARSHAL
605 throw ::CORBA::MARSHAL (0, CORBA::COMPLETED_MAYBE);
608 CORBA::ULong minor = 0;
609 CORBA::ULong completion = 0;
611 if (!(cdr >> minor) || !(cdr >> completion))
613 throw ::CORBA::MARSHAL (0, CORBA::COMPLETED_MAYBE);
616 bool retry_on_exception = false;
617 bool do_forward = false;
619 const TAO_ORB_Parameters *orb_params = this->stub ()->orb_core ()->orb_params ();
621 if (this->retry_state_ &&
622 this->retry_state_->forward_on_exception_limit_used () &&
623 (CORBA::CompletionStatus) completion == CORBA::COMPLETED_NO)
625 if (this->retry_state_->forward_on_exception_increment (excep_for_type (type_id.in ())))
627 retry_on_exception = true;
628 this->retry_state_->sleep_at_starting_profile (*this->stub ());
631 else
633 int const foe_kind = orb_params->forward_once_exception();
634 int const ex_id = excep_for_type (type_id.in ());
636 // this logic is a little confusing but prior to Jul 24 2009, TRANSIENT,
637 // OBJ_ADAPTER, NO_RESPONSE, and COMM_FAILURE were always retried if possible.
638 // Later, the ForwardOnceOn* were added, which reverts to default behavior
639 // when not set.
640 if ((CORBA::CompletionStatus) completion != CORBA::COMPLETED_YES)
642 switch (ex_id)
644 case TAO::FOE_TRANSIENT:
645 case TAO::FOE_COMM_FAILURE:
646 retry_on_exception = (foe_kind & ex_id) == 0;
647 break;
648 case TAO::FOE_OBJ_ADAPTER:
649 case TAO::FOE_NO_RESPONSE:
650 retry_on_exception = true;
651 break;
652 case TAO::FOE_OBJECT_NOT_EXIST:
653 retry_on_exception = orb_params->forward_invocation_on_object_not_exist ();
654 break;
655 default:
656 break;
658 if (!retry_on_exception)
660 do_forward = !this->stub ()->forwarded_on_exception () &&
661 ((foe_kind & ex_id) == ex_id);
666 if (retry_on_exception || do_forward)
668 // If we are here then possibly we'll need a restart.
669 mon.set_status (TAO_INVOKE_RESTART);
671 if (TAO_debug_level > 4)
672 TAOLIB_DEBUG ((LM_DEBUG,
673 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
674 ACE_TEXT ("handle_system_exception, profile forwarding ")
675 ACE_TEXT ("on exception %C \n"),
676 type_id.in ()));
678 if (do_forward)
679 this->stub ()->forwarded_on_exception (true);
681 // Start the special case for FTCORBA.
683 * There has been a unanimous view that this is not the
684 * right way to do things. But a need to be compliant is
685 * forcing us into this.
687 Invocation_Status const s =
688 this->stub ()->orb_core ()->service_raise_transient_failure (
689 this->details_.request_service_context ().service_info (),
690 this->resolver_.profile ());
692 if (s == TAO_INVOKE_RESTART)
693 return s;
695 // Attempt profile retry.
697 * @note A location forwarding loop may occur where a client
698 * is bounced from the original target to the forwarded
699 * target and back if the application is not equipped to
700 * handle retries of previously called targets. TAO may
701 * be able to help in this case but it ultimately ends
702 * up being an application issue.
704 if (completion != CORBA::COMPLETED_MAYBE &&
705 this->resolver_.stub ()->next_profile_retry ())
707 return TAO_INVOKE_RESTART;
710 // Fall through and raise an exception.
711 mon.set_status (TAO_INVOKE_FAILURE);
714 CORBA::SystemException *ex = TAO::create_system_exception (type_id.in ());
716 if (ex == nullptr)
718 // @@ We should raise a CORBA::NO_MEMORY, but we ran out
719 // of memory already. We need a pre-allocated, TSS,
720 // CORBA::NO_MEMORY instance
721 ACE_NEW_RETURN (ex,
722 CORBA::UNKNOWN,
723 TAO_INVOKE_FAILURE);
726 // Without this, the call to create_system_exception() above
727 // causes a memory leak. On platforms without native exceptions,
728 // the CORBA::Environment class manages the memory.
729 std::unique_ptr<CORBA::SystemException> safety (ex);
731 ex->minor (minor);
732 ex->completed (CORBA::CompletionStatus (completion));
734 if (TAO_debug_level > 4)
735 TAOLIB_DEBUG ((LM_DEBUG,
736 ACE_TEXT ("TAO (%P|%t) - Synch_Twoway_Invocation::")
737 ACE_TEXT ("handle_system_exception, about to raise\n")));
739 mon.set_status (TAO_INVOKE_SYSTEM_EXCEPTION);
741 // Raise the exception.
742 ex->_raise ();
744 return TAO_INVOKE_SYSTEM_EXCEPTION;
747 // =========================================================================
749 Synch_Oneway_Invocation::Synch_Oneway_Invocation (
750 CORBA::Object_ptr otarget,
751 Profile_Transport_Resolver &r,
752 TAO_Operation_Details &d)
753 : Synch_Twoway_Invocation (otarget, r, d, false)
757 Invocation_Status
758 Synch_Oneway_Invocation::remote_oneway (ACE_Time_Value *max_wait_time)
760 TAO::ORB_Countdown_Time countdown (max_wait_time);
762 CORBA::Octet const response_flags = this->details_.response_flags ();
764 Invocation_Status s = TAO_INVOKE_FAILURE;
766 if (response_flags == CORBA::Octet (Messaging::SYNC_WITH_SERVER) ||
767 response_flags == CORBA::Octet (Messaging::SYNC_WITH_TARGET))
769 s = Synch_Twoway_Invocation::remote_twoway (max_wait_time);
771 return s;
774 #if TAO_HAS_INTERCEPTORS == 1
775 s = this->send_request_interception ();
777 if (s != TAO_INVOKE_SUCCESS)
778 return s;
782 #endif /*TAO_HAS_INTERCEPTORS */
783 TAO_Transport* const transport = this->resolver_.transport ();
785 if (!transport)
787 if (this->retry_state_ &&
788 this->retry_state_->forward_on_exception_increment(FOE_TRANSIENT))
790 if (TAO_debug_level > 0)
791 TAOLIB_DEBUG ((LM_INFO,
792 ACE_TEXT ("TAO (%P|%t) - Synch_Oneway_Invocation::")
793 ACE_TEXT ("remote_oneway retrying on TRANSIENT ")
794 ACE_TEXT ("exception\n")));
795 this->retry_state_->next_profile_retry (*this->stub ());
796 return TAO_INVOKE_RESTART;
798 else
800 // Way back, we failed to find a profile we could connect to.
801 // We've come this far only so we reach the interception points
802 // in case they can fix things. Time to bail....
803 throw CORBA::TRANSIENT (CORBA::OMGVMCID | 2, CORBA::COMPLETED_NO);
807 else
809 ACE_GUARD_RETURN (TAO_SYNCH_MUTEX, ace_mon, transport->output_cdr_lock (),
810 TAO_INVOKE_FAILURE);
812 TAO_OutputCDR &cdr = transport->out_stream ();
815 CDR_Byte_Order_Guard cdr_guard (cdr, this->_tao_byte_order ());
817 cdr.message_attributes (this->details_.request_id (),
818 this->resolver_.stub (),
819 TAO_Message_Semantics (TAO_Message_Semantics::
820 TAO_ONEWAY_REQUEST),
821 max_wait_time);
823 this->write_header (cdr);
825 this->marshal_data (cdr);
827 countdown.update ();
829 if (transport->is_connected ())
831 // We have a connected transport so we can send the message
832 s = this->send_message (cdr,
833 TAO_Message_Semantics (TAO_Message_Semantics::
834 TAO_ONEWAY_REQUEST),
835 max_wait_time);
837 if (transport->wait_strategy ()->non_blocking () == 0 &&
838 transport->orb_core ()->client_factory ()->use_cleanup_options ())
840 if (!transport->wait_strategy ()->is_registered())
842 ACE_Event_Handler * const eh =
843 transport->event_handler_i ();
845 ACE_Reactor * const r =
846 transport->orb_core ()->reactor ();
848 if (r->register_handler (eh, ACE_Event_Handler::READ_MASK) == -1)
850 if (TAO_debug_level > 0)
851 TAOLIB_ERROR ((LM_ERROR,
852 ACE_TEXT ("TAO (%P|%t) - Synch_Oneway_Invocation::")
853 ACE_TEXT ("remote_oneway transport[%d] ")
854 ACE_TEXT ("registration withreactor ")
855 ACE_TEXT ("returned an error\n"),
856 transport->id ()));
858 else
860 // Only set this flag when registration succeeds
861 transport->wait_strategy ()->is_registered (true);
867 else
869 if (TAO_debug_level > 4)
870 TAOLIB_DEBUG ((LM_DEBUG,
871 ACE_TEXT ("TAO (%P|%t) - Synch_Oneway_Invocation::")
872 ACE_TEXT ("remote_oneway, queueing message\n")));
874 if (transport->format_queue_message (cdr,
875 max_wait_time,
876 this->resolver_.stub()) != 0)
878 s = TAO_INVOKE_FAILURE;
881 } // CDR_Byte_Order_Guard
884 #if TAO_HAS_INTERCEPTORS == 1
885 s = this->receive_other_interception ();
887 catch ( ::CORBA::Exception& ex)
889 PortableInterceptor::ReplyStatus const status =
890 this->handle_any_exception (&ex);
892 if (status == PortableInterceptor::LOCATION_FORWARD ||
893 status == PortableInterceptor::TRANSPORT_RETRY)
894 s = TAO_INVOKE_RESTART;
895 else if (status == PortableInterceptor::SYSTEM_EXCEPTION
896 || status == PortableInterceptor::USER_EXCEPTION)
897 throw;
899 catch (...)
901 // Notify interceptors of non-CORBA exception, and propagate
902 // that exception to the caller.
904 PortableInterceptor::ReplyStatus const st =
905 this->handle_all_exception ();
907 if (st == PortableInterceptor::LOCATION_FORWARD ||
908 st == PortableInterceptor::TRANSPORT_RETRY)
909 s = TAO_INVOKE_RESTART;
910 else
911 throw;
913 #endif /* TAO_HAS_INTERCEPTORS */
915 return s;
919 TAO_END_VERSIONED_NAMESPACE_DECL