Digital DCE for OpenVMS VAX and OpenVMS Alpha
Product Guide


Previous Contents Index


Chapter 15
IDL Encoding Services

IDL Encoding Services are a feature of the IDL compiler, which separates out the data marshalling and unmarshalling functions from the interaction with the RPC runtime.

The compiler can generate code that takes the input parameters to a procedure and places them in a standard form in one or more buffers that are delivered to user code. This is called encoding. Encoded data can be written to a file or forwarded by a messaging system.

The compiler can also generate code that delivers as the output parameters of a procedure data that has been converted into the standard form by encoding. Delivery of data in this way is called decoding. Data to be decoded can be read from a file or received by a messaging system.

15.1 Attribute Configuration File (ACF) Attributes

Stubs that perform encoding or decoding operations are different from the stubs that perform RPC operations. ACF attributes are used to direct the IDL compiler to generate IDL Encoding Services stubs for operations. The attributes used are encode and decode.

The attributes may be used as operation attributes or as interface attributes. If either encode or decode is used as an interface attribute, the effect is as if it had been applied to every operation in the interface.

Operation stubs to perform encoding or decoding are generated into the client stub module. If an operation has the encode or decode attribute, no code for it is generated into the server stub. If all the operations in an interface have the encode or decode attribute, the IDL compiler will not generate a server stub module.

If these attributes are used only as operation attributes on some of the operations in an interface, the stubs for operations to which they are not applied become RPC stubs.

Therefore, if the following interface:


[uuid(20aac780-5398-11c9-b996-08002b13d56d), version(0)] 
interface es_array 
{ 
    void in_array_op1([in] handle_t h, [in] long arr[100]); 
    void out_array_op1([in] handle_t h, [out] long arr[100]); 
    void array_op2([in] handle_t h, [in,out] long big[100]); 
    void array_op3([in] handle_t h, [in,out] long big[100]); 
} 

is compiled with the ACF:


interface es_array 
{ 
    [encode] in_array_op1(); 
    [decode] out_array_op1(); 
    [encode, decode] array_op2(); 
} 

the operation stubs in the client stub module are as follows:
in_array_op1 IDL Encoding Services stub supporting encoding only
out_array_op1 IDL Encoding Services stub supporting decoding only
array_op2 IDL Encoding Services stub supporting encoding and decoding
array_op3 RPC client stub

Interaction of Attributes

When encoding of data is taking place, only the in parameters of an operation provide data for the encoding.

When decoding of data is taking place, data is delivered only to the out parameters of the operation.

Normal use of IDL Encoding Services where data is being both encoded and decoded is for all the parameters of an operation to be in, out. However, you can encode data using the in parameters of one operation, and decode it using the out parameters of another operation if the types and order of these parameters are the same. For equivalence, a function result is treated as an out parameter appearing after all other out parameters.

15.2 Buffering Styles

There are a number of different ways in which buffers containing encoded data can be passed betweeen user code and IDL Encoding Services. These are referred to as different buffering styles. The different buffering styles are as follows:

15.2.1 Incremental Encoding

This style of buffering requires that you provide an allocate routine which delivers an empty buffer into which IDL Encoding Services can place encoded data and a write routine which IDL Encoding Services will call when the buffer is full or all the parameters of the operation have been encoded.

The allocate routine must be of the type idl_es_allocate_fn_t defined by:


typedef void (*idl_es_allocate_fn_t)(     
    idl_void_p_t    state, 
    idl_byte     **buf, 
    idl_ulong_int   *size 
); 

The parameters of such an allocate routine are as follows:
state Pointer to a user-defined data structure that may be used to coordinate the actions of the allocate and write routines.
buf Address to which the allocate routine must write the address of the buffer into which IDL Encoding Services is to place encoded data. This address must be 8-byte aligned.
size When this routine is called, the value at the address indicated by size is the size of buffer that IDL Encoding Services would like the routine to allocate. The routine must write to this address the size of the buffer it actually allocated. This size must be a multiple of 8 bytes.

The write routine must be of the type idl_es_write_fn_t defined by the following:


typedef void (*idl_es_write_fn_t)(           
    idl_void_p_t    state 
    idl_byte     *buf, 
    idl_ulong_int   size 
); 

The parameters of such a write routine are as follows:
state A pointer to a user-defined data structure that may be used to coordinate the actions of the allocate and write routines.
buf The address of the encoded data provided by IDL Encoding Services.
size The size, in bytes, of the encoded data provided by IDL Encoding Services.

These routines are called repeatedly by IDL Encoding Services until the encoding of all of the parameters has been delivered to the user code.

15.2.2 Fixed Buffer Encoding

This buffering style requires that you supply a single buffer into which all the encoded data is to be placed.

This buffer must have the following characteristics:

56 bytes should be allowed for each encoding header.

15.2.3 Dynamic Buffer Encoding

Using this buffering style, a single buffer containing all the encoded data is built by IDL Encoding Services and delivered to user code. The buffer is allocated by whatever client memory management mechanism has been put in place by user code. The default for this is malloc. When the buffer is no longer needed by the user code, it should release the memory resource.

There are performance implications in this style. IDL Encoding Services will usually allocate a number of intermediate buffers, then allocate the buffer to be delivered to the user, copy data into it from the intermediate buffers, and release the intermediate buffers.

15.2.4 Incremental Decoding

This buffering style requires that you provide a read routine which, when called, delivers to IDL Encoding Services a buffer containing the next part of the data to be decoded.

The read routine must be of the type idl_es_read_fn_t defined by:


typedef void (*idl_es_read_fn_t)( 
    idl_void_p_t state, 
    idl_byte **buf, 
    idl_ulong_int *size 
); 

The parameters of such a read routine are as follows:
state A pointer to a user-defined data structure that may be used to coordinate the actions of a sequence of calls to the routine.
buf The address to which the read routine must write the address of the buffer from which IDL Encoding Services is to obtain encoded data. This address must be 8-byte aligned.
size The address to which the read routine must write the size of the buffer from which IDL Encoding Services is to obtain encoded data. If this is not the last buffer from which IDL Encoding Services will need to obtain data, this size must be a multiple of 8 bytes.

This routine is called repeatedly by IDL Encoding Services until all the required data has been decoded.

15.2.5 Buffer Decoding

This buffering style requires that you supply a single buffer containing all the encoded data.

Where application performance is important, note that if the supplied buffer is not 8-byte aligned, IDL Encoding Services allocates a temporary aligned buffer of comparable size and copies data from the user-supplied buffer into it before performing the requested decoding.

15.3 IDL Encoding Services Handles

When an encoding or decoding operation is invoked, the handle it is passed must be of type idl_es_handle_t. This handle indicates whether encoding or decoding is required, and what style of buffering is to be used.

It is an error to call an operation for which encode or decode has been specified using an RPC binding handle, and it is an error to call an RPC operation using an IDL Encoding Services handle.

15.3.1 Restrictions on the Use of Handles

The following restrictions apply when using IDL Encoding Services Handles:

15.3.2 Obtaining a Handle

A set of routines is provided to enable user code to obtain an appropriate handle to use IDL Encoding Services. This section describes the following routines:

15.3.3 Incremental Encoding Handle

The following routine must be called to obtain an incremental encoding handle:


void idl_es_encode_incremental( 
    idl_void_p_t     state, 
    idl_es_allocate_fn_t    alloc, 
    idl_es_write_fn_t     write, 
    idl_es_handle_t     *h, 
    error_status_t     *st 
); 

The parameters for the routine that is used to obtain an incremental encoding handle are as follows:
state The address of the user state block that coordinates the actions of the allocate and write routines.
alloc The address of the user allocate routine.
write The address of the user write routine.
h The address to which the handle is written.
st The address to which a status code is written.

15.3.4 Fixed Buffer Encoding Handle

The following routine must be called to obtain a fixed buffer encoding handle:


void idl_es_encode_fixed_buffer( 
    idl_byte      *ep, 
    idl_ulong_int     bsize, 
    idl_ulong_int     *esize, 
    idl_es_handle_t     *h, 
    error_status_t     *st 
); 

The parameters for the routine that is used to obtain a fixed buffer encoding handle are as follows:
ep The address of the user-supplied buffer. Must be 8-byte aligned.
bsize The size of the user-supplied buffer. Must be a multiple of 8 bytes.
esize The address to which IDL Encoding Services writes the size of the encoding when it is complete.
h The address to which the handle is written.
st The address to which a status code is written.

15.3.5 Dynamic Buffer Encoding Handle

The following routine must be called to obtain a dynamic buffer encoding handle:


void idl_es_encode_dyn_buffer( 
    idl_byte      **ep, 
    idl_ulong_int     *esize, 
    idl_es_handle_t     *h, 
    error_status_t     *st 
); 

The parameters for the routine that is used to obtain a dynamic buffer encoding handle are as follows:
ep The address to which IDL Encoding Services will write the address of the buffer containing the encoded data when the encoding is complete. When the buffer is no longer needed by the user code, it should release the memory resource.
size The address to which IDL Encoding Services will write the size of the buffer containing the encoded data when the encoding is complete.
h The address to which the handle is written.
st The address to which a status code is written.

15.3.6 Incremental Decoding Handle

The following routine must be called to obtain an incremental decoding handle:


void idl_es_decode_incremental( 
    idl_void_p_t     state, 
    idl_es_read_fn_t     write, 
    idl_es_handle_t     *h, 
    error_status_t     *st 
); 

The parameters for the routine that is used to obtain an incremental decoding handle are as follows:
state The address of the user state block which coordinates the actions of successive calls to the read routine.
read The address of the user read routine.
h The address to which the handle is written.
st The address to which a status code is written.

15.3.6.1 Buffer Decoding Handle

The following routine must be called to obtain a buffer decoding handle:


void idl_es_decode_buffer( 
    idl_byte      *ep, 
    idl_ulong_int     size, 
    idl_es_handle_t     *h, 
    error_status_t     *st 
); 

The parameters for the routine that is used to obtain a buffer decoding handle are as follows:
ep The address of the buffer containing the data to be decoded.
size The number of bytes of data in the buffer to be decoded.
h The address to which the handle is written.
st The address to which a status code is written.

15.3.7 Releasing a Handle

When the encoding or decoding for which the handle was required is completed, user code should release the handle resources. It does this by calling the following routine:


void idl_es_handle_free 
( 
    idl_es_handle_t *h, 
    error_status_t *st 
) 

The parameters for the routine are as follows:
h The address of the handle whose resources are to be freed. The handle will be made NULL by this operation.
st The address to which a status code will be written.

15.4 Programming Example

The following example uses the features described in the preceding sections. The example verifies that the results of a number of decoding operations are the same as the parameters used to create the corresponding encodings.

The IDL for this example is as follows:


[uuid(20aac780-5398-11c9-b996-08002b13d56d), version(0)] 
interface es_array 
{ 
    const long N = 5000; 
 
    typedef struct 
    { 
        byte b; 
        long l; 
    } s_t; 
 
    typedef struct 
    { 
        byte b; 
        long a[7]; 
    } t_t; 
 
    void in_array_op1([in] handle_t h, [in] long arr[N]); 
    void out_array_op1([in] handle_t h, [out] long arr[N]); 
 
    void array_op2([in] handle_t h, [in,out] s_t big[N]); 
 
    void array_op3([in] handle_t h, [in,out] t_t big[N]); 
} 

The ACF for the example is as follows:


interface es_array 
{ 
    [encode] in_array_op1(); 
    [decode] out_array_op1(); 
    [encode, decode] array_op2(); 
    [encode, decode] array_op3(); 
} 

The test code for the example is as follows:


#include <DCE/PTHREAD_EXC.H> 
#include "rpcexc.h" 
#include <STDIO.H> 
#include <STDLIB.H> 
#if defined(VMS) || defined(__VMS) 
#include <FILE.H> 
#else 
#include <SYS/FILE.H> 
#endif 
#include <DCE/ES_ARRAY.H> 
 
/* 
 *  User state for incremental encode/decode 
 */ 
typedef struct es_state_t { 
    idl_byte *malloced_addr; 
    int file_handle; 
} es_state_t; 
 
static es_state_t es_state; 
 
#define OUT_BUFF_SIZE 2048 
static idl_byte out_buff[OUT_BUFF_SIZE]; 
static idl_byte *out_data_addr; 
static idl_ulong_int out_data_size; 
 
/* 
 *  User allocate routine for incremental encode 
 */ 
void es_allocate(state, buf, size) 
idl_void_p_t state; 
idl_byte **buf; 
idl_ulong_int *size; 
{ 
    idl_byte *malloced_addr; 
    es_state_t *p_es_state = (es_state_t *)state; 
 
    malloced_addr = (idl_byte *)malloc(*size); 
    p_es_state->malloced_addr = malloced_addr; 
    *buf = (idl_byte *)(((malloced_addr - (idl_byte *)0) + 7) & (~7)); 
    *size = (*size - (*buf - malloced_addr)) & (~7); 
} 
 
/* 
 *  User write routine for incremental encode 
 */ 
void es_write(state, buf, size) 
idl_void_p_t state; 
idl_byte *buf; 
idl_ulong_int size; 
{ 
    es_state_t *p_es_state = (es_state_t *)state; 
 
    write(p_es_state->file_handle, buf, size); 
    free(p_es_state->malloced_addr); 
} 
 
/* 
 *  User read routine for incremental decode 
 */ 
void es_read(state, buf, size) 
idl_void_p_t state; 
idl_byte **buf; 
idl_ulong_int *size; 
{ 
    es_state_t *p_es_state = (es_state_t *)state; 
 
    read(p_es_state->file_handle, out_data_addr, out_data_size); 
    *buf = out_data_addr; 
    *size = out_data_size; 
} 
 
static ndr_long_int arr[N]; 
static ndr_long_int out_arr[N]; 
static s_t sarr[N]; 
static s_t ref_sarr[N]; 
static s_t out_sarr[N]; 
static t_t tarr[N]; 
static t_t ref_tarr[N]; 
static t_t out_tarr[N]; 
static ndr_long_int (*oarr)[M]; 
 
#define FIXED_BUFF_STORE (8*N+64) 
static idl_byte fixed_buff_area[FIXED_BUFF_STORE]; 
 
/* 
 *  Test Program 
 */ 
main() 
{ 
    idl_es_handle_t es_h; 
    idl_byte *fixed_buff_start; 
    idl_ulong_int fixed_buff_size, encoding_size; 
    idl_byte *dyn_buff_start; 
    error_status_t status; 
    int i,j; 
 
 
    for (i = 0; i   N; i++) 
    { 
        arr[i] = random()%10000; 
        sarr[i].b = i & 0x7f; 
        sarr[i].l = random()%10000; 
        ref_sarr[i] = sarr[i]; 
        tarr[i].b = i & 0x7f; 
        for (j = 0; j   7; j++) tarr[i].a[j] = random()%10000; 
        ref_tarr[i] = tarr[i]; 
    } 
.nP 
    /* 
     *Incremental encode/decode 
     */ 
    /* Encode data using one operation */ 
es_state.file_handle = open("es_array_1.dat", O_CREAT|O_TRUNC|O_WRONLY, 
                                                              0777); 
    if (es_state.file_handle   0) 
    { 
        printf("Can't open es_array_1.dat\en"); 
        exit(0); 
    } 
idl_es_encode_incremental((idl_void_p_t)&es_state, es_allocate, es_write, 
                                &es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_encode_incremental\en", status); 
        exit(0); 
    } 
    in_array_op1(es_h, arr); 
    close(es_state.file_handle); 
    idl_es_handle_free(&es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_handle_free\en", status); 
        exit(0); 
    } 
 
    /* Decode the data using another operation with the same signature */ 
    out_data_addr = (idl_byte *)(((out_buff - (idl_byte *)0) + 7) & (~7)); 
    out_data_size = (OUT_BUFF_SIZE - (out_data_addr - out_buff)) & (~7); 
    es_state.file_handle = open("es_array_1.dat", O_RDONLY, 0); 
    if (es_state.file_handle   0) 
    { 
        printf("Can't open es_array_1.dat for reading\en"); 
        exit(0); 
    } 
    idl_es_decode_incremental((idl_void_p_t)&es_state, es_read, 
                                &es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_decode_incremental\en", status); 
        exit(0); 
    } 
    out_array_op1(es_h, out_arr); 
    close(es_state.file_handle); 
    idl_es_handle_free(&es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_handle_free\en", status); 
        exit(0); 
    } 
 
    /* Check the input and output are the same */ 
    for (i = 0; i   N; i++) 
    { 
        if (out_arr[i] != arr[i]) 
        { 
            printf("out_arr[%d] - found %d - expecting %d\en", 
                    i, out_arr[i], arr[i]); 
        } 
    } 
 
    /* 
     * Fixed buffer encode/decode 
     */ 
fixed_buff_start = (idl_byte *)(((fixed_buff_area - (idl_byte *)0) + 7) 
                                                               & (~7)); 
fixed_buff_size = (FIXED_BUFF_STORE - (fixed_buff_start - fixed_buff_area)) 
                                                                & (~7); 
    idl_es_encode_fixed_buffer(fixed_buff_start, fixed_buff_size, 
                                &encoding_size, &es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_encode_fixed_buffer\en", status); 
        exit(0); 
    } 
    array_op2(es_h, sarr); 
    idl_es_handle_free(&es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_handle_free\en", status); 
        exit(0); 
    } 
    idl_es_decode_buffer(fixed_buff_start, encoding_size, &es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_decode_buffer\en", status); 
        exit(0); 
    } 
    array_op2(es_h, out_sarr); 
    idl_es_handle_free(&es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_handle_free\en", status); 
        exit(0); 
    } 
    for (i = 0; i   N; i++) 
    { 
        if (out_sarr[i].b != ref_sarr[i].b) 
        { 
          printf("array_op2 - out_sarr[%d].b = %c\en", i, out_sarr[i].b); 
        } 
        if (out_sarr[i].l != ref_sarr[i].l) 
        { 
          printf("array_op2 - out_sarr[%d].l = %d\en", i, out_sarr[i].l); 
        } 
    } 
 
    /* 
     * Dynamic buffer encode - fixed buffer decode 
     */ 
idl_es_encode_dyn_buffer(&dyn_buff_start, &encoding_size, &es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_encode_dyn_buffer\en", status); 
        exit(0); 
    } 
    array_op3(es_h, tarr); 
    free (dyn_buff_start); 
    idl_es_handle_free(&es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_handle_free\en", status); 
        exit(0); 
    } 
    idl_es_decode_buffer(dyn_buff_start, encoding_size, &es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_decode_buffer\en", status); 
        exit(0); 
    } 
    array_op3(es_h, out_tarr); 
    free (dyn_buff_start); 
    idl_es_handle_free(&es_h, &status); 
    if (status != error_status_ok) 
    { 
        printf("Error %08x from idl_es_handle_free\en", status); 
        exit(0); 
    } 
    for (i = 0; i   N; i++) 
    { 
        if (out_tarr[i].b != ref_tarr[i].b) 
        { 
         printf("array_op3 - out_tarr[%d].b = %c\en", i, out_tarr[i].b); 
        } 
        for (j=0; j 7; j++) 
        { 
            if (out_tarr[i].a[j] != ref_tarr[i].a[j]) 
            { 
                printf("array_op3 - out_tarr[%d].a[%d] = %d\en", 
                        i, j, out_tarr[i].a[j]); 
            } 
        } 
    } 
 
    printf("Test Complete\en"); 
} 


Previous Next Contents Index