How do I read request arguments in a ServerInterceptor receive request method?

From Support
Jump to: navigation, search

Question:

How do I read request arguments in a ServerInterceptor receive_request method?

Answer:

A ServerInterceptor read_request method read request arguments and perform actions or logging based on the request. If the receive_request interceptor does not return a new MarshalInBuffer, then care must be taken to leave the original buffer in a state that is compatible with the request skeleton marshal code.

This note explains the internal state of the MarshalInBuffer passed to the receive_request interceptor method, and how to make a safe copy for reading only.

On the server side there is an internal optimization that causes the
MarshalInBuffer to be in a slightly unusual state.  The buffer is
delivered to the skeleton (or interceptor code if present) without the
GIOP message header, but does include the request header.  The offset is
set to the beginning of the arguments data. In order to ensure that the
marshaling routines can correctly account for alignment/padding, the
internal buffer _start_offset variable used to control padding/alignment
assumptions is adjusted and does not match the actual buffer offset
(normally they are the same or the _start_offset is zeroed for an new
encapsulation).

In the case where the marshal buffer is delivered directly to the
skeleton method, or in the case where an interceptor is used to replace
the buffer completely there are no issues with this design.  But in the
case where an interceptor simply needs to read the data this internal
state must be known and accounted for.  If the input buffer is read
directly, there is no API available to reset it into its initial state
because there is no way to independently set the _start_offset value. If
the seekpos() method is used to reset the offset, this has a side effect
of resetting the _start_offset and causes a marshaling error when the
skeleton attempts to read the data.

If the application tries to construct a new buffer, again the buffer
offset and _start_offset will be the same. The natural thing to do is to
build a copy that starts at offset 0, or offset 40, but both of these
will result in a  _start_offset that is wrong (for the marshaling
algorithm).

The way to overcome this is to construct the buffer with a starting
point that is slightly prior to the actual data, then move the offset to
the starting point of the data.  As long as the starting point sets up a
_start_offset value which preserves the original offset relative to the
start of the buffer then the reader will properly handle the
padding/alighnment issues.

The following is a general workaround:
 

virtual CORBA_MarshalInBuffer *receive_request(
        GIOP::RequestHeader&            hdr,
        CORBA::Object *& target         target,
        CORBA_MarshalInBuffer *         buf,
        VISClosure&                     closure)
{
     // buf has _start_offset = _cur_off + GIOP_MSGHDR_LEN, so
     // make a copy with "correct" _cur_off and _start_offset values
     // to preserve alignment/padding rules.

     CORBA::ULong adjust =   buf->curoff() - GIOP_MSGHDR_LEN;
     CORBA_MarshalInBuffer  arg_buf(buf->buffer() + adjust,
                                    buf->length() - adjust);
     arg_buf.seekpos(GIOP_MSGHDR_LEN);

     // read values from arg_buf, input buf is not modified
     // ...

     return 0;
}
 



Article originally contributed by