summaryrefslogtreecommitdiff
path: root/TAO/tao/Invocation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/tao/Invocation.cpp')
-rw-r--r--TAO/tao/Invocation.cpp1138
1 files changed, 0 insertions, 1138 deletions
diff --git a/TAO/tao/Invocation.cpp b/TAO/tao/Invocation.cpp
deleted file mode 100644
index 5a4b170c5ff..00000000000
--- a/TAO/tao/Invocation.cpp
+++ /dev/null
@@ -1,1138 +0,0 @@
-// $Id$
-
-#include "tao/corba.h"
-
-#include "tao/Timeprobe.h"
-
-#if !defined (__ACE_INLINE__)
-# include "tao/Invocation.i"
-#endif /* ! __ACE_INLINE__ */
-
-ACE_RCSID(tao, Invocation, "$Id$")
-
-#if defined (ACE_ENABLE_TIMEPROBES)
-
- static const char *TAO_Invocation_Timeprobe_Description[] =
-{
- "GIOP_Invocation::start - enter",
- "GIOP_Invocation::start - leave",
- "GIOP_Invocation::start - connect",
- "GIOP_Invocation::start - start_msg",
- "GIOP_Invocation::start - request_hdr"
-};
-
-enum
-{
- TAO_GIOP_INVOCATION_START_ENTER = 1000,
- TAO_GIOP_INVOCATION_START_LEAVE,
- TAO_GIOP_INVOCATION_START_CONNECT,
- TAO_GIOP_INVOCATION_START_START_MSG,
- TAO_GIOP_INVOCATION_START_REQUEST_HDR
-};
-
-
-// Setup Timeprobes
-ACE_TIMEPROBE_EVENT_DESCRIPTIONS (TAO_Invocation_Timeprobe_Description,
- TAO_GIOP_INVOCATION_START_ENTER);
-
-#endif /* ACE_ENABLE_TIMEPROBES */
-
-// Normal invocations don't involve any heap al; messages are
-// constructed into stack-based buffers and are read into those
-// buffers too. Larger buffers are heap-allocated as needed.
-//
-// The constraint on request IDs is that no two requests from the same
-// client with the same ID are outstanding at the same time. In
-// single threaded environments, this is met by any number whatever.
-// When multiple threads are used, we eliminate the need for any
-// locked state by using the thread ID as the request ID, since any
-// given thread has at most one request outstanding at a time.
-//
-// NOTE: this means that if "deferred synchronous" calls get
-// supported, it's done by creating a thread internally to make the
-// call. That is less disruptive (and error prone) in general than
-// restructuring an ORB core in terms of asynchrony.
-
-TAO_GIOP_Invocation::TAO_GIOP_Invocation (IIOP_Object *data,
- const char *operation,
- TAO_ORB_Core* orb_core)
- : data_ (data),
- opname_ (operation),
- my_request_id_ (0),
- out_stream_ (buffer, sizeof buffer, /* CDR::DEFAULT_BUFSIZE */
- TAO_ENCAP_BYTE_ORDER,
- TAO_Marshal::DEFAULT_MARSHAL_FACTORY,
- orb_core->output_cdr_buffer_allocator (),
- orb_core->output_cdr_dblock_allocator ()),
- orb_core_ (orb_core)
-{
- // @@ TODO The comments here are scary, can someone please give me a
- // warm fuzzy feeling about this (coryan).
-
- // The assumption that thread ids are ints is false and horribly
- // implementation-dependent, so this code just sucks. But, at least
- // it will compile on multiple platforms through the magic of ACE
- // :-/
-
- //assert (sizeof (CORBA::ULong) == sizeof (ACE_thread_t));
- ACE_thread_t me = ACE_OS::thr_self ();
-
- // Copy in only as many bytes are valid, or only as many as we have
- // room for, whichever is less. -------> What a friggin' HACK!?!?!
- ACE_OS::memcpy (&this->my_request_id_,
- &me,
- ACE_MIN (sizeof (me), sizeof (this->my_request_id_)));
-}
-
-TAO_GIOP_Invocation::~TAO_GIOP_Invocation (void)
-{
- if (this->data_->handler () != 0)
- this->data_->handler ()->idle ();
-}
-
-// The public API involves creating an invocation, starting it, filling
-// in request parameters, actually performing the invocation, getting
-// response parameters, and then cleaning up. Sometimes they must be
-// restarted (e.g. request forwarding). This is the start/restart entry.
-
-void
-TAO_GIOP_Invocation::start (CORBA::Boolean is_roundtrip,
- TAO_GIOP::Message_Type message_type,
- CORBA::Environment &TAO_IN_ENV)
-{
- ACE_FUNCTION_TIMEPROBE (TAO_GIOP_INVOCATION_START_ENTER);
-
- // First try to bind to the appropriate address. We do that here
- // since we may get forwarded to a different objref in the course of
- // any given call, with new start () call each time. It's not
- // cached in the objref data since the connections change
- // asynchronously from objref invocations and this simplifies
- // connection management.
- // We also need to bind *before* marshalling, because different
- // Profiles have different ObjectKeys, thus a change of Profile can
- // result in different alignment for the buffer.
- //
- // THREADING NOTE: this connection is reserved to this call. Also,
- // starting at this point in the call, new forwarding information
- // will not be used until/unless the call is reissued. Correctness
- // is not affected, the call will just be forwarded later than it
- // might be in a more complex implementation.
-
- // @@ assert is evil, it crashes the program, changed to an
- // exception (coryan)
- // assert (this->data_ != 0);
-
- if (this->data_ == 0)
- TAO_THROW (CORBA::MARSHAL (CORBA::COMPLETED_NO));
-
- // Get a pointer to the connector, which might be in thread-specific
- // storage, depending on the concurrency model.
- TAO_CONNECTOR *con = this->orb_core_->connector ();
-
- // Determine the object key and the address to which we'll need a
- // connection.
- const TAO_opaque *key;
- ACE_INET_Addr *server_addr_p = 0;
-
- {
- ACE_MT (ACE_GUARD (ACE_Lock, guard, data_->get_fwd_profile_lock ()));
-
- if (data_->get_fwd_profile_i () != 0)
- {
- key = &data_->get_fwd_profile_i ()->object_key;
- server_addr_p = &data_->get_fwd_profile_i ()->object_addr ();
- }
- else
- {
- key = &data_->profile.object_key;
- server_addr_p = &data_->profile.object_addr ();
- }
- }
-
- if (server_addr_p == 0)
- TAO_THROW (CORBA::INTERNAL (CORBA::COMPLETED_NO));
-
- // Establish the connection and get back a
- // <Client_Connection_Handler>.
-#if defined (TAO_ARL_USES_SAME_CONNECTOR_PORT)
- if (this->orb_core_->arl_same_port_connect ())
- {
- ACE_INET_Addr local_addr (this->orb_core_->orb_params ()->addr ());
- local_addr.set_port_number (server_addr_p->get_port_number ());
-
- // Set the local port number to use.
-
- if (con->connect (this->data_->handler (),
- *server_addr_p,
- 0,
- local_addr,
- 1) == -1)
- {
- // Give users a clue to the problem.
- ACE_DEBUG ((LM_ERROR, "(%P|%t) %s:%u, connection to "
- "%s (%s):%hu failed (%p) (using local port #: %d)\n",
- __FILE__,
- __LINE__,
- server_addr_p->get_host_name (),
- server_addr_p->get_host_addr (),
- server_addr_p->get_port_number (),
- local_addr.get_port_number (),
- "errno"));
-
- TAO_THROW (CORBA::TRANSIENT (CORBA::COMPLETED_NO));
- }
- }
- else
-#endif /* TAO_ARL_USES_SAME_CONNECTOR_PORT */
- if (con->connect (this->data_->handler (),
- *server_addr_p) == -1)
- {
- // Give users a clue to the problem.
- if (TAO_orbdebug)
- ACE_DEBUG ((LM_ERROR, "(%P|%t) %s:%u, connection to "
- "%s (%s):%hu failed (%p)\n",
- __FILE__,
- __LINE__,
- server_addr_p->get_host_name (),
- server_addr_p->get_host_addr (),
- server_addr_p->get_port_number (),
- "errno"));
-
- TAO_THROW (CORBA::TRANSIENT (CORBA::COMPLETED_NO));
- }
-
- ACE_TIMEPROBE (TAO_GIOP_INVOCATION_START_CONNECT);
-
- // Use the TAO_SOCK_Stream from the Client_Connection_Handler for
- // communication inplace of the endpoint used below.
-
- // POLICY DECISION: If the client expects most agents to forward,
- // then it could try to make sure that it's been forwarded at least
- // once by eliciting it with a LocateRequest message. (Further
- // hinting in the IIOP::ProfileData could help!)
- //
- // That scenario does not match an "Inter" ORB Protocol well, since
- // bridges chain calls rather than forwarding them. It does match
- // some kinds of "Intra" ORB scenarios well, with many agents that
- // spawn new processes talking to their clients across the net.
- //
- // At this time, the policy noted above is followed in the sense
- // that this software does NOT expect most agents to forward, so it
- // doesn't bother to probe. Correctness is not affected; this is
- // only a quality-of-service policy. It affects mostly performance,
- // but the "best efforts" semantics for "oneway" messages would also
- // be impacted in that some (by definition, buggy!) code which used
- // only "oneway" messages might not work at all.
-
- // Build the outgoing message, starting with generic GIOP header.
-
- CORBA::Boolean bt =
- TAO_GIOP::start_message (message_type,
- this->out_stream_,
- this->orb_core_);
-
- if (bt != 1)
- TAO_THROW (CORBA::MARSHAL (CORBA::COMPLETED_NO));
-
- ACE_TIMEPROBE (TAO_GIOP_INVOCATION_START_START_MSG);
-
- // Then fill in the rest of the RequestHeader
- //
- // The first element of header is service context list;
- // transactional context would be acquired here using the
- // transaction service APIs. Other kinds of context are as yet
- // undefined.
- //
- // Last element of request header is the principal; no portable way
- // to get it, we just pass empty principal (convention: indicates
- // "anybody"). Steps upward in security include passing an
- // unverified user ID, and then verifying the message (i.e. a dummy
- // service context entry is set up to hold a digital signature for
- // this message, then patched shortly before it's sent).
- static CORBA::Principal_ptr principal = 0;
-
- // This static is only used to write into the CDR stream, once we
- // have real service context (needed for the messaging spec) this
- // will have to be a parameter.
- static TAO_GIOP_ServiceContextList svc_ctx;
-
- switch (message_type)
- {
- case TAO_GIOP::Request:
-
- this->write_request_header (svc_ctx,
- this->my_request_id_,
- is_roundtrip,
- key,
- this->opname_,
- principal);
- break;
-
- case TAO_GIOP::LocateRequest:
- this->out_stream_ << this->my_request_id_;
- this->out_stream_ << *key;
- break;
-
- default:
- TAO_THROW (CORBA::INTERNAL (CORBA::COMPLETED_NO));
- }
- if (!this->out_stream_.good_bit ())
- TAO_THROW (CORBA::MARSHAL (CORBA::COMPLETED_NO));
-
- ACE_TIMEPROBE (TAO_GIOP_INVOCATION_START_REQUEST_HDR);
-}
-
-CORBA::Boolean
-TAO_GIOP_Invocation::write_request_header_std
- (const TAO_GIOP_ServiceContextList& svc_ctx,
- CORBA::ULong request_id,
- CORBA::Boolean is_roundtrip,
- const TAO_opaque* key,
- const char* opname,
- CORBA::Principal_ptr principal)
-{
- this->out_stream_ << svc_ctx;
- this->out_stream_ << request_id;
- this->out_stream_ << CORBA::Any::from_boolean (is_roundtrip);
- this->out_stream_ << *key;
- this->out_stream_ << opname;
- this->out_stream_ << principal;
- return 1;
-}
-
-CORBA::Boolean
-TAO_GIOP_Invocation::write_request_header_lite
- (const TAO_GIOP_ServiceContextList&,
- CORBA::ULong request_id,
- CORBA::Boolean is_roundtrip,
- const TAO_opaque* key,
- const char* opname,
- CORBA::Principal_ptr)
-{
- this->out_stream_ << request_id;
- this->out_stream_ << CORBA::Any::from_boolean (is_roundtrip);
- this->out_stream_ << *key;
- this->out_stream_ << opname;
- return 1;
-}
-
-CORBA::Boolean
-TAO_GIOP_Invocation::write_request_header
- (const TAO_GIOP_ServiceContextList& svc_ctx,
- CORBA::ULong request_id,
- CORBA::Boolean is_roundtrip,
- const TAO_opaque* key,
- const char* opname,
- CORBA::Principal_ptr principal)
-{
- if (this->orb_core_->orb_params ()->use_IIOP_lite_protocol ())
- return this->write_request_header_lite (svc_ctx,
- request_id,
- is_roundtrip,
- key,
- opname,
- principal);
- else
- return this->write_request_header_std (svc_ctx,
- request_id,
- is_roundtrip,
- key,
- opname,
- principal);
-}
-
-
-// Send request, block until any reply comes back, and unmarshal reply
-// parameters as appropriate.
-
-TAO_GIOP_ReplyStatusType
-TAO_GIOP_Invocation::invoke (CORBA::Boolean is_roundtrip,
- CORBA::Environment &TAO_IN_ENV)
-{
- // Send Request, return on error or if we're done
-
- if (this->data_->handler ()->send_request (this->orb_core_,
- this->out_stream_,
- is_roundtrip) == -1)
- {
- // send_request () closed the connection; we just set the
- // handler to 0 here.
- this->data_->reset_handler ();
-
- //
- // @@ highly desirable to know whether we wrote _any_ data; if
- // we wrote none, then there's no chance the call completed and
- // applications don't have to deal with those nasty
- // indeterminate states where they can't immediatly tell if
- // what's safe to do.
- //
- // @@ also, there might have been a GIOP::CloseConnection
- // message in the input queue. If so, this request should be
- // treated as a (full) "rebind" case. Can't do that from this
- // point in the code however! Some minor restructuring needs to
- // happen.
- //
- TAO_THROW_RETURN (CORBA::TRANSIENT (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
- return TAO_GIOP_NO_EXCEPTION;
-}
-
-// ****************************************************************
-
-TAO_GIOP_ReplyStatusType
-TAO_GIOP_Invocation::close_connection (void)
-{
- // Special case of forwarding -- server was closing the
- // connection, which just indicates resource constraints, not an
- // error. The client is effectively "forwarded" to the same
- // server!
- //
- // However, we must reinitialize the forwarding chain, since the
- // resource being reclaimed might also have been the process,
- // not just the connection. Without reinitializing, we'd give
- // false error reports to applications.
- {
- ACE_MT (ACE_GUARD_RETURN (ACE_Lock,
- guard,
- data_->get_fwd_profile_lock (),
- TAO_GIOP_SYSTEM_EXCEPTION));
-
- IIOP::Profile *old = data_->set_fwd_profile (0);
- delete old;
- // sets the forwarding profile to 0 and deletes the old one;
-
- data_->reset_first_locate_request ();
- // resets the flag of the first call locate request to true
- }
-
- this->data_->handler ()->handle_close ();
- this->data_->reset_handler ();
- return TAO_GIOP_LOCATION_FORWARD;
-}
-
-
-// Handle the GIOP Reply with status = LOCATION_FORWARD
-// Replace the IIOP Profile. The call is then automatically
-// reinvoked by the IIOP_Object::do_static_call method.
-
-TAO_GIOP_ReplyStatusType
-TAO_GIOP_Invocation::location_forward (TAO_InputCDR &inp_stream,
- CORBA::Environment &TAO_IN_ENV)
-{
- // It can be assumed that the GIOP header and the reply header
- // are already handled. Further it can be assumed that the
- // reply body contains an object reference to the new object.
- // This object pointer will be now extracted.
-
- CORBA::Object_ptr object_ptr = 0;
-
- TAO_TRY_VAR (TAO_IN_ENV)
- {
- inp_stream.decode (CORBA::_tc_Object,
- &(object_ptr),
- 0,
- TAO_TRY_ENV);
- TAO_CHECK_ENV;
- }
- TAO_CATCH (CORBA_SystemException, ex)
- {
- // Handle the exception for this level here and throw it out again.
- dexc (TAO_TRY_ENV, "invoke, location forward (decode)");
- this->data_->handler ()->handle_close ();
- TAO_RETHROW_SAME_ENV_RETURN (TAO_GIOP_SYSTEM_EXCEPTION);
- }
- TAO_ENDTRY;
-
- // The object pointer has to be changed to a IIOP_Object pointer
- // in order to extract the profile.
-
- IIOP_Object *iiopobj =
- ACE_dynamic_cast (IIOP_Object *, object_ptr->_stubobj ());
-
- if (iiopobj == 0)
- {
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::UNKNOWN (CORBA::COMPLETED_NO), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- // Make a copy of the IIOP profile in the forwarded objref,
- // reusing memory where practical. Then delete the forwarded
- // objref, retaining only its profile.
- //
- // @@ add and use a "forward count", to prevent loss of data
- // in forwarding chains during concurrent calls -- only a
- // forward that's a response to the current fwd_profile should
- // be recorded here. (This is just an optimization, and is not
- // related to correctness.)
-
- // the copy method on IIOP::Profile will be used to copy the content
- data_->set_fwd_profile (&iiopobj->profile);
- // store the new profile in the forwarding profile
- // note: this has to be and is thread safe
-
- // The object is no longer needed, because we have now the IIOP_Object
- // @@ Is this exception safe?
- CORBA::release (object_ptr);
-
- TAO_IN_ENV.clear ();
-
- // We may not need to do this since TAO_GIOP_Invocations
- // get created on a per-call basis. For now we'll play it safe.
-
- return TAO_GIOP_LOCATION_FORWARD;
-}
-
-// ****************************************************************
-
-TAO_GIOP_ReplyStatusType
-TAO_GIOP_Twoway_Invocation::invoke (CORBA::ExceptionList &exceptions,
- CORBA::Environment &TAO_IN_ENV)
-{
- TAO_GIOP_ReplyStatusType retval =
- TAO_GIOP_Invocation::invoke (1, TAO_IN_ENV);
- TAO_CHECK_RETURN (retval);
- ACE_UNUSED_ARG (retval);
-
- // This blocks until the response is read. In the current version,
- // there is only one client thread that ever uses this connection,
- // so most response messages are illegal.
- //
- // THREADING NOTE: to make more efficient use of connection
- // resources, we'd multiplex I/O on connections. For example, one
- // thread would write its GIOP::Request (or GIOP::LocateRequest etc)
- // message and block for the response, then another would do the
- // same thing. When a response came back, it would be handed to the
- // thread which requested it.
- //
- // Currently the connection manager doesn't support such fine
- // grained connection locking, and also this server implementation
- // wouldn't take advantage of that potential concurrency in requests
- // either. There are often performance losses coming from
- // fine-grained locks being used inappropriately; there's some
- // evidence that locking at the level of requests loses on at least
- // some platforms.
- //
- // @@ In all MT environments, there's a cancellation point lurking
- // here; need to investigate. Client threads would frequently be
- // canceled sometime during recv_request ... the correct action to
- // take on being canceled is to issue a CancelRequest message to the
- // server and then imediately let other client-side cancellation
- // handlers do their jobs.
- //
- // In C++, that basically means to unwind the stack using almost
- // normal procedures: all destructors should fire, and some "catch"
- // blocks should probably be able to handle things like releasing
- // pointers. (Without unwinding the C++ stack, resources that must
- // be freed by thread cancellation won't be freed, and the process
- // won't continue to function correctly.) The tricky part is that
- // according to POSIX, all C stack frames must also have their
- // (explicitly coded) handlers called. We assume a POSIX.1c/C/C++
- // environment.
-
- TAO_SVC_HANDLER *handler = this->data_->handler ();
- TAO_GIOP::Message_Type m = TAO_GIOP::recv_request (handler,
- this->inp_stream_,
- this->orb_core_);
-
- // suspend was called in TAO_Client_Connection_Handler::handle_input
- int result = this->orb_core_->reactor ()->resume_handler (handler);
- ACE_UNUSED_ARG (result);
- ACE_ASSERT (result == 0);
-
- switch (m)
- {
- case TAO_GIOP::Reply:
- // handle reply ... must be right one etc
- break;
-
- case TAO_GIOP::CloseConnection:
- return (TAO_GIOP_Invocation::close_connection ());
-
- case TAO_GIOP::Request:
- case TAO_GIOP::CancelRequest:
- case TAO_GIOP::LocateRequest:
- case TAO_GIOP::LocateReply:
- default:
- // These are all illegal messages to find. If found, they could
- // be indicative of client bugs (lost track of input stream) or
- // server bugs; maybe the request was acted on, maybe not, we
- // can't tell.
- ACE_DEBUG ((LM_DEBUG,
- "(%P|%t) illegal GIOP message (%s) in response to my Request!\n",
- TAO_GIOP::message_name (m)));
- // FALLTHROUGH ...
-
- case TAO_GIOP::CommunicationError:
- case TAO_GIOP::MessageError:
- // Couldn't read it for some reason ... exception's set already,
- // so just tell the other end about the trouble (closing the
- // connection) and return.
-
- // FALLTHROUGH
-
- case TAO_GIOP::EndOfFile:
- // @@ This should only refer to "getting GIOP MessageError" message only.
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- // Process reply message. Again, due to the single threading in
- // this code, only the reply to this request is allowed to be coming
- // back.
- //
- // NOTE: if the response really _isn't_ for this thread, it's now
- // treated as an error in which synchronization can't be recovered.
- // There might be cases where it _could_ be recovered ... e.g. maybe
- // for some reason the previous call couldn't pick up its response.
- // It'd be worth investigating (and handling) any such cases.
- //
- // NOTE: since this implementation supports no ORB services
- // (notably, the transaction service, which is the only one that's
- // currently defined), the reply context is discarded. Normally
- // it'd be fed, component at a time, to the relevant services.
- //
- // NOTE: As security support kicks in, this is the right place to
- // verify a digital signature, if that is required in this
- // particular runtime security environment. How to know if that's
- // the case? It's likely that standard Internet IPSEC
- // infrastructure (RFC 1825 through 1827, and successors) will be
- // used to enforce many security policies; integrity and privacy
- // guarantees may be provided by the network, and need no support
- // here.
-
- TAO_GIOP_ServiceContextList reply_ctx;
- CORBA::ULong request_id;
- CORBA::ULong reply_status; // TAO_GIOP_ReplyStatusType
-
- this->inp_stream_ >> reply_ctx;
- if (!this->inp_stream_.good_bit ())
- {
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::MARSHAL (CORBA::COMPLETED_NO), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- if (!this->inp_stream_.read_ulong (request_id)
- || request_id != this->my_request_id_
- || !this->inp_stream_.read_ulong (reply_status)
- || reply_status > TAO_GIOP_LOCATION_FORWARD)
- {
- this->data_->handler ()->handle_close ();
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) bad Response header\n"));
- TAO_THROW_RETURN (CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- // If there was no exception, let the caller parse the normal
- // response. Otherwise parse and handle the response; we always
- // know how to deal with the standard exceptions, and the caller
- // provides a list of allowed user-defined exceptions so that we
- // know how to unmarshal those too (without IFR consultation).
- //
- // When requests are forwarded, we just store the revised profile
- // data in this objref structure. The expectation is that the call
- // will be reissued until someone gives up on a forwarding chain,
- // and that other calls will reap the benefit of the forwarding work
- // by this thread.
- //
- // NOTE: should ensure that from here on, all system exceptions
- // return COMPLETED_YES status ... even ones reported by code which
- // we call.
-
- switch (reply_status)
- {
- case TAO_GIOP_NO_EXCEPTION:
- break;
-
- case TAO_GIOP_USER_EXCEPTION:
- case TAO_GIOP_SYSTEM_EXCEPTION:
- {
- // @@ TODO This code is not exception safe. Notice how on
- // every exit path we have to invoke TAO_GIOP::send_error,
- // this should be handled by the destructor of some class;
- // which is disabled on the normal exit paths.
- // Plus <buf> should be stored in a CORBA::String_var
-
- char* buf;
- CORBA::String_var buf_holder; // Used to clean up dynamic allocated string
- // in <buf>.
-
- // Pull the exception ID out of the marshaling buffer.
- {
- if (this->inp_stream_.read_string (buf) == 0)
- {
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::MARSHAL (CORBA::COMPLETED_YES), TAO_GIOP_SYSTEM_EXCEPTION);
- }
- }
-
- buf_holder = buf; // Assume ownership of <buf>
-
- if (reply_status == TAO_GIOP_SYSTEM_EXCEPTION)
- {
- CORBA_Exception *exception =
- TAO_Exceptions::create_system_exception (buf_holder.in (), TAO_IN_ENV);
- TAO_CHECK_RETURN (TAO_GIOP_SYSTEM_EXCEPTION);
-
- if (exception != 0)
- {
- this->inp_stream_.decode (exception->_type (),
- &exception, 0,
- TAO_IN_ENV);
- TAO_CHECK_RETURN (TAO_GIOP_SYSTEM_EXCEPTION)
-;
- TAO_IN_ENV.exception (exception);
- return TAO_GIOP_SYSTEM_EXCEPTION;
- }
- else
- {
- // @@ TODO We should have policies to handle this
- // error, for instance:
- // + the spec requires us to silently raise a
- // CORBA::UNKNOWN exception
- // + Don't print a message and try
- // + Print the message and try
- // + Print the message and rasize CORBA::UNKNOWN
- ACE_ERROR ((LM_ERROR,
- "Received Reply with SYSTEM_EXCEPTION "
- "status, but unknown or invalid "
- "exception.\n"
- "Trying to interpret as a user exception"));
- }
- }
- {
- // Find it in the operation description and then use that
- // to get the typecode.
- // This is important to decode the exception.
-
- for (CORBA::ULong i = 0;
- i < exceptions.count ();
- i++)
- {
- CORBA::TypeCode_ptr tcp = 0;
- int loop_continue = 0;
- TAO_TRY
- {
- tcp = exceptions.item (i, TAO_IN_ENV);
- TAO_CHECK_ENV;
-
- const char *xid = tcp->id (TAO_IN_ENV);
- TAO_CHECK_ENV;
-
- if (ACE_OS::strcmp (buf_holder.in (), xid) != 0)
- loop_continue = 1;
- }
- TAO_CATCH (CORBA_SystemException, ex)
- {
- this->data_->handler ()->handle_close ();
- TAO_RETHROW_SAME_ENV_RETURN (TAO_GIOP_SYSTEM_EXCEPTION);
- }
- TAO_ENDTRY;
- if (loop_continue)
- continue;
-
- const ACE_Message_Block* cdr =
- this->inp_stream_.start ();
- CORBA_Any any (tcp, cdr);
- CORBA_Exception *exception =
- new CORBA_UnknownUserException (any);
- TAO_IN_ENV.exception (exception);
- return TAO_GIOP_USER_EXCEPTION;
- }
- }
-
- // If we couldn't find the right exception, report it as
- // CORBA::UNKNOWN.
-
- TAO_THROW_RETURN (CORBA::UNKNOWN (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
- // NOTREACHED
-
- case TAO_GIOP_LOCATION_FORWARD:
- return (this->location_forward (this->inp_stream_, TAO_IN_ENV));
- }
-
- // All standard exceptions from here on in the call path know for
- // certain that the call "completed" ... except in the case of
- // system exceptions which say otherwise, and for
- // TAO_GIOP_LOCATION_FORWARD responses.
-
- return (TAO_GIOP_ReplyStatusType) reply_status;
-}
-
-// Send request, block until any reply comes back, and unmarshal reply
-// parameters as appropriate.
-//
-// This invoke method is for the stubs to use
-
-TAO_GIOP_ReplyStatusType
-TAO_GIOP_Twoway_Invocation::invoke (TAO_Exception_Data *excepts,
- CORBA::ULong except_count,
- CORBA::Environment &TAO_IN_ENV)
-{
- TAO_GIOP_ReplyStatusType retval =
- TAO_GIOP_Invocation::invoke (1, TAO_IN_ENV);
- TAO_CHECK_RETURN (retval);
- ACE_UNUSED_ARG (retval);
-
- // This blocks until the response is read. In the current version,
- // there is only one client thread that ever uses this connection,
- // so most response messages are illegal.
- //
- // THREADING NOTE: to make more efficient use of connection
- // resources, we'd multiplex I/O on connections. For example, one
- // thread would write its GIOP::Request (or GIOP::LocateRequest etc)
- // message and block for the response, then another would do the
- // same thing. When a response came back, it would be handed to the
- // thread which requested it.
- //
- // Currently the connection manager doesn't support such fine
- // grained connection locking, and also this server implementation
- // wouldn't take advantage of that potential concurrency in requests
- // either. There are often performance losses coming from
- // fine-grained locks being used inappropriately; there's some
- // evidence that locking at the level of requests loses on at least
- // some platforms.
- //
- // @@ In all MT environments, there's a cancellation point lurking
- // here; need to investigate. Client threads would frequently be
- // canceled sometime during recv_request ... the correct action to
- // take on being canceled is to issue a CancelRequest message to the
- // server and then imediately let other client-side cancellation
- // handlers do their jobs.
- //
- // In C++, that basically means to unwind the stack using almost
- // normal procedures: all destructors should fire, and some "catch"
- // blocks should probably be able to handle things like releasing
- // pointers. (Without unwinding the C++ stack, resources that must
- // be freed by thread cancellation won't be freed, and the process
- // won't continue to function correctly.) The tricky part is that
- // according to POSIX, all C stack frames must also have their
- // (explicitly coded) handlers called. We assume a POSIX.1c/C/C++
- // environment.
-
- TAO_SVC_HANDLER *handler = this->data_->handler ();
- TAO_GIOP::Message_Type m = TAO_GIOP::recv_request (handler,
- this->inp_stream_,
- this->orb_core_);
-
- // suspend was called in TAO_Client_Connection_Handler::handle_input
- int result = this->orb_core_->reactor ()->resume_handler (handler);
- ACE_UNUSED_ARG (result);
- ACE_ASSERT (result == 0);
-
- switch (m)
- {
- case TAO_GIOP::Reply:
- // handle reply ... must be right one etc
- break;
-
- case TAO_GIOP::CloseConnection:
- return (TAO_GIOP_Invocation::close_connection ());
-
- case TAO_GIOP::Request:
- case TAO_GIOP::CancelRequest:
- case TAO_GIOP::LocateRequest:
- case TAO_GIOP::LocateReply:
- default:
- // These are all illegal messages to find. If found, they could
- // be indicative of client bugs (lost track of input stream) or
- // server bugs; maybe the request was acted on, maybe not, we
- // can't tell.
- ACE_DEBUG ((LM_DEBUG,
- "(%P|%t) illegal GIOP message (%s) in response to my Request!\n",
- TAO_GIOP::message_name (m)));
- // FALLTHROUGH ...
-
- case TAO_GIOP::CommunicationError:
- case TAO_GIOP::MessageError:
- // Couldn't read it for some reason ... exception's set already,
- // so just tell the other end about the trouble (closing the
- // connection) and return.
-
- // FALLTHROUGH
-
- case TAO_GIOP::EndOfFile:
- // @@ This should only refer to "getting GIOP MessageError" message only.
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- // Process reply message. Again, due to the single threading in
- // this code, only the reply to this request is allowed to be coming
- // back.
- //
- // NOTE: if the response really _isn't_ for this thread, it's now
- // treated as an error in which synchronization can't be recovered.
- // There might be cases where it _could_ be recovered ... e.g. maybe
- // for some reason the previous call couldn't pick up its response.
- // It'd be worth investigating (and handling) any such cases.
- //
- // NOTE: since this implementation supports no ORB services
- // (notably, the transaction service, which is the only one that's
- // currently defined), the reply context is discarded. Normally
- // it'd be fed, component at a time, to the relevant services.
- //
- // NOTE: As security support kicks in, this is the right place to
- // verify a digital signature, if that is required in this
- // particular runtime security environment. How to know if that's
- // the case? It's likely that standard Internet IPSEC
- // infrastructure (RFC 1825 through 1827, and successors) will be
- // used to enforce many security policies; integrity and privacy
- // guarantees may be provided by the network, and need no support
- // here.
-
- TAO_GIOP_ServiceContextList reply_ctx;
- CORBA::ULong request_id;
- CORBA::ULong reply_status; // TAO_GIOP_ReplyStatusType
-
- this->inp_stream_ >> reply_ctx;
- if (!this->inp_stream_.good_bit ())
- {
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::MARSHAL (CORBA::COMPLETED_NO), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- if (!this->inp_stream_.read_ulong (request_id)
- || request_id != this->my_request_id_
- || !this->inp_stream_.read_ulong (reply_status)
- || reply_status > TAO_GIOP_LOCATION_FORWARD)
- {
- this->data_->handler ()->handle_close ();
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) bad Response header\n"));
- TAO_THROW_RETURN (CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- // If there was no exception, let the caller parse the normal
- // response. Otherwise parse and handle the response; we always
- // know how to deal with the standard exceptions, and the caller
- // provides a list of allowed user-defined exceptions so that we
- // know how to unmarshal those too (without IFR consultation).
- //
- // When requests are forwarded, we just store the revised profile
- // data in this objref structure. The expectation is that the call
- // will be reissued until someone gives up on a forwarding chain,
- // and that other calls will reap the benefit of the forwarding work
- // by this thread.
- //
- // NOTE: should ensure that from here on, all system exceptions
- // return COMPLETED_YES status ... even ones reported by code which
- // we call.
-
- switch (reply_status)
- {
- case TAO_GIOP_NO_EXCEPTION:
- break;
-
- case TAO_GIOP_USER_EXCEPTION:
- case TAO_GIOP_SYSTEM_EXCEPTION:
- {
- // @@ TODO This code is not exception safe. Notice how on
- // every exit path we have to invoke TAO_GIOP::send_error,
- // this should be handled by the destructor of some class;
- // which is disabled on the normal exit paths.
- // Plus <buf> should be stored in a CORBA::String_var
-
- char* buf;
- CORBA::String_var buf_holder; // Used to clean up dynamically allocated
- // <buf> upon exceptions or return
-
- // Pull the exception ID out of the marshaling buffer.
- {
- if (this->inp_stream_.read_string (buf) == 0)
- {
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::MARSHAL (CORBA::COMPLETED_YES), TAO_GIOP_SYSTEM_EXCEPTION);
- }
- }
-
- buf_holder = buf; // Assume ownership of <buf>
-
- // Find it in the operation description and then use that to
- // get the typecode. Use it to unmarshal the exception's
- // value; if that exception is not allowed by this operation,
- // fail (next).
-
- // placeholder to decode the exception
- CORBA::Exception *exception = 0;
- CORBA::TypeCode_ptr tcp = 0;
-
- if (reply_status == TAO_GIOP_SYSTEM_EXCEPTION)
- {
- exception =
- TAO_Exceptions::create_system_exception (buf_holder.in (), TAO_IN_ENV);
- TAO_CHECK_RETURN (TAO_GIOP_SYSTEM_EXCEPTION);
-
- if (exception != 0)
- {
- this->inp_stream_.decode (exception->_type (),
- exception, 0,
- TAO_IN_ENV);
- TAO_CHECK_RETURN (TAO_GIOP_SYSTEM_EXCEPTION);
-
- // @@ What do we do if an exception is raised while
- // demarshaling an exception????
- TAO_IN_ENV.exception (exception);
- return TAO_GIOP_SYSTEM_EXCEPTION;
- }
- }
- // else // this else is commented out, see the coment above
- {
- // search the table of exceptions and see if there is a match
- for (CORBA::ULong i = 0;
- i < except_count;
- i++)
- {
- int loop_continue = 0;
- TAO_TRY_VAR (TAO_IN_ENV)
- {
- tcp = excepts[i].tc;
- const char *xid = tcp->id (TAO_TRY_ENV);
- TAO_CHECK_ENV;
-
- if (ACE_OS::strcmp (buf_holder.in (), (char *)xid) != 0)
- loop_continue = 1;
- else
- {
- // match
- exception = excepts[i].alloc ();
-
- this->inp_stream_.decode (exception->_type (),
- exception, 0,
- TAO_TRY_ENV);
- TAO_CHECK_ENV;
- }
- }
- TAO_CATCH (CORBA_SystemException, ex)
- {
- this->data_->handler ()->handle_close ();
- TAO_RETHROW_SAME_ENV_RETURN (TAO_GIOP_SYSTEM_EXCEPTION);
- }
- TAO_ENDTRY;
- if (loop_continue)
- continue;
-
- TAO_IN_ENV.exception (exception);
- return TAO_GIOP_USER_EXCEPTION;
- } // end of loop
- }
-
- // If we couldn't find the right exception, report it as
- // CORBA::UNKNOWN.
-
- TAO_IN_ENV.exception (new CORBA::UNKNOWN (CORBA::COMPLETED_YES));
- return TAO_GIOP_SYSTEM_EXCEPTION;
- }
- // NOTREACHED
-
- case TAO_GIOP_LOCATION_FORWARD:
- return (this->location_forward (this->inp_stream_, TAO_IN_ENV));
- }
-
- // All standard exceptions from here on in the call path know for
- // certain that the call "completed" ... except in the case of
- // system exceptions which say otherwise, and for
- // TAO_GIOP_LOCATION_FORWARD responses.
-
- return (TAO_GIOP_ReplyStatusType) reply_status;
-}
-
-
-// ****************************************************************
-
-
-// Send request, block until any reply comes back
-
-TAO_GIOP_ReplyStatusType
-TAO_GIOP_Locate_Request_Invocation::invoke (CORBA::Environment &TAO_IN_ENV)
-{
- // Send Request, return on error or if we're done
-
- if (this->data_->handler ()->send_request (this->orb_core_,
- this->out_stream_,
- 1) == -1)
- {
- // send_request () closed the connection; we just set the
- // handler to 0 here.
- this->data_->reset_handler ();
- TAO_IN_ENV.exception (new CORBA::TRANSIENT (CORBA::COMPLETED_MAYBE));
- return TAO_GIOP_SYSTEM_EXCEPTION;
- }
-
- TAO_SVC_HANDLER *handler = this->data_->handler ();
- TAO_GIOP::Message_Type m = TAO_GIOP::recv_request (handler,
- this->inp_stream_,
- this->orb_core_);
-
- // suspend was called in TAO_Client_Connection_Handler::handle_input
- int result = this->orb_core_->reactor ()->resume_handler (handler);
- ACE_UNUSED_ARG (result);
- ACE_ASSERT (result == 0);
-
- switch (m)
- {
- case TAO_GIOP::CloseConnection:
- return (this->close_connection ());
-
- case TAO_GIOP::LocateReply:
- // Handle the reply
- // Especially set the new location
-
- CORBA::ULong request_id;
- CORBA::ULong locate_status; // TAO_GIOP_LocateStatusType
-
- if (!this->inp_stream_.read_ulong (request_id)
- || request_id != this->my_request_id_
- || !this->inp_stream_.read_ulong (locate_status))
- {
- this->data_->handler ()->handle_close ();
- ACE_DEBUG ((LM_DEBUG,
- "(%P|%t) bad Response header\n"));
- TAO_THROW_RETURN (CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
- switch (locate_status)
- {
- case TAO_GIOP_UNKNOWN_OBJECT:
- TAO_THROW_RETURN (CORBA::OBJECT_NOT_EXIST (CORBA::COMPLETED_YES), TAO_GIOP_SYSTEM_EXCEPTION);
- /* not reached */
- case TAO_GIOP_OBJECT_HERE:
- return TAO_GIOP_NO_EXCEPTION;
- /* not reached */
- case TAO_GIOP_OBJECT_FORWARD:
- return (this->location_forward (this->inp_stream_, TAO_IN_ENV));
- /* not reached */
- }
- /* not reached */
- case TAO_GIOP::Reply:
- case TAO_GIOP::Request:
- case TAO_GIOP::CancelRequest:
- case TAO_GIOP::LocateRequest:
- default:
- // These are all illegal messages to find. If found, they could
- // be indicative of client bugs (lost track of input stream) or
- // server bugs; maybe the request was acted on, maybe not, we
- // can't tell.
- ACE_DEBUG ((LM_DEBUG,
- "(%P|%t) illegal GIOP message (%s) in response to my Request!\n",
- TAO_GIOP::message_name (m)));
- // FALLTHROUGH ...
-
- case TAO_GIOP::CommunicationError:
- case TAO_GIOP::MessageError:
- // Couldn't read it for some reason ... exception's set already,
- // so just tell the other end about the trouble (closing the
- // connection) and return.
- // FALLTHROUGH
-
- case TAO_GIOP::EndOfFile:
- // @@ This should only refer to "getting GIOP MessageError" message only.
- this->data_->handler ()->handle_close ();
- TAO_THROW_RETURN (CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE), TAO_GIOP_SYSTEM_EXCEPTION);
- }
-
- ACE_NOTREACHED (return TAO_GIOP_NO_EXCEPTION);
-}
-
-// ****************************************************************
-
-#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
-#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
-#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */