summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TAO/ChangeLog-98c26
-rw-r--r--TAO/TAO_IDL/be/be_visitor_exception.cpp8
-rw-r--r--TAO/TAO_IDL/be/be_visitor_operation.cpp19
-rw-r--r--TAO/tao/GIOP.cpp384
-rw-r--r--TAO/tao/GIOP.h8
-rw-r--r--TAO/tao/IIOP_Object.cpp5
-rw-r--r--TAO/tao/Stub.h28
7 files changed, 471 insertions, 7 deletions
diff --git a/TAO/ChangeLog-98c b/TAO/ChangeLog-98c
index 1edec8ccc56..33a1183dec4 100644
--- a/TAO/ChangeLog-98c
+++ b/TAO/ChangeLog-98c
@@ -1,3 +1,29 @@
+Fri May 1 13:05:56 1998 Aniruddha Gokhale <gokhale@mambo.cs.wustl.edu>
+
+ * tao/Stub.h: Added a new structure called TAO_Exception_Data that
+ holds the typecode and pointer to a function for the user
+ exception we are dealing with. This was necessary since the
+ interpreter had no clue of how to allocate storage for the
+ exception we are dealing with and how to decode it.
+
+ * tao/GIOP.{h, cpp}: Affected by the above change is the "invoke"
+ method which takes the list of exceptions. It is this method that
+ is responsible for allocating the right amount of storage for the
+ exceptions and decode it.
+
+ We kept the original invoke method as it is because the newer
+ signature cannot work with DII. This still needs work.
+
+ * tao/IIOP_Object.cpp:(do_static_call) - When "invoke" is called,
+ we now pass the TAO_Exception_Data table.
+
+ * TAO_IDL/be/be_visitor_operation.cpp: The exceptionlist table
+ that gets generated is now an array of TAO_Exception_Data. In
+ addition, it is made static.
+
+ * TAO_IDL/be/be_visitor_exception.cpp: Added code to generate the
+ *_alloc function that allocates memory for the exception.
+
Fri May 1 09:55:56 1998 Aniruddha Gokhale <gokhale@mambo.cs.wustl.edu>
* tao/POAS.cpp: In the initialization section of constructors for
diff --git a/TAO/TAO_IDL/be/be_visitor_exception.cpp b/TAO/TAO_IDL/be/be_visitor_exception.cpp
index 4e635804a32..63bf273dca6 100644
--- a/TAO/TAO_IDL/be/be_visitor_exception.cpp
+++ b/TAO/TAO_IDL/be/be_visitor_exception.cpp
@@ -488,6 +488,14 @@ int be_visitor_exception_cs::visit_exception (be_exception *node)
*os << "CORBA::TypeCode_ptr " << node->tc_name () << " = &_tc__tc_" <<
node->flatname () << ";\n\n";
+ // generate the _alloc method
+ os->indent ();
+ *os << "static CORBA::Exception *" << node->flatname ()
+ << "_alloc (void)" << be_nl;
+ *os << "{" << be_idt_nl;
+ *os << "return new " << node->name () << ";" << be_uidt_nl;
+ *os << "}\n\n";
+
node->cli_stub_gen (I_TRUE);
}
diff --git a/TAO/TAO_IDL/be/be_visitor_operation.cpp b/TAO/TAO_IDL/be/be_visitor_operation.cpp
index 63092b98f56..0c75e993f6a 100644
--- a/TAO/TAO_IDL/be/be_visitor_operation.cpp
+++ b/TAO/TAO_IDL/be/be_visitor_operation.cpp
@@ -345,7 +345,7 @@ be_visitor_operation_cs::visit_operation (be_operation *node)
if (node->exceptions ())
{
*os << node->exceptions ()->length ()
- << ", _tao_" << node->flatname () << "_exceptlist};\n\n";
+ << ", _tao_" << node->flatname () << "_exceptiondata};\n\n";
}
else
*os << "0, 0};\n\n";
@@ -3207,8 +3207,13 @@ be_visitor_operation_exceptlist_cs::visit_operation (be_operation *node)
if (node->exceptions ())
{
os->indent ();
- *os << "CORBA::TypeCode_ptr " << "_tao_" << node->flatname ()
+#if 0
+ *os << "static CORBA::TypeCode_ptr " << "_tao_" << node->flatname ()
<< "_exceptlist [] = {" << be_idt_nl;
+#endif
+ *os << "static TAO_Exception_Data " << "_tao_" << node->flatname ()
+ << "_exceptiondata [] = " << be_nl;
+ *os << "{" << be_idt_nl;
// initialize an iterator to iterate thru the exception list
UTL_ExceptlistActiveIterator *ei;
ACE_NEW_RETURN (ei,
@@ -3228,12 +3233,16 @@ be_visitor_operation_exceptlist_cs::visit_operation (be_operation *node)
"codegen for scope failed\n"), -1);
}
- os->indent ();
+ *os << "{";
*os << excp->tc_name ();
-
+ *os << ", ";
+ *os << excp->flatname () << "_alloc}";
ei->next ();
if (!ei->is_done ())
- *os << ",\n";
+ {
+ *os << ",\n";
+ os->indent ();
+ }
// except the last one is processed?
} // end of while loop
diff --git a/TAO/tao/GIOP.cpp b/TAO/tao/GIOP.cpp
index 0bdffa0b375..5ecf9979d7f 100644
--- a/TAO/tao/GIOP.cpp
+++ b/TAO/tao/GIOP.cpp
@@ -1058,6 +1058,390 @@ TAO_GIOP_Invocation::invoke (CORBA::ExceptionList &exceptions,
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_Invocation::invoke (TAO_Exception_Data *excepts,
+ CORBA::ULong except_count,
+ CORBA::Environment &env)
+{
+ // Send Request, return on error or if we're done
+
+ if (this->handler_->send_request (this->out_stream_,
+ this->do_rsvp_) == -1)
+ {
+ // send_request () closed the connection; we just set the
+ // handler to 0 here.
+ this->handler_ = 0;
+
+ //
+ // @@ 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.
+ //
+ env.exception (new CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE));
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+ if (!this->do_rsvp_)
+ return TAO_GIOP_NO_EXCEPTION;
+
+ // 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->handler_;
+ TAO_GIOP::Message_Type m = TAO_GIOP::recv_request (handler,
+ this->inp_stream_,
+ env);
+ switch (m)
+ {
+ case TAO_GIOP::Reply:
+ // handle reply ... must be right one etc
+ break;
+
+ case TAO_GIOP::CloseConnection:
+ // 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.
+ {
+#if 0 /* Keep this around in case forwarding is ever implemented */
+ ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard, data_->fwd_profile_lock (), TAO_GIOP_SYSTEM_EXCEPTION));
+#endif
+
+ IIOP::Profile *old = data_->fwd_profile_i (0);
+ delete old;
+
+ this->handler_->close ();
+ this->handler_ = 0;
+ return TAO_GIOP_LOCATION_FORWARD;
+ }
+
+ 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)));
+ env.exception (new CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE));
+ // FALLTHROUGH ...
+
+ 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.
+ TAO_GIOP::send_error (this->handler_);
+ return 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
+
+ if (this->inp_stream_.decode (TC_ServiceContextList, &reply_ctx, 0, env)
+ != CORBA::TypeCode::TRAVERSE_CONTINUE)
+ {
+ TAO_GIOP::send_error (this->handler_);
+ return 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)
+ {
+ TAO_GIOP::send_error (this->handler_);
+ env.exception (new CORBA::COMM_FAILURE (CORBA::COMPLETED_MAYBE));
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) bad Response header\n"));
+ return 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:
+ {
+ char* buf;
+
+ // Pull the exception ID out of the marshaling buffer.
+ {
+ if (this->inp_stream_.read_string (buf) == CORBA::B_FALSE)
+ {
+ TAO_GIOP::send_error (this->handler_);
+ env.exception (new CORBA::MARSHAL (CORBA::COMPLETED_YES));
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+ }
+
+ // 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_USER_EXCEPTION)
+ {
+ // search the table of exceptions and see if there is a match
+ for (CORBA::ULong i = 0;
+ i < except_count;
+ i++)
+ {
+ tcp = excepts[i].tc;
+ const char *xid = tcp->id (env);
+
+ if (env.exception () != 0)
+ {
+ dexc (env, "invoke (), get exception ID");
+ TAO_GIOP::send_error (this->handler_);
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+
+ if (ACE_OS::strcmp (buf, (char *)xid) == 0)
+ {
+ // match
+ exception = excepts[i].alloc ();
+
+ if (env.exception () != 0)
+ {
+ dexc (env, "invoke (), get exception size");
+ TAO_GIOP::send_error (this->handler_);
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+
+ }
+ } // end of loop
+ CORBA::string_free (buf);
+ }
+ else
+ {
+ CORBA::ExceptionList *xlist;
+ xlist = TAO_Exceptions::system_exceptions;
+
+ // 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).
+
+ for (CORBA::ULong i = 0;
+ i < xlist->count ();
+ i++)
+ {
+ tcp = xlist->item (i, env);
+ const char *xid = tcp->id (env);
+
+ if (env.exception () != 0)
+ {
+ dexc (env, "invoke (), get exception ID");
+ TAO_GIOP::send_error (this->handler_);
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+
+ if (ACE_OS::strcmp (buf, (char *)xid) == 0)
+ {
+
+ // must be a system exception
+ exception = new CORBA::SystemException (tcp,
+ (CORBA::ULong)0,
+ CORBA::COMPLETED_NO);
+ }
+ }
+ }
+
+ // If we couldn't find this exception's typecode, report it as
+ // an OA error since the skeleton passed an exception that was
+ // not allowed by the operation's IDL definition. In the case
+ // of a dynamic skeleton it's actually an implementation bug.
+ //
+ // It's known to be _very_ misleading to try reporting this as
+ // any kind of marshaling error (unless minor codes are made
+ // to be _very_ useful) ... folk try to find/fix ORB bugs that
+ // don't exist, not bugs in/near the implementation code.
+
+ if (!exception)
+ {
+ if (reply_status == TAO_GIOP_USER_EXCEPTION)
+ env.exception (new CORBA::OBJ_ADAPTER (CORBA::COMPLETED_YES));
+ else
+ env.exception (new CORBA::INTERNAL (CORBA::COMPLETED_MAYBE));
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+
+ // decode the exception
+ if (this->inp_stream_.decode (tcp, exception, 0, env)
+ != CORBA::TypeCode::TRAVERSE_CONTINUE)
+ {
+ delete exception;
+ ACE_DEBUG ((LM_ERROR, "(%P|%t) invoke, unmarshal %s exception %s\n",
+ (reply_status == TAO_GIOP_USER_EXCEPTION) ? "user" : "system",
+ buf));
+ TAO_GIOP::send_error (this->handler_);
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+ env.exception (exception);
+ return (TAO_GIOP_ReplyStatusType) reply_status;
+
+ }
+ // NOTREACHED
+
+ case TAO_GIOP_LOCATION_FORWARD:
+ {
+ CORBA::Object_ptr obj;
+ IIOP_Object *obj2;
+
+ // Unmarshal the object we _should_ be calling. We know that
+ // one of the facets of this object will be an IIOP invocation
+ // profile.
+
+ if (this->inp_stream_.decode (CORBA::_tc_Object,
+ &obj, 0,
+ env) != CORBA::TypeCode::TRAVERSE_CONTINUE
+ || obj->QueryInterface (IID_IIOP_Object,
+ (void **) &obj2) != TAO_NOERROR)
+ {
+ dexc (env, "invoke, location forward");
+ TAO_GIOP::send_error (this->handler_);
+ return TAO_GIOP_SYSTEM_EXCEPTION;
+ }
+ CORBA::release (obj);
+
+ // 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.)
+
+#if 0 /* Keep this around in case forwarding is ever implemented. */
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, guard, data_->fwd_profile_lock (), TAO_GIOP_SYSTEM_EXCEPTION);
+#endif
+
+ IIOP::Profile *old = data_->fwd_profile_i (new IIOP::Profile (obj2->profile));
+ delete old;
+
+ obj2->Release ();
+
+ env.clear ();
+
+ // Make sure a new connection is used next time.
+ this->handler_->close ();
+ this->handler_ = 0;
+ // 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.
+ }
+ break;
+ }
+
+ // 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;
+}
+
void
TAO_GIOP::make_error (TAO_OutputCDR &msg, ...)
{
diff --git a/TAO/tao/GIOP.h b/TAO/tao/GIOP.h
index 84adbf1555e..8e3d54f3667 100644
--- a/TAO/tao/GIOP.h
+++ b/TAO/tao/GIOP.h
@@ -322,6 +322,14 @@ public:
// Send request, block until any reply comes back, and unmarshal
// reply parameters as appropriate.
+ TAO_GIOP_ReplyStatusType invoke (TAO_Exception_Data *excepts,
+ CORBA::ULong except_count,
+ CORBA::Environment &env);
+ // Special purpose invoke method used by the stubs. This accomplishes the
+ // same task as the normal invoke except that Exceptions are allocated and
+ // decoded here. This keeps the size of the stubs small and abstracts all the
+ // common code here.
+
void get_value (CORBA::TypeCode_ptr tc,
void *value,
CORBA::Environment &env);
diff --git a/TAO/tao/IIOP_Object.cpp b/TAO/tao/IIOP_Object.cpp
index e5c318e9593..779fdd15ba1 100644
--- a/TAO/tao/IIOP_Object.cpp
+++ b/TAO/tao/IIOP_Object.cpp
@@ -492,10 +492,13 @@ IIOP_Object::do_static_call (CORBA::Environment &env, // exception reporting
// ones.
TAO_GIOP_ReplyStatusType status;
+#if 0
CORBA::ExceptionList exceptions (info->except_count,
info->excepts);
-
status = call.invoke (exceptions, env);
+#endif
+
+ status = call.invoke (info->excepts, info->except_count, env);
if (env.exception ())
{
diff --git a/TAO/tao/Stub.h b/TAO/tao/Stub.h
index cc945760d28..5f422c10dd5 100644
--- a/TAO/tao/Stub.h
+++ b/TAO/tao/Stub.h
@@ -80,6 +80,31 @@ struct TAO_Param_Data
// compiler which generates the stub code.
};
+// Function pointer returning a pointer to CORBA::Exception. This is used to
+// describe the allocator for user-defined exceptions that are used internally
+// by the interpreter.
+typedef CORBA::Exception* (*TAO_Exception_Alloc) (void);
+
+struct TAO_Exception_Data
+{
+ // = TITLE
+ // TAO_Exception_Data
+ //
+ // = DESCRIPTION
+ // Description of a single exception
+ //
+ // The interpreter needs a way to allocate memory to hold the exception
+ // that was raised by the stub. This data structure provides the typecode
+ // for the exception as well as a static function pointer that does the job
+ // of memory allocation.
+
+ CORBA::TypeCode_ptr tc;
+ // typecode describing the exception
+
+ TAO_Exception_Alloc alloc;
+ // the allocator for this exception
+};
+
struct TAO_Call_Data
{
// = TITLE
@@ -122,7 +147,8 @@ struct TAO_Call_Data
u_int except_count;
// # exceptions.
- CORBA::TypeCode_ptr *excepts;
+ // CORBA::TypeCode_ptr *excepts;
+ TAO_Exception_Data *excepts;
// Their descriptions.
};