diff options
Diffstat (limited to 'TAO/IIOP/lib/marshal.cpp')
-rw-r--r-- | TAO/IIOP/lib/marshal.cpp | 1930 |
1 files changed, 947 insertions, 983 deletions
diff --git a/TAO/IIOP/lib/marshal.cpp b/TAO/IIOP/lib/marshal.cpp index 6f0d77bc440..f37af656c17 100644 --- a/TAO/IIOP/lib/marshal.cpp +++ b/TAO/IIOP/lib/marshal.cpp @@ -4,38 +4,41 @@ // // CDR: Marshaling interpreter // -// This marshaling interpreter is driven by the typecode interpreter. The -// typecode interpreter understands each compiler environment's rules for -// data structure layout; this understands CDR's rules for on-the-wire data -// structure layout. +// This marshaling interpreter is driven by the typecode interpreter. +// The typecode interpreter understands each compiler environment's +// rules for data structure layout; this understands CDR's rules for +// on-the-wire data structure layout. // -// Apart from some high level rules related to construction of complex data -// types, the marshaling interpreter just knows how to encode primitive data -// types and allocate memory on decode. +// Apart from some high level rules related to construction of complex +// data types, the marshaling interpreter just knows how to encode +// primitive data types and allocate memory on decode. // -// NOTE: to reduce the amount of compiled code, this "knows" facts like -// native float/long/ulong being in legal CDR format, and that "char" is -// native in ISO Latin/1 (so no transformation is needed, and octet/char -// marshaling code is identical). On exotic platforms where this is not -// true, some of the merged "switch" branches will need to be split. +// NOTE: to reduce the amount of compiled code, this "knows" facts +// like native float/long/ulong being in legal CDR format, and that +// "char" is native in ISO Latin/1 (so no transformation is needed, +// and octet/char marshaling code is identical). On exotic platforms +// where this is not true, some of the merged "switch" branches will +// need to be split. // -// REMEMBER: goal is to have the typecode interpreter plus one side of the -// marshaling interpreter reside in a CPU's code cache; or at least to have -// as litle as possible _outside_ cache when marshaling. Compiled marshaling -// code will have a few less instructions, but most will of them will be -// outside the instruction cache; access time to get at them will be high. +// REMEMBER: goal is to have the typecode interpreter plus one side of +// the marshaling interpreter reside in a CPU's code cache; or at +// least to have as litle as possible _outside_ cache when marshaling. +// Compiled marshaling code will have a few less instructions, but +// most will of them will be outside the instruction cache; access +// time to get at them will be high. // -// NOTE: One interesting optimization is inlining the primitive put/get -// calls ... it'd typically save at least 40% in terms of instruction count -// on each of these critical paths by eliminating subroutine call overhead. -// Since it would increase code size, such changes might not be desirable -// on machines with small caches. Also, with network I/O being today's most -// significant bottleneck, such optimizations haven't been well explored. +// NOTE: One interesting optimization is inlining the primitive +// put/get calls ... it'd typically save at least 40% in terms of +// instruction count on each of these critical paths by eliminating +// subroutine call overhead. Since it would increase code size, such +// changes might not be desirable on machines with small caches. +// Also, with network I/O being today's most significant bottleneck, +// such optimizations haven't been well explored. // -// THREADING NOTE: The only threading concern is as always, that data -// structures being manipulated by any given thread must be reserved to -// it by some mechanism (e.g. mutex). This uses no mutable data outside -// of the thread stack, so the onus is entirely on the caller. +// THREADING NOTE: The only threading concern is as always, that data +// structures being manipulated by any given thread must be reserved +// to it by some mechanism (e.g. mutex). This uses no mutable data +// outside of the thread stack, so the onus is entirely on the caller. // #include <assert.h> @@ -48,507 +51,473 @@ #include "giop.h" - #if defined (HAVE_WIDEC_H) # include <widec.h> #else - extern "C" { - unsigned wslen (const CORBA_WChar *); - CORBA_WChar *wscpy (CORBA_WChar *, const CORBA_WChar *); - } +extern "C" +{ + u_int wslen (const CORBA_WChar *); + CORBA_WChar *wscpy (CORBA_WChar *, const CORBA_WChar *); +} #endif -extern CORBA_TypeCode TC_opaque; +extern CORBA_TypeCode TC_opaque; - -// -// Encode instances of arbitrary data types based only on typecode. "data" -// points to the data type; if it's not a primitve data type, the TypeCode -// interpreter is used to recursively encode its components. "context" is -// the marshaling stream on which to encode the data value. -// -// This is a fairly typical TypeCode interpreter visit() routine; it works -// on a single data value in conjunction with context information, and must -// handle all IDL data types. +// Encode instances of arbitrary data types based only on typecode. +// "data" points to the data type; if it's not a primitve data type, +// the TypeCode interpreter is used to recursively encode its +// components. "context" is the marshaling stream on which to encode +// the data value. // +// This is a fairly typical TypeCode interpreter visit() routine; it +// works on a single data value in conjunction with context +// information, and must handle all IDL data types. + CORBA_TypeCode::traverse_status -CDR::encoder ( - CORBA_TypeCode_ptr tc, - const void *data, - const void *, - void *context, - CORBA_Environment &env -) +CDR::encoder (CORBA_TypeCode_ptr tc, + const void *data, + const void *, + void *context, + CORBA_Environment &env) { - CORBA_Boolean continue_encoding = CORBA_B_TRUE; - CDR *stream = (CDR *)context; - - switch (tc->_kind) { - case tk_null: - case tk_void: - // nothing to encode! - break; - - case tk_char: - case tk_octet: - continue_encoding = stream->put_char (*(char *)data); - break; - - case tk_short: - case tk_ushort: - continue_encoding = stream->put_short (*(short *)data); - break; - - case tk_long: - case tk_ulong: - case tk_float: - continue_encoding = stream->put_long (*(CORBA_Long *)data); - break; - - case tk_double: - case tk_longlong: - case tk_ulonglong: - continue_encoding = stream->put_longlong (*(CORBA_LongLong *)data); - break; - - case tk_boolean: - continue_encoding = stream->put_boolean (*(CORBA_Boolean *)data); - break; - - case tk_enum: - { - // - // NOTE assumption that this is in-range. - // - // XXX should check this, it's a hard-to-recover error - // for the other side - // - unsigned value = *(unsigned *)data; - continue_encoding = stream->put_ulong (value); - } - break; + CORBA_Boolean continue_encoding = CORBA_B_TRUE; + CDR *stream = (CDR *) context; + + switch (tc->_kind) + { + case tk_null: + case tk_void: + // nothing to encode! + break; + + case tk_char: + case tk_octet: + continue_encoding = stream->put_char (*(char *) data); + break; + + case tk_short: + case tk_ushort: + continue_encoding = stream->put_short (*(short *) data); + break; + + case tk_long: + case tk_ulong: + case tk_float: + continue_encoding = stream->put_long (*(CORBA_Long *) data); + break; + + case tk_double: + case tk_longlong: + case tk_ulonglong: + continue_encoding = stream->put_longlong (*(CORBA_LongLong *) data); + break; + + case tk_boolean: + continue_encoding = stream->put_boolean (*(CORBA_Boolean *) data); + break; + + case tk_enum: + { + // NOTE assumption that this is in-range. + // + // XXX should check this, it's a hard-to-recover error for the + // other side + + u_int value = *(u_int *) data; + continue_encoding = stream->put_ulong (value); + } + break; + + case tk_any: + { + CORBA_Any *any = (CORBA_Any *) data; + + tc = any->type (); + if (encoder (_tc_CORBA_TypeCode, &tc, 0, context, env) + != CORBA_TypeCode::TRAVERSE_CONTINUE) + return CORBA_TypeCode::TRAVERSE_STOP; + + data = any->value (); + return encoder (tc, data, 0, context, env); + } + // NOTREACHED + + case tk_TypeCode: + { + CORBA_TypeCode_ptr tc2; + + tc2 = *(CORBA_TypeCode_ptr *) data; + + continue_encoding = stream->put_ulong ((CORBA_ULong) tc2->_kind); + if (continue_encoding == CORBA_B_FALSE) + break; + + switch (tc2->_kind) + { + // Most TypeCodes have empty parameter lists + default: + break; - case tk_any: - { - CORBA_Any *any = (CORBA_Any *)data; + // A few have "simple" parameter lists + case tk_string: + case tk_wstring: + continue_encoding = stream->put_ulong (tc2->_length); + break; - tc = any->type (); - if (encoder (_tc_CORBA_TypeCode, &tc, 0, context, env) - != CORBA_TypeCode::TRAVERSE_CONTINUE) - return CORBA_TypeCode::TRAVERSE_STOP; + // Indirected typecodes can't occur at "top level" like + // this, only nested inside others! + case ~0: + dmsg ("indirected typecode at top level!"); + continue_encoding = CORBA_B_FALSE; + break; - data = any->value (); - return encoder (tc, data, 0, context, env); - } - // NOTREACHED - - case tk_TypeCode: - { - CORBA_TypeCode_ptr tc2; - - tc2 = *(CORBA_TypeCode_ptr *)data; - - continue_encoding = stream->put_ulong ((CORBA_ULong) tc2->_kind); - if (continue_encoding == CORBA_B_FALSE) - break; - - switch (tc2->_kind) { - // - // Most TypeCodes have empty parameter lists - // - default: - break; - - // - // A few have "simple" parameter lists - // - case tk_string: - case tk_wstring: - continue_encoding = stream->put_ulong (tc2->_length); - break; - - // - // Indirected typecodes can't occur at "top level" like - // this, only nested inside others! - // - case ~0: - dmsg ("indirected typecode at top level!"); - continue_encoding = CORBA_B_FALSE; - break; - - // - // The rest have "complex" parameter lists that are already - // encoded as bulk octets ... put length, then octets - // - case tk_objref: - case tk_struct: - case tk_union: - case tk_enum: - case tk_sequence: - case tk_array: - case tk_alias: - case tk_except: - { - unsigned i; - - continue_encoding = stream->put_ulong (tc2->_length); - for (i = 0; i < tc2->_length && continue_encoding; i++) - continue_encoding = - stream->put_octet (tc2->_buffer [i]); - } + // The rest have "complex" parameter lists that are + // already encoded as bulk octets ... put length, then + // octets. + case tk_objref: + case tk_struct: + case tk_union: + case tk_enum: + case tk_sequence: + case tk_array: + case tk_alias: + case tk_except: + { + continue_encoding = stream->put_ulong (tc2->_length); + + for (u_int i = 0; i < tc2->_length && continue_encoding; i++) + continue_encoding = stream->put_octet (tc2->_buffer [i]); } - } - break; - - case tk_Principal: - { - CORBA_Principal_ptr p = *(CORBA_Principal_ptr*) data; - unsigned i; - - if (p != 0) { - continue_encoding = stream->put_long (p->id.length); - for (i = 0; continue_encoding && i < p->id.length; i++) - continue_encoding = stream->put_octet (p->id.buffer [i]); - } else - continue_encoding = stream->put_long (0); - } - break; + } + } + break; + + case tk_Principal: + { + CORBA_Principal_ptr p = *(CORBA_Principal_ptr *) data; + + if (p != 0) + { + continue_encoding = stream->put_long (p->id.length); + + for (u_int i = 0; continue_encoding && i < p->id.length; i++) + continue_encoding = stream->put_octet (p->id.buffer [i]); + } + else + continue_encoding = stream->put_long (0); + } + break; + + case tk_objref: + + // Current version: objref is really an IIOP_Object. + // + // This will change in the future; STUB_Object knows how to + // marshal itself, that will be used. + // + // XXX this doesn't actually verify that the stuff got written + // OK to the "wire" ... + { + CORBA_Object_ptr obj = *(CORBA_Object_ptr *) data; + + // NIL objrefs ... marshal as empty type hint, no elements. + + if (CORBA_is_nil (obj)) + { + continue_encoding = + stream->put_ulong (1) // strlen + && stream->put_char (0) // NUL + && stream->put_ulong (0); // no profiles + break; + } - case tk_objref: - // - // Current version: objref is really an IIOP_Object. - // - // This will change in the future; STUB_Object knows how to - // marshal itself, that will be used. + // All other objrefs ... narrow to a "real type" that we + // recognize, then marshal. // - // XXX this doesn't actually verify that the stuff got written - // OK to the "wire" ... + // XXX this will be changed so it narrows to STUB_Object and + // then asks that surrogate/proxy to marshal itself. // - { - CORBA_Object_ptr obj = *(CORBA_Object_ptr *)data; - - // - // NIL objrefs ... marshal as empty type hint, no elements. - // - if (CORBA_is_nil (obj)) { - continue_encoding = - stream->put_ulong (1) // strlen - && stream->put_char (0) // NUL - && stream->put_ulong (0); // no profiles - break; - } - - // - // All other objrefs ... narrow to a "real type" that we - // recognize, then marshal. - // - // XXX this will be changed so it narrows to STUB_Object - // and then asks that surrogate/proxy to marshal itself. - // - // For now, the original code is minimally changed. - // - IIOP_Object *objdata; - IIOP::ProfileBody *profile; + // For now, the original code is minimally changed. + + IIOP_Object *objdata; + IIOP::ProfileBody *profile; + + if (obj->QueryInterface (IID_IIOP_Object, + (void **) &objdata) != NOERROR) + { + env.exception (new CORBA_MARSHAL (COMPLETED_NO)); + return CORBA_TypeCode::TRAVERSE_STOP; + } + obj->Release (); + profile = &objdata->profile; + + // STRING, a type ID hint + encoder (_tc_CORBA_String, &objdata->type_id, 0, context, env); + + // UNSIGNED LONG, value one, count of the sequence of + // encapsulated protocol profiles; + stream->put_ulong (1); + + // UNSIGNED LONG, tag for this protocol profile; + stream->put_ulong (IOP::TAG_INTERNET_IOP); + + // UNSIGNED LONG, number of succeeding bytes in the + // encapsulation. We don't actually need to make the + // encapsulation, as nothing needs stronger alignment than + // this longword; it guarantees the rest is aligned for us. + u_int hostlen; + + hostlen = ACE_OS::strlen ((char *) profile->host); + stream->put_ulong (1 // byte order + + 3 // version + pad byte + + 4 // sizeof (strlen) + + hostlen + 1 // strlen + null + + (~hostlen & 01) // optional pad byte + + 2 // port + + (hostlen & 02) // optional pad short + + 4 // sizeof (key length) + + profile->object_key.length); // key length + + // CHAR describing byte order, starting the encapsulation + + stream->put_char (MY_BYTE_SEX); + + // IIOP::Version, two characters (version 1.0) padding + stream->put_char (profile->iiop_version.major); + stream->put_char (profile->iiop_version.minor); + + // STRING hostname from profile + encoder (_tc_CORBA_String, &profile->host, 0, context, env); + + // UNSIGNED SHORT port number + stream->put_ushort (profile->port); + + // OCTET SEQUENCE for object key + encoder (&TC_opaque, &profile->object_key, 0, context, env); + } + break; + + case tk_sequence: + { + // First marshal the sequence length, verifying that it's + // within the sequence bounds ... + CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data; + CORBA_ULong len = seq ? seq->length : 0; + + if (len > 0) + { + CORBA_ULong bounds; + + bounds = tc->ulong_param (1, env); + if (env.exception () != 0) + return CORBA_TypeCode::TRAVERSE_STOP; - if (obj->QueryInterface (IID_IIOP_Object, (void **)&objdata) - != NOERROR) { - env.exception (new CORBA_MARSHAL (COMPLETED_NO)); + if (bounds != 0 && len > bounds) + { + env.exception (new CORBA_BAD_PARAM (COMPLETED_MAYBE)); return CORBA_TypeCode::TRAVERSE_STOP; - } - obj->Release (); - profile = &objdata->profile; - - // - // STRING, a type ID hint - // - encoder (_tc_CORBA_String, &objdata->type_id, 0, context, env); - - // - // UNSIGNED LONG, value one, count of the sequence - // of encapsulated protocol profiles; - // + } + } + continue_encoding = stream->put_ulong (len); + + // Fast exit on error or empty sequence + if (!continue_encoding || len == 0) + break; + } + // FALLTHROUGH + + case tk_struct: + case tk_union: + case tk_array: + case tk_alias: + // Marshal each member in order. + return tc->traverse (data, 0, encoder, context, env); + + case tk_except: + // Convert the the "hidden" TypeCode at the beginning of the + // exception into an on-the-wire ID, then marshal the members in + // order (traversal skips that hidden typecode, and more). + // + // NOTE: This is asymmetric with respect to decoding the + // exception, since whoever decodes must pull off the ID and map + // it to the typecode to be used to unmarshal it (search among + // legal choices). + { + CORBA_String id = tc->id (env); + + if (env.exception () == 0) + { + continue_encoding = + encoder (_tc_CORBA_String, &id, 0, context, env) + == CORBA_TypeCode::TRAVERSE_CONTINUE + && tc->traverse (data, 0, encoder, context, env); + } + else + continue_encoding = CORBA_B_FALSE; + } + break; + + case tk_string: + { + CORBA_String str = *(CORBA_String *) data; + CORBA_ULong len; + CORBA_ULong bounds; + + // Be nice to programmers: treat nulls as empty strings not + // errors. (OMG-IDL supports languages that don't use the + // C/C++ notion of null v. empty strings; nulls aren't part of + // the OMG-IDL string model.) + if (str == 0) + { stream->put_ulong (1); + stream->put_char (0); + break; + } + + // Verify string satisfies bounds requirements. We're not so + // permissive as to send messages violating the interface spec + // by having excessively long strings! + bounds = tc->ulong_param (0, env); + if (env.exception () != 0) + return CORBA_TypeCode::TRAVERSE_STOP; + len = ACE_OS::strlen ((char *) str); + + if (bounds != 0 && len > bounds) + { + continue_encoding = CORBA_B_FALSE; + break; + } - // - // UNSIGNED LONG, tag for this protocol profile; - // - stream->put_ulong (IOP::TAG_INTERNET_IOP); - - // - // UNSIGNED LONG, number of succeeding bytes in the encapsulation. - // We don't actually need to make the encapsulation, as nothing - // needs stronger alignment than this longword; it guarantees - // the rest is aligned for us. - // - unsigned hostlen; - - hostlen = ACE_OS::strlen ((char *)profile->host); - stream->put_ulong ( - 1 // byte order - + 3 // version + pad byte - + 4 // sizeof (strlen) - + hostlen + 1 // strlen + null - + (~hostlen & 01) // optional pad byte - + 2 // port - + (hostlen & 02) // optional pad short - + 4 // sizeof (key length) - + profile->object_key.length); // key length - - // - // CHAR describing byte order, starting the encapsulation - // - stream->put_char (MY_BYTE_SEX); - - // - // IIOP::Version, two characters (version 1.0) - // padding - // - stream->put_char (profile->iiop_version.major); - stream->put_char (profile->iiop_version.minor); - - // - // STRING hostname from profile - // - encoder (_tc_CORBA_String, &profile->host, 0, context, env); - - // - // UNSIGNED SHORT port number - // - stream->put_ushort (profile->port); - - // - // OCTET SEQUENCE for object key - // - encoder (&TC_opaque, &profile->object_key, 0, context, env); - } - break; - - case tk_sequence: - { - // - // First marshal the sequence length, verifying that - // it's within the sequence bounds ... - // - CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data; - CORBA_ULong len = seq ? seq->length : 0; - - if (len > 0) { - CORBA_ULong bounds; - - bounds = tc->ulong_param (1, env); - if (env.exception () != 0) - return CORBA_TypeCode::TRAVERSE_STOP; - - if (bounds != 0 && len > bounds) { - env.exception (new CORBA_BAD_PARAM (COMPLETED_MAYBE)); - return CORBA_TypeCode::TRAVERSE_STOP; - } - } - continue_encoding = stream->put_ulong (len); - - // - // Fast exit on error or empty sequence - // - if (!continue_encoding || len == 0) - break; - } - // FALLTHROUGH - - case tk_struct: - case tk_union: - case tk_array: - case tk_alias: - // - // Marshal each member in order. - // - return tc->traverse (data, 0, encoder, context, env); - - case tk_except: - // - // Convert the the "hidden" TypeCode at the beginning of the - // exception into an on-the-wire ID, then marshal the members - // in order (traversal skips that hidden typecode, and more). - // - // NOTE: This is asymmetric with respect to decoding the exception, - // since whoever decodes must pull off the ID and map it to the - // typecode to be used to unmarshal it (search among legal choices). - // - { - CORBA_String id = tc->id (env); - - if (env.exception () == 0) { - continue_encoding = - encoder (_tc_CORBA_String, &id, 0, context, env) - == CORBA_TypeCode::TRAVERSE_CONTINUE - && tc->traverse (data, 0, encoder, context, env); - } else - continue_encoding = CORBA_B_FALSE; - } - break; - - case tk_string: - { - CORBA_String str = *(CORBA_String *) data; - CORBA_ULong len, bounds; + // Encode the string, followed by a NUL character. - // - // Be nice to programmers: treat nulls as empty strings - // not errors. (OMG-IDL supports languages that don't use - // the C/C++ notion of null v. empty strings; nulls aren't - // part of the OMG-IDL string model.) - // - if (str == 0) { - stream->put_ulong (1); - stream->put_char (0); - break; - } + for (continue_encoding = stream->put_ulong (len + 1); + continue_encoding != CORBA_B_FALSE && *str; + continue_encoding = stream->put_char (*str++)) + continue; - // - // Verify string satisfies bounds requirements. We're not - // so permissive as to send messages violating the interface - // spec by having excessively long strings! - // - bounds = tc->ulong_param (0, env); - if (env.exception () != 0) - return CORBA_TypeCode::TRAVERSE_STOP; - len = ACE_OS::strlen ((char *)str); + stream->put_char (0); + } + break; - if (bounds != 0 && len > bounds) { - continue_encoding = CORBA_B_FALSE; - break; - } + case tk_wstring: + { + CORBA_WChar *str = *(CORBA_WChar **) data; + CORBA_ULong len; + CORBA_ULong bounds; - // - // Encode the string, followed by a NUL character. - // - continue_encoding = stream->put_ulong (len + 1); - while (continue_encoding != CORBA_B_FALSE && *str) - continue_encoding = stream->put_char (*str++); - stream->put_char (0); - } - break; + // Be nice to programmers: treat nulls as empty strings not + // errors. (OMG-IDL supports languages that don't use the + // C/C++ notion of null v. empty strings; nulls aren't part of + // the OMG-IDL string model.) - case tk_wstring: - { - CORBA_WChar *str = *(CORBA_WChar **) data; - CORBA_ULong len, bounds; + if (str == 0) + { + stream->put_ulong (1); + stream->put_wchar (0); + break; + } + + // Verify wide string satisfies bounds requirements. We're + // not so permissive as to send messages violating the + // interface spec by having excessively long strings! + + bounds = tc->ulong_param (0, env); + if (env.exception () != 0) + return CORBA_TypeCode::TRAVERSE_STOP; + len = wslen (str); + if (bounds != 0 && len > bounds) + { + continue_encoding = CORBA_B_FALSE; + break; + } - // - // Be nice to programmers: treat nulls as empty strings - // not errors. (OMG-IDL supports languages that don't use - // the C/C++ notion of null v. empty strings; nulls aren't - // part of the OMG-IDL string model.) - // - if (str == 0) { - stream->put_ulong (1); - stream->put_wchar (0); - break; - } + // Encode the wide string, followed by a NUL character. - // - // Verify wide string satisfies bounds requirements. We're - // not so permissive as to send messages violating the interface - // spec by having excessively long strings! - // - bounds = tc->ulong_param (0, env); - if (env.exception () != 0) - return CORBA_TypeCode::TRAVERSE_STOP; - len = wslen (str); - if (bounds != 0 && len > bounds) { - continue_encoding = CORBA_B_FALSE; - break; - } + for (continue_encoding = stream->put_ulong (wslen (str) + 1); + continue_encoding != CORBA_B_FALSE && *str; + continue_encoding = stream->put_wchar (*str++)) + continue; - // - // Encode the wide string, followed by a NUL character. - // - continue_encoding = stream->put_ulong (wslen (str) + 1); - while (continue_encoding != CORBA_B_FALSE && *str) - continue_encoding = stream->put_wchar (*str++); - stream->put_wchar (0); - } - break; + stream->put_wchar (0); + } + break; - case tk_longdouble: - continue_encoding = - stream->put_longdouble (*(CORBA_LongDouble *)data); - break; + case tk_longdouble: + continue_encoding = stream->put_longdouble (*(CORBA_LongDouble *) data); + break; - case tk_wchar: - continue_encoding = stream->put_wchar (*(CORBA_WChar *)data); - break; + case tk_wchar: + continue_encoding = stream->put_wchar (*(CORBA_WChar *) data); + break; // case ~0: - default: - dmsg ("encoder default case ?"); - continue_encoding = CORBA_B_FALSE; - break; + default: + dmsg ("encoder default case ?"); + continue_encoding = CORBA_B_FALSE; + break; } - if (continue_encoding == CORBA_B_FALSE) { - env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); - dmsg ("marshaling encoder detected error"); - return CORBA_TypeCode::TRAVERSE_STOP; + if (continue_encoding == CORBA_B_FALSE) + { + env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); + dmsg ("marshaling encoder detected error"); + return CORBA_TypeCode::TRAVERSE_STOP; } - return CORBA_TypeCode::TRAVERSE_CONTINUE; + return CORBA_TypeCode::TRAVERSE_CONTINUE; } - -// -// This table of TypeCode constants lets us unmarshal most typecodes using -// the predefined constants, rather than constantly reallocating them. -// -// XXX CFRONT-based compilers can't cope with this table initialization, -// and need some kind of init function. Luckily, they're increasingly -// rare in any "production" environment. +// This table of TypeCode constants lets us unmarshal most typecodes +// using the predefined constants, rather than constantly reallocating +// them. // +// XXX CFRONT-based compilers can't cope with this table +// initialization, and need some kind of init function. Luckily, +// they're increasingly rare in any "production" environment. + #if THE_COMPILER_CAN_FIND_THIS_PROPERLY -const // The extern reference in onc/xdr.cpp doesn't - // seem to be able to find this decl with as - // long as the const is part of it. I even - // tried changing the ref decl to have 'const' - // in it, to no avail. --cjc +// The extern reference in onc/xdr.cpp doesn't seem to be able to find +// this decl with as long as the const is part of it. I even tried +// changing the ref decl to have 'const' in it, to no avail. --cjc +const #endif -CORBA_TypeCode_ptr -__tc_consts [TC_KIND_COUNT] = { - _tc_CORBA_Null - , _tc_CORBA_Void - , _tc_CORBA_Short - , _tc_CORBA_Long - , _tc_CORBA_UShort - - , _tc_CORBA_ULong - , _tc_CORBA_Float - , _tc_CORBA_Double - , _tc_CORBA_Boolean - , _tc_CORBA_Char - - , _tc_CORBA_Octet - , _tc_CORBA_Any - , _tc_CORBA_TypeCode - , _tc_CORBA_Principal - , 0 // _tc_CORBA_Object ... type ID is CORBA::Object - - , 0 // tk_struct - , 0 // tk_union - , 0 // tk_enum - , 0 // _tc_CORBA_String ... unbounded - , 0 // tk_sequence - - , 0 // tk_array - - , 0 // tk_alias - , 0 // tk_except - - , _tc_CORBA_LongLong - , _tc_CORBA_ULongLong - , _tc_CORBA_LongDouble - , _tc_CORBA_WChar - , 0 // _tc_CORBA_WString ... unbounded +CORBA_TypeCode_ptr __tc_consts [TC_KIND_COUNT] = +{ + _tc_CORBA_Null + , _tc_CORBA_Void + , _tc_CORBA_Short + , _tc_CORBA_Long + , _tc_CORBA_UShort + + , _tc_CORBA_ULong + , _tc_CORBA_Float + , _tc_CORBA_Double + , _tc_CORBA_Boolean + , _tc_CORBA_Char + + , _tc_CORBA_Octet + , _tc_CORBA_Any + , _tc_CORBA_TypeCode + , _tc_CORBA_Principal + , 0 // _tc_CORBA_Object ... type ID is CORBA::Object + + , 0 // tk_struct + , 0 // tk_union + , 0 // tk_enum + , 0 // _tc_CORBA_String ... unbounded + , 0 // tk_sequence + + , 0 // tk_array + + , 0 // tk_alias + , 0 // tk_except + + , _tc_CORBA_LongLong + , _tc_CORBA_ULongLong + , _tc_CORBA_LongDouble + , _tc_CORBA_WChar + , 0 // _tc_CORBA_WString ... unbounded }; - -// // The decoder is exactly the reverse of the encoder, except that: // // * Unmarshaling some data types involve allocating memory. Such @@ -559,550 +528,545 @@ __tc_consts [TC_KIND_COUNT] = { // encapsulations. This means it must deal with "tk_indirect", // the magic value (~0) signifying typecode indirection. // -// This second case is identified by a bit of a hack: the second "data" -// value is used to hold the parent typecode, rather than being ignored. -// This means that all other invocations of decoder() ** MUST ** pass zero -// for the second data parameter, in case they decode a TypeCode. If they -// didn't, this case might be signified inappropriately. -// -// XXX desirable to have a less hacky solution to that ... pull that code -// out into a separate routine called both by CDR::decoder() and by the -// code retrieving typecode parameters from encapsulations. +// This second case is identified by a bit of a hack: the second +// "data" value is used to hold the parent typecode, rather than being +// ignored. This means that all other invocations of decoder() ** +// MUST ** pass zero for the second data parameter, in case they +// decode a TypeCode. If they didn't, this case might be signified +// inappropriately. // +// XXX desirable to have a less hacky solution to that ... pull that +// code out into a separate routine called both by CDR::decoder() and +// by the code retrieving typecode parameters from encapsulations. + CORBA_TypeCode::traverse_status -CDR::decoder ( - CORBA_TypeCode_ptr tc, - const void *data, - const void *parent_typecode, - void *context, - CORBA_Environment &env -) +CDR::decoder (CORBA_TypeCode_ptr tc, + const void *data, + const void *parent_typecode, + void *context, + CORBA_Environment &env) { - CORBA_Boolean continue_decoding = CORBA_B_TRUE; - CDR *stream = (CDR *)context; - - switch (tc->_kind) { - case tk_null: - case tk_void: - // nothing to decode! - break; + CORBA_Boolean continue_decoding = CORBA_B_TRUE; + CDR *stream = (CDR *) context; + + switch (tc->_kind) + { + case tk_null: + case tk_void: + // nothing to decode! + break; - case tk_char: - case tk_octet: - continue_decoding = stream->get_char (*(CORBA_Char *)data); - break; - - case tk_short: - case tk_ushort: - continue_decoding = stream->get_short (*(short *)data); - break; - - case tk_long: - case tk_ulong: - case tk_float: - continue_decoding = stream->get_long (*(CORBA_Long *)data); - break; - - case tk_longlong: - case tk_ulonglong: - case tk_double: - continue_decoding = stream->get_longlong (*(CORBA_LongLong *)data); - break; - - case tk_boolean: - continue_decoding = stream->get_boolean (*(CORBA_Boolean *)data); - break; - - case tk_enum: - { - CORBA_ULong val; - - // - // NOTE assumption that this is in-range. - // - // XXX should check this, it's rather hard to recover - // from such errors since they "do not occur" and are - // essentially never tested for. - // - continue_decoding = stream->get_ulong (val); - *(unsigned *)data = (unsigned) val; - } - break; - - case tk_any: - { - CORBA_Any *any = (CORBA_Any *)data; - CORBA_TypeCode_ptr tc2; - void *value; - - if (decoder (_tc_CORBA_TypeCode, &tc2, 0, context, env) - != CORBA_TypeCode::TRAVERSE_CONTINUE) - return CORBA_TypeCode::TRAVERSE_STOP; - - value = new CORBA_Octet [tc2->size (env)]; - - if (decoder (tc2, value, 0, context, env) - != CORBA_TypeCode::TRAVERSE_CONTINUE) { - delete value; - CORBA_release (tc2); - return CORBA_TypeCode::TRAVERSE_STOP; - } - (void) new (any) CORBA_Any (tc2, value, CORBA_B_TRUE); - } - break; - - case tk_TypeCode: - { - CORBA_ULong kind; - CORBA_TypeCode_ptr *tcp; - - continue_decoding = stream->get_ulong (kind); - if (continue_decoding == CORBA_B_FALSE) - break; - if (kind >= TC_KIND_COUNT) { - continue_decoding = CORBA_B_FALSE; - break; - } + case tk_char: + case tk_octet: + continue_decoding = stream->get_char (*(CORBA_Char *) data); + break; + + case tk_short: + case tk_ushort: + continue_decoding = stream->get_short (*(short *) data); + break; + + case tk_long: + case tk_ulong: + case tk_float: + continue_decoding = stream->get_long (*(CORBA_Long *) data); + break; + + case tk_longlong: + case tk_ulonglong: + case tk_double: + continue_decoding = stream->get_longlong (*(CORBA_LongLong *) data); + break; + + case tk_boolean: + continue_decoding = stream->get_boolean (*(CORBA_Boolean *) data); + break; + + case tk_enum: + { + CORBA_ULong val; + + // NOTE assumption that this is in-range. + // + // XXX should check this, it's rather hard to recover from + // such errors since they "do not occur" and are essentially + // never tested for. + continue_decoding = stream->get_ulong (val); + *(u_int *) data = (u_int) val; + } + break; + + case tk_any: + { + CORBA_Any *any = (CORBA_Any *) data; + CORBA_TypeCode_ptr tc2; + void *value; + + if (decoder (_tc_CORBA_TypeCode, + &tc2, 0, + context, env) != CORBA_TypeCode::TRAVERSE_CONTINUE) + return CORBA_TypeCode::TRAVERSE_STOP; + + value = new CORBA_Octet[tc2->size (env)]; + + if (decoder (tc2, + value, 0, + context, env) != CORBA_TypeCode::TRAVERSE_CONTINUE) + { + delete value; + CORBA_release (tc2); + return CORBA_TypeCode::TRAVERSE_STOP; + } + (void) new (any) CORBA_Any (tc2, value, CORBA_B_TRUE); + } + break; + + case tk_TypeCode: + { + CORBA_ULong kind; + CORBA_TypeCode_ptr *tcp; + + continue_decoding = stream->get_ulong (kind); + if (continue_decoding == CORBA_B_FALSE) + break; + if (kind >= TC_KIND_COUNT) + { + continue_decoding = CORBA_B_FALSE; + break; + } - tcp = (CORBA_TypeCode_ptr *)data; + tcp = (CORBA_TypeCode_ptr *) data; - // - // Typecodes with empty parameter lists all have preallocated - // constants. We use those to reduce memory consumption and - // heap access ... also, to speed things up! - // - if (((*tcp) = __tc_consts [(unsigned) kind]) != 0) { - *tcp = __tc_consts [(unsigned) kind]; - break; - } else switch (kind) { - // + // Typecodes with empty parameter lists all have preallocated + // constants. We use those to reduce memory consumption and + // heap access ... also, to speed things up! + + if (((*tcp) = __tc_consts [(u_int) kind]) != 0) + { + *tcp = __tc_consts [(u_int) kind]; + break; + } + else + switch (kind) + { // Need special handling for all kinds of typecodes that have // nonempty parameter lists ... - // - default: // error: missed a case! - env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE)); - return CORBA_TypeCode::TRAVERSE_STOP; + default: // error: missed a case! + env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE)); + return CORBA_TypeCode::TRAVERSE_STOP; - // // Some have "simple" parameter lists ... some of these also // have preallocated constants that could be used. - // - case tk_string: - case tk_wstring: - { - CORBA_ULong bound; - - continue_decoding = stream->get_ulong (bound); - if (continue_decoding) { - if (bound == 0) { - if (kind == tk_string) - *tcp = _tc_CORBA_String; - else - *tcp = _tc_CORBA_WString; - } else { - *tcp = new CORBA_TypeCode ((CORBA_TCKind) kind, - bound, 0, CORBA_B_TRUE); - } - } + case tk_string: + case tk_wstring: + { + CORBA_ULong bound; + + continue_decoding = stream->get_ulong (bound); + if (continue_decoding) { + if (bound == 0) { + if (kind == tk_string) + *tcp = _tc_CORBA_String; + else + *tcp = _tc_CORBA_WString; + } else { + *tcp = new CORBA_TypeCode ((CORBA_TCKind) kind, + bound, 0, CORBA_B_TRUE); + } } - break; - - // - // Indirected typecodes, illegal at "top level" but we allow - // unmarshaling of them here because we use the same code to - // read "off the wire" (where they're illegal) and to read - // out of an encapsulation stream. We distinguish the case - // where this is legal as described above. - // - case ~0: - { - CORBA_TypeCode_ptr parent; - - if (parent_typecode == 0) { - env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE)); - return CORBA_TypeCode::TRAVERSE_STOP; - } - parent = (CORBA_TypeCode_ptr) parent_typecode; - - // - // Get the long indicating the encapsulation offset, - // then set up indirection stream that's like "stream" - // but has space enough only for the typecode and - // the length for the encapsulated parameters. - // - CDR indir_stream; - CORBA_Long offset; - - continue_decoding = stream->get_long (offset); - if (continue_decoding) - continue_decoding = (offset < 0); - if (continue_decoding) { - indir_stream.buffer = indir_stream.next - = stream->next + offset; - indir_stream.remaining = indir_stream.length = 8; - - // - // Reject indirections outside parent's scope. - // - if (indir_stream.next < parent->_buffer) - continue_decoding = CORBA_B_FALSE; - } - - // - // Get "kind" and length of target typecode - // - // XXX this currently assumes the TCKind to which - // we indirect is the same byte order as the "parent" - // typecode -- not the right assumption; see how - // the TypeCode interpreter does it. - // - CORBA_ULong indir_kind, indir_len; - - if (continue_decoding) - continue_decoding = stream->get_ulong (indir_kind); - if (continue_decoding - && indir_kind >= TC_KIND_COUNT) - continue_decoding = CORBA_B_FALSE; - if (continue_decoding) - continue_decoding = stream->get_ulong (indir_len); - - // - // Now construct indirected typecode. This shares the - // typecode octets with the "parent" typecode, increasing - // the amount of memory sharing and reducing the cost of - // getting typecodes. - // - if (continue_decoding) { - *tcp = new CORBA_TypeCode ( - (CORBA_TCKind) indir_kind, - indir_len, indir_stream.next, - CORBA_B_FALSE); - (*tcp)->_parent = parent; - parent->AddRef (); - } - } - break; - - // - // The rest have "complex" parameter lists that are - // encoded as bulk octets ... - // - case tk_objref: - case tk_struct: - case tk_union: - case tk_enum: - case tk_sequence: - case tk_array: - case tk_alias: - case tk_except: - { - unsigned len, i; - CORBA_ULong length; - CORBA_Octet *buffer; - - continue_decoding = stream->get_ulong (length); - if (!continue_decoding) - break; - - // if length > MAXUNSIGNED, error ... - len = (unsigned) length; - - buffer = new CORBA_Octet [len]; - - for (i = 0; i < len && continue_decoding; i++) - continue_decoding = stream->get_octet (buffer [i]); - - if (!continue_decoding) { - delete buffer; - break; - } - *tcp = new CORBA_TypeCode ((CORBA_TCKind)kind, - len, buffer, CORBA_B_TRUE); - } - } - } - break; - - case tk_Principal: - { - CORBA_Principal_ptr *pp = (CORBA_Principal_ptr *)data; - CORBA_ULong len; - - continue_decoding = stream->get_ulong (len); - if (len == 0) - *pp = 0; - else { - *pp = new CORBA_Principal; - (*pp)->id.buffer = new CORBA_Octet [(size_t) len]; - (*pp)->id.maximum = (*pp)->id.length = len; - - for (unsigned i = 0; - continue_decoding != CORBA_B_FALSE && i < len; - i++) - continue_decoding = stream->get_octet ( - (*pp)->id.buffer [i]); - } - } - break; + } + break; - case tk_objref: - { - // - // First, read the type hint. - // - CORBA_String type_hint; + // Indirected typecodes, illegal at "top level" but we + // allow unmarshaling of them here because we use the same + // code to read "off the wire" (where they're illegal) and + // to read out of an encapsulation stream. We distinguish + // the case where this is legal as described above. + case ~0: + { + CORBA_TypeCode_ptr parent; + + if (parent_typecode == 0) + { + env.exception (new CORBA_INTERNAL (COMPLETED_MAYBE)); + return CORBA_TypeCode::TRAVERSE_STOP; + } + parent = (CORBA_TypeCode_ptr) parent_typecode; + + // Get the long indicating the encapsulation offset, + // then set up indirection stream that's like "stream" + // but has space enough only for the typecode and the + // length for the encapsulated parameters. + CDR indir_stream; + CORBA_Long offset; + + continue_decoding = stream->get_long (offset); + if (continue_decoding) + continue_decoding = (offset < 0); + if (continue_decoding) + { + indir_stream.buffer = indir_stream.next + = stream->next + offset; + indir_stream.remaining = indir_stream.length = 8; + + // Reject indirections outside parent's scope. + if (indir_stream.next < parent->_buffer) + continue_decoding = CORBA_B_FALSE; + } + + // Get "kind" and length of target typecode + // + // XXX this currently assumes the TCKind to which we + // indirect is the same byte order as the "parent" + // typecode -- not the right assumption; see how the + // TypeCode interpreter does it. + + CORBA_ULong indir_kind; + CORBA_ULong indir_len; + + if (continue_decoding) + continue_decoding = stream->get_ulong (indir_kind); + if (continue_decoding + && indir_kind >= TC_KIND_COUNT) + continue_decoding = CORBA_B_FALSE; + if (continue_decoding) + continue_decoding = stream->get_ulong (indir_len); + + // Now construct indirected typecode. This shares the + // typecode octets with the "parent" typecode, + // increasing the amount of memory sharing and + // reducing the cost of getting typecodes. + if (continue_decoding) + { + *tcp = new CORBA_TypeCode ((CORBA_TCKind) indir_kind, + indir_len, + indir_stream.next, + CORBA_B_FALSE); + (*tcp)->_parent = parent; + parent->AddRef (); + } + } + break; - decoder (_tc_CORBA_String, &type_hint, 0, context, env); + // The rest have "complex" parameter lists that are + // encoded as bulk octets ... + case tk_objref: + case tk_struct: + case tk_union: + case tk_enum: + case tk_sequence: + case tk_array: + case tk_alias: + case tk_except: + { + u_int len; + u_int i; + CORBA_ULong length; + CORBA_Octet *buffer; + + continue_decoding = stream->get_ulong (length); + if (!continue_decoding) + break; + + // if length > MAXUNSIGNED, error ... + len = (u_int) length; + + buffer = new CORBA_Octet [len]; + + for (i = 0; i < len && continue_decoding; i++) + continue_decoding = stream->get_octet (buffer [i]); + + if (!continue_decoding) { + delete buffer; + break; + } + *tcp = new CORBA_TypeCode ((CORBA_TCKind) kind, + len, + buffer, + CORBA_B_TRUE); + } + } + } + break; + + case tk_Principal: + { + CORBA_Principal_ptr *pp = (CORBA_Principal_ptr *) data; + CORBA_ULong len; + + continue_decoding = stream->get_ulong (len); + if (len == 0) + *pp = 0; + else + { + *pp = new CORBA_Principal; + (*pp)->id.buffer = new CORBA_Octet [(size_t) len]; + (*pp)->id.maximum = (*pp)->id.length = len; + + for (u_int i = 0; + continue_decoding != CORBA_B_FALSE && i < len; + i++) + continue_decoding = stream->get_octet ((*pp)->id.buffer [i]); + } + } + break; + + case tk_objref: + { + // First, read the type hint. + + CORBA_String type_hint; + + decoder (_tc_CORBA_String, &type_hint, 0, context, env); + + // Read the profiles, discarding all until an IIOP profile + // comes by. Once we see an IIOP profile, ignore any further + // ones. + // + // XXX this will need to change someday to let different + // protocol code be accessed, not just IIOP. Protocol modules + // will be dynamically loaded from shared libraries via + // ORB_init(), and we just need to be able to access such + // preloaded libraries here as we unmarshal objrefs. - // - // Read the profiles, discarding all until an IIOP profile comes by. - // Once we see an IIOP profile, ignore any further ones. - // - // XXX this will need to change someday to let different protocol - // code be accessed, not just IIOP. Protocol modules will be - // dynamically loaded from shared libraries via ORB_init(), and - // we just need to be able to access such preloaded libraries here - // as we unmarshal objrefs. - // - CORBA_ULong profiles; - IIOP_Object *objdata = 0; + CORBA_ULong profiles; + IIOP_Object *objdata = 0; - stream->get_ulong (profiles); + stream->get_ulong (profiles); - // - // No profiles means a NIL objref. - // - if (profiles == 0) { - *(CORBA_Object_ptr *)data = CORBA_Object::_nil (); - delete type_hint; - break; - } - while (profiles-- != 0 && continue_decoding) { - CORBA_ULong tmp; - - stream->get_ulong (tmp); - if (tmp != IOP::TAG_INTERNET_IOP || objdata != 0) { - continue_decoding = stream->skip_string (); - continue; - } + // No profiles means a NIL objref. - // - // OK, we've got an IIOP profile. It's going to be - // encapsulated ProfileData. Create a new decoding - // stream and context for it, and tell the "parent" - // stream that this data isn't part of it any more. - // - continue_decoding = stream->get_ulong (tmp); - assert (stream->remaining >= tmp); + if (profiles == 0) + { + *(CORBA_Object_ptr *) data = CORBA_Object::_nil (); + delete type_hint; + break; + } - // - // Create the decoding stream from the encapsulation - // in the buffer, and skip the encapsulation. - // - CDR str; + while (profiles-- != 0 && continue_decoding) + { + CORBA_ULong tmp; - str.setup_encapsulation (stream->next, (size_t) tmp); + stream->get_ulong (tmp); - stream->next += (unsigned) tmp; - stream->remaining -= (unsigned) tmp; + if (tmp != IOP::TAG_INTERNET_IOP || objdata != 0) + { + continue_decoding = stream->skip_string (); + continue; + } - objdata = new IIOP_Object (type_hint); + // OK, we've got an IIOP profile. It's going to be + // encapsulated ProfileData. Create a new decoding stream + // and context for it, and tell the "parent" stream that + // this data isn't part of it any more. - IIOP::ProfileBody *profile = &objdata->profile; + continue_decoding = stream->get_ulong (tmp); + assert (stream->remaining >= tmp); - // - // Read and verify major, minor versions, ignoring - // IIOP profiles whose versions we don't understand. - // - // XXX this doesn't actually go back and skip the - // whole encapsulation... - // - if (!(str.get_octet (profile->iiop_version.major) - && profile->iiop_version.major == IIOP::MY_MAJOR - && str.get_octet (profile->iiop_version.minor) - && profile->iiop_version.minor <= IIOP::MY_MINOR)) { - dmsg2 ("detected new v%d.%d IIOP profile", - profile->iiop_version.major, - profile->iiop_version.minor); - objdata->type_id = 0; - objdata->Release (); - objdata = 0; - continue; - } - - // - // Get host and port - // - if (decoder (_tc_CORBA_String, &profile->host, 0, &str, env) - != CORBA_TypeCode::TRAVERSE_CONTINUE - || !str.get_ushort (profile->port)) { - env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); - dmsg ("error decoding IIOP host/port"); - objdata->Release (); - return CORBA_TypeCode::TRAVERSE_STOP; - } + // Create the decoding stream from the encapsulation in + // the buffer, and skip the encapsulation. + CDR str; - // - // ... and object key - // - continue_decoding = - (decoder (&TC_opaque, &profile->object_key, 0, &str, env) - == CORBA_TypeCode::TRAVERSE_CONTINUE); - - if (str.remaining != 0) { - env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); - dmsg ("extra data at end of IIOP profile data"); - objdata->Release (); - return CORBA_TypeCode::TRAVERSE_STOP; - } - } - if (objdata == 0) { - env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); - dmsg2 ("no IIOP v%d.%d (or earlier) profile in IOR!", - IIOP::MY_MAJOR, IIOP::MY_MINOR); - return CORBA_TypeCode::TRAVERSE_STOP; - } else { - if (objdata->QueryInterface (IID_CORBA_Object, (void **) data) - != NOERROR) - continue_decoding = CORBA_B_FALSE; - objdata->Release (); - } - } - break; + str.setup_encapsulation (stream->next, (size_t) tmp); - case tk_sequence: - { - // - // First unmarshal the sequence length ... we trust it - // to be right here, on the "be gracious in what you - // accept" principle. We don't generate illegal sequences - // (i.e. length > bounds). - // - CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data; + stream->next += (u_int) tmp; + stream->remaining -= (u_int) tmp; - continue_decoding = stream->get_ulong (seq->length); - seq->maximum = seq->length; - seq->buffer = 0; + objdata = new IIOP_Object (type_hint); - // - // Fast exit on empty sequences or errors - // - if (!continue_decoding || seq->length == 0) - break; + IIOP::ProfileBody *profile = &objdata->profile; + // Read and verify major, minor versions, ignoring IIOP + // profiles whose versions we don't understand. // - // ... then allocate the memory into which we'll unmarshal - // - CORBA_TypeCode_ptr tc2; - size_t size; - - tc2 = tc->typecode_param (0, env); - if (env.exception ()) - return CORBA_TypeCode::TRAVERSE_STOP; - - size = tc2->size (env); - if (env.exception ()) + // XXX this doesn't actually go back and skip the whole + // encapsulation... + if (!(str.get_octet (profile->iiop_version.major) + && profile->iiop_version.major == IIOP::MY_MAJOR + && str.get_octet (profile->iiop_version.minor) + && profile->iiop_version.minor <= IIOP::MY_MINOR)) + { + dmsg2 ("detected new v%d.%d IIOP profile", + profile->iiop_version.major, + profile->iiop_version.minor); + objdata->type_id = 0; + objdata->Release (); + objdata = 0; + continue; + } + + // Get host and port + if (decoder (_tc_CORBA_String, &profile->host, 0, &str, env) + != CORBA_TypeCode::TRAVERSE_CONTINUE + || !str.get_ushort (profile->port)) + { + env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); + dmsg ("error decoding IIOP host/port"); + objdata->Release (); return CORBA_TypeCode::TRAVERSE_STOP; + } - tc2->Release (); + // ... and object key - seq->buffer = new CORBA_Octet [size * (size_t) seq->maximum]; - } - // FALLTHROUGH + continue_decoding = decoder (&TC_opaque, + &profile->object_key, + 0, + &str, + env) == CORBA_TypeCode::TRAVERSE_CONTINUE; - case tk_struct: - case tk_union: - case tk_array: - case tk_alias: - // - // Unmarshal all the individual elements using the per-member - // description held in the "parent" TypeCode. - // + if (str.remaining != 0) + { + env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); + dmsg ("extra data at end of IIOP profile data"); + objdata->Release (); + return CORBA_TypeCode::TRAVERSE_STOP; + } + } + if (objdata == 0) + { + env.exception (new CORBA_MARSHAL (COMPLETED_MAYBE)); + dmsg2 ("no IIOP v%d.%d (or earlier) profile in IOR!", + IIOP::MY_MAJOR, IIOP::MY_MINOR); + return CORBA_TypeCode::TRAVERSE_STOP; + } + else + { + if (objdata->QueryInterface (IID_CORBA_Object, + (void **) data) != NOERROR) + continue_decoding = CORBA_B_FALSE; + objdata->Release (); + } + } + break; + + case tk_sequence: + { + // First unmarshal the sequence length ... we trust it to be + // right here, on the "be gracious in what you accept" + // principle. We don't generate illegal sequences + // (i.e. length > bounds). + + CORBA_OctetSeq *seq = (CORBA_OctetSeq *) data; + + continue_decoding = stream->get_ulong (seq->length); + seq->maximum = seq->length; + seq->buffer = 0; + + // Fast exit on empty sequences or errors + if (!continue_decoding || seq->length == 0) + break; + + // ... then allocate the memory into which we'll unmarshal + CORBA_TypeCode_ptr tc2; + size_t size; + + tc2 = tc->typecode_param (0, env); + if (env.exception ()) + return CORBA_TypeCode::TRAVERSE_STOP; + + size = tc2->size (env); + if (env.exception ()) + return CORBA_TypeCode::TRAVERSE_STOP; + + tc2->Release (); + + seq->buffer = new CORBA_Octet [size * (size_t) seq->maximum]; + } + // FALLTHROUGH + + case tk_struct: + case tk_union: + case tk_array: + case tk_alias: + // Unmarshal all the individual elements using the per-member + // description held in the "parent" TypeCode. - // FALLTHROUGH - - case tk_except: + // FALLTHROUGH + + case tk_except: + // For exceptions, the "hidden" type ID near the front of the + // on-wire representation was previously unmarshaled and mapped + // to the "tc" typcode we're using to traverse the memory ... + // at the same time its vtable, refcount, and other state was + // established. + // + // NOTE: This is asymmetric with respect to encoding exceptions. + return tc->traverse (data, 0, decoder, context, env); + + case tk_string: + { + CORBA_String str; + CORBA_ULong len = 0; + + // On decode, omit the check against specified string bounds, + // and cope with illegal "zero length" strings (all lengths on + // the wire must include a NUL). // - // For exceptions, the "hidden" type ID near the front of the - // on-wire representation was previously unmarshaled and mapped - // to the "tc" typcode we're using to traverse the memory ... - // at the same time its vtable, refcount, and other state was - // established. - // - // NOTE: This is asymmetric with respect to encoding exceptions. - // - return tc->traverse (data, 0, decoder, context, env); + // This is on the principle of being gracious in what we + // accept; we don't generate messages that fail to comply with + // protocol specs, but we will accept them when it's clear how + // to do so. + + continue_decoding = stream->get_ulong (len); + *((CORBA_String*) data) = str = new CORBA_Char [(size_t) (len)]; + + if (len != 0) + while (continue_decoding != CORBA_B_FALSE && len-- != 0) + { + continue_decoding = stream->get_char (*(CORBA_Char *) str); + str++; + } + break; + } - case tk_string: - { - CORBA_String str; - CORBA_ULong len = 0; + case tk_wstring: + { + CORBA_WChar *str; + CORBA_ULong len = 0; - // - // On decode, omit the check against specified string bounds, - // and cope with illegal "zero length" strings (all lengths - // on the wire must include a NUL). - // - // This is on the principle of being gracious in what we accept; - // we don't generate messages that fail to comply with protocol - // specs, but we will accept them when it's clear how to do so. - // - continue_decoding = stream->get_ulong (len); - *((CORBA_String*)data) = str = new CORBA_Char [(size_t) (len)]; - if (len != 0) - while (continue_decoding != CORBA_B_FALSE && len-- != 0) { - continue_decoding = stream->get_char (*(CORBA_Char *)str); - str++; - } - break; - } + // On decode, omit the check against specified wstring bounds, + // and cope with illegal "zero length" strings (all lengths on + // the wire must include a NUL). + // + // This is on the principle of being gracious in what we + // accept; we don't generate messages that fail to comply with + // protocol specs, but we will accept them when it's clear how + // to do so. - case tk_wstring: - { - CORBA_WChar *str; - CORBA_ULong len = 0; + continue_decoding = stream->get_ulong (len); - // - // On decode, omit the check against specified wstring bounds, - // and cope with illegal "zero length" strings (all lengths - // on the wire must include a NUL). - // - // This is on the principle of being gracious in what we accept; - // we don't generate messages that fail to comply with protocol - // specs, but we will accept them when it's clear how to do so. - // - continue_decoding = stream->get_ulong (len); - *((CORBA_WChar **)data) = str = new CORBA_WChar [(size_t) (len)]; - if (len != 0) { - while (continue_decoding != CORBA_B_FALSE && len--) { - continue_decoding = stream->get_wchar (*str); - str++; - } + *((CORBA_WChar **) data) = str = new CORBA_WChar [(size_t) (len)]; + + if (len != 0) + while (continue_decoding != CORBA_B_FALSE && len--) + { + continue_decoding = stream->get_wchar (*str); + str++; } - } - break; + } + break; - case tk_longdouble: - continue_decoding = - stream->get_longdouble (*(CORBA_LongDouble *)data); - break; + case tk_longdouble: + continue_decoding = stream->get_longdouble (*(CORBA_LongDouble *) data); + break; - case tk_wchar: - continue_decoding = stream->get_wchar (*(CORBA_WChar *)data); - break; + case tk_wchar: + continue_decoding = stream->get_wchar (*(CORBA_WChar *) data); + break; // case ~0: - default: - continue_decoding = CORBA_B_FALSE; - dmsg ("decode, default case?"); - break; + default: + continue_decoding = CORBA_B_FALSE; + dmsg ("decode, default case?"); + break; } - if (continue_decoding == CORBA_B_FALSE) { - env.exception (new CORBA_MARSHAL (COMPLETED_NO)); - dmsg ("marshaling decoder detected error"); - return CORBA_TypeCode::TRAVERSE_STOP; + if (continue_decoding == CORBA_B_FALSE) + { + env.exception (new CORBA_MARSHAL (COMPLETED_NO)); + dmsg ("marshaling decoder detected error"); + return CORBA_TypeCode::TRAVERSE_STOP; } - return CORBA_TypeCode::TRAVERSE_CONTINUE; + return CORBA_TypeCode::TRAVERSE_CONTINUE; } |