diff options
-rw-r--r-- | TAO/ChangeLog-98c | 26 | ||||
-rw-r--r-- | TAO/TAO_IDL/be/be_visitor_exception.cpp | 8 | ||||
-rw-r--r-- | TAO/TAO_IDL/be/be_visitor_operation.cpp | 19 | ||||
-rw-r--r-- | TAO/tao/GIOP.cpp | 384 | ||||
-rw-r--r-- | TAO/tao/GIOP.h | 8 | ||||
-rw-r--r-- | TAO/tao/IIOP_Object.cpp | 5 | ||||
-rw-r--r-- | TAO/tao/Stub.h | 28 |
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. }; |