diff options
Diffstat (limited to 'TAO/tao/Server_Request.cpp')
-rw-r--r-- | TAO/tao/Server_Request.cpp | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/TAO/tao/Server_Request.cpp b/TAO/tao/Server_Request.cpp new file mode 100644 index 00000000000..bd979cc1805 --- /dev/null +++ b/TAO/tao/Server_Request.cpp @@ -0,0 +1,390 @@ +// $Id$ + +// Implementation of the Dynamic Server Skeleton Interface + +#include "tao/corba.h" + +// {77420086-F276-11ce-9598-0000C07CA898} +DEFINE_GUID (IID_IIOP_ServerRequest, +0x77420086, 0xf276, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98); + +// {4B48D881-F7F0-11ce-9598-0000C07CA898} +DEFINE_GUID (IID_CORBA_ServerRequest, +0x4b48d881, 0xf7f0, 0x11ce, 0x95, 0x98, 0x0, 0x0, 0xc0, 0x7c, 0xa8, 0x98); + +IIOP_ServerRequest::IIOP_ServerRequest (CDR *req, + CDR *resp, + CORBA::ULong reqid, + CORBA::ORB_ptr the_orb, + TAO_POA *the_poa) + : incoming_ (req), + outgoing_ (resp), + reqid_ (reqid), + params_ (0), + retval_ (0), + exception_ (0), + ex_type_ (CORBA::NO_EXCEPTION), + refcount_ (1), + orb_ (the_orb), + poa_ (the_poa) +{ +} + +IIOP_ServerRequest::~IIOP_ServerRequest (void) +{ + ACE_ASSERT (refcount_ == 0); + + if (params_) + CORBA::release (params_); + if (retval_) + delete retval_; + if (exception_) + delete exception_; +} + +ULONG +IIOP_ServerRequest::AddRef (void) +{ + ACE_ASSERT (refcount_ > 0); + return refcount_++; +} + +ULONG +IIOP_ServerRequest::Release (void) +{ + ACE_ASSERT (this != 0); + + if (--refcount_ != 0) + return refcount_; + + delete this; + return 0; +} + +TAO_HRESULT +IIOP_ServerRequest::QueryInterface (REFIID riid, + void **ppv) +{ + ACE_ASSERT (refcount_ > 0); + *ppv = 0; + + if (IID_IIOP_ServerRequest == riid + || IID_CORBA_ServerRequest == riid + || IID_TAO_IUnknown == riid) + *ppv = this; + + if (*ppv == 0) + return ResultFromScode (TAO_E_NOINTERFACE); + + (void) AddRef (); + return TAO_NOERROR; +} + +// Unmarshal in/inout params, and set up to marshal the appropriate +// inout/out/return values later on. + +void +IIOP_ServerRequest::params (CORBA::NVList_ptr list, + CORBA::Environment &env) +{ + env.clear (); + + // Save params for later use when marshaling the reply. + this->params_ = list; + + // Then unmarshal each "in" and "inout" parameter. + for (u_int i = 0; i < list->count (); i++) + { + CORBA::NamedValue_ptr nv = list->item (i, env); + + if (ACE_BIT_DISABLED (nv->flags (), CORBA::ARG_IN | CORBA::ARG_INOUT)) + continue; + + // First, make sure the memory into which we'll be unmarshaling + // exists, and is the right size. + // + // NOTE: desirable to have a way to let the dynamic + // implementation routine preallocate this data, for + // environments where DSI is just being used in lieu of a + // language mapped server-side API and the size is really + // knowable in advance. + + CORBA::Any_ptr any = nv->value (); + CORBA::TypeCode_ptr tc = any->type (); + + tc->AddRef (); + + void *value; + if (!any->value ()) + { // not preallocated + ACE_NEW (value, char [tc->size (env)]); + + any->replace (tc, value, CORBA::B_TRUE, env); + + // Decrement the refcount of "tc". + // + // The earlier AddRef is needed since Any::replace () releases + // the typecode inside the Any. Without the dup, the reference + // count can go to zero, and the typecode would then be deleted. + // + // This Release ensures that the reference count is correct so + // the typecode can be deleted some other time. + + tc->Release (); + } + else + value = (void *)any->value (); + + // Then just unmarshal the value. + (void) incoming_->decode (tc, value, 0, env); + } + + // If any data is left over, it'd be context values ... else error. + // We don't support context values, so it's always an error. + + if (incoming_->bytes_remaining () != 0) + { + dmsg1 ("params (), %d bytes remaining (error)", + incoming_->bytes_remaining ()); + env.exception (new CORBA::BAD_PARAM (CORBA::COMPLETED_NO)); + } +} + +// Store the result value. There's either an exception, or a result, +// but not both of them. Results (and exceptions) can be reported +// only after the parameter list has been provided (maybe empty). + +void +IIOP_ServerRequest::result (CORBA::Any_ptr value, + CORBA::Environment &env) +{ + env.clear (); + + if (!params_ || retval_ || exception_) + env.exception (new CORBA::BAD_INV_ORDER (CORBA::COMPLETED_NO)); + else + retval_ = value; + + // XXX send the message now! +} + +// Store the exception value. + +void +IIOP_ServerRequest::exception (CORBA::ExceptionType type, + CORBA::Any_ptr value, + CORBA::Environment &env) +{ + if (!params_ || retval_ || exception_) + env.exception (new CORBA::BAD_INV_ORDER (CORBA::COMPLETED_NO)); + else + { + env.clear (); + exception_ = value; + ex_type_ = type; + } + + // XXX send the message now! +} + +// Invocation attributes. + +CORBA::String +IIOP_ServerRequest::op_name (void) +{ + return opname_; +} + +CORBA::Object_ptr +IIOP_ServerRequest::target (void) +{ + // XXX implement me!! Code from TCP_OA exists ... + return 0; +} + +CORBA::Principal_ptr +IIOP_ServerRequest::caller (void) +{ + // XXX ... return client's principal + return 0; +} + +CORBA::ORB_ptr +IIOP_ServerRequest::orb (void) +{ + return orb_; +} + +TAO_POA * +IIOP_ServerRequest::oa (void) +{ + return poa_; +} + +// Extension +void +IIOP_ServerRequest::demarshal (CORBA::Environment &env, // exception reporting + const TAO_Call_Data_Skel *info, // call description + ...) // ... any parameters +{ + // First find out the size of the list to be created. info->count + // keeps track of the table size. If "roundtrip" is true => one + // entry is for RETURN type which does not go into the NVList + CORBA::ULong list_size = + info->is_roundtrip ? (info->param_count - 1) : info->param_count; + + CORBA::NVList_ptr nvlist; + + // Create an NVList of the appropriate size. + this->orb ()->create_list (list_size, nvlist); + + // Now, put all "in" and "inout" parameters into the NVList. + CORBA::ULong i; + + // Setup the variable argument list. + const TAO_Param_Data_Skel *pdp; + va_list param_vector; + va_start (param_vector, info); + + for (i = 0, pdp = info->params; + i < info->param_count; + i++, pdp++) + { + void *ptr = va_arg (param_vector, void *); + + if ((pdp->mode == CORBA::ARG_IN) + || (pdp->mode == CORBA::ARG_INOUT)) + // Populate the NVList. + (void) nvlist->add_item (0, pdp->mode, env)->value ()->replace (pdp->tc, ptr, pdp->own, env); + else if (pdp->mode == CORBA::ARG_OUT) + // Don't add any value. + (void) nvlist->add_item (0, pdp->mode, env); + + } + + va_end (param_vector); + + // Now demarshal the parameters using a call to params. + this->params (nvlist, env); // nvlist is now owned by us +} + +// Extension + +void +IIOP_ServerRequest::marshal (CORBA::Environment &env, // exception reporting + const TAO_Call_Data_Skel *info, // call description + ...) // ... any parameters +{ + // Now, put all "in" and "inout" parameters into the NVList. + CORBA::ULong i; + CORBA::ULong j; + + // Setup the variable argument list. + const TAO_Param_Data_Skel *pdp; + va_list param_vector; + va_start (param_vector, info); + + j = 0; + + for (i = 0, pdp = info->params; + i < info->param_count; + i++, pdp++) + { + void *ptr = va_arg (param_vector, void *); + + if (pdp->mode == 0) // return type + { + this->retval_ = new CORBA::Any (pdp->tc, ptr, pdp->own); + continue; + } + + if (pdp->mode == CORBA::ARG_OUT) + // don't add any value. + (void) this->params_->item (j, env)->value ()->replace (pdp->tc, ptr, pdp->own, env); + + j++; + } + + va_end (param_vector); + + // Setup a Reply message. + this->init_reply (env); + + // Normal reply. + if (!env.exception ()) + { + // ... then send any return value ... + if (this->retval_) + { + CORBA::TypeCode_ptr tc = this->retval_->type (); + const void *value = this->retval_->value (); + + if (value) + (void) this->outgoing_->encode (tc, value, 0, env); + } + + // ... Followed by "inout" and "out" parameters, left to right + for (i = 0; + i < this->params_->count (); + i++) + { + CORBA::NamedValue_ptr nv = this->params_->item (i, env); + CORBA::Any_ptr any; + + if (!(nv->flags () & (CORBA::ARG_INOUT|CORBA::ARG_OUT))) + continue; + + any = nv->value (); + CORBA::TypeCode_ptr tc = any->type (); + const void *value = any->value (); + (void) this->outgoing_->encode (tc, value, 0, env); + } + } +} + +void +IIOP_ServerRequest::init_reply (CORBA::Environment &env) +{ + // Construct a REPLY header. + TAO_GIOP::start_message (TAO_GIOP::Reply, *this->outgoing_); + TAO_GIOP_ServiceContextList resp_ctx; + resp_ctx.length (0); + this->outgoing_->encode (&TC_ServiceContextList, + &resp_ctx, + 0, + env); + this->outgoing_->put_ulong (this->reqid_); + + // Standard exceptions only. + if (env.exception () != 0) + { + CORBA::Environment env2; + CORBA::Exception *x = env.exception (); + CORBA::TypeCode_ptr except_tc = x->_type (); + + this->outgoing_->put_ulong (TAO_GIOP_SYSTEM_EXCEPTION); + (void) this->outgoing_->encode (except_tc, x, 0, env2); + } + + // Any exception at all. + else if (this->exception_) + { + CORBA::Exception *x; + CORBA::TypeCode_ptr except_tc; + + x = (CORBA::Exception *) this->exception_->value (); + except_tc = this->exception_->type (); + + // Finish the GIOP Reply header, then marshal the exception. + // XXX x->type () someday ... + if (this->ex_type_ == CORBA::SYSTEM_EXCEPTION) + this->outgoing_->put_ulong (TAO_GIOP_SYSTEM_EXCEPTION); + else + this->outgoing_->put_ulong (TAO_GIOP_USER_EXCEPTION); + + (void) this->outgoing_->encode (except_tc, x, 0, env); + } + else // Normal reply + // First finish the GIOP header ... + this->outgoing_->put_ulong (TAO_GIOP_NO_EXCEPTION); +} |