Previous section.

CDE 1.1: Remote Procedure Call
Copyright © 1997 The Open Group

Stubs

The IDL source and any ACS are used to generate client and server stubs for a specified interface. Except for data type and syntax mappings, specified for the C language in IDL to C-language Mappings , the mappings of IDL and ACS to stub code for a given language are mostly implementation-dependent. However, there are certain additional portability requirements on the application/stub interface as well as interoperability requirements on stub code. These requirements are specified in the following sections.

The Application/Stub Interface

Applications interact with the stub mainly by calling IDL specified remote interfaces (on the client side) and by implementing managers for these interfaces (on the server side). However, in certain cases, applications need to be aware of specific details of stub code. These include:

The following sections specify these aspects of stub code. Where appropriate, they provide C bindings that portable C applications must adhere to.

Parameters

Parameter semantics depend on the IDL directional attributes as follows:

In the event of an abnormal end-of-call, resulting from either an exception condition on the server (which may be reported through fault_status parameter) or a communications failure (which may be reported through comm_status parameter) the values of out parameters are undefined.

Parameter Memory Management
RPC attempts to extend local procedure call parameter memory management semantics to a situation in which the calling and called procedure no longer share the same memory space. In effect, parameter memory has to be allocated twice, once on the client side, once on the server side. Stubs do as much of the extra allocation work as possible so that the complexities of parameter allocation are transparent to applications. In some cases, however, applications may have to manage parameter memory in a way that differs from the usual local procedure call semantics. This section specifies stub and application requirements on parameter allocation.

For the purposes of memory allocation, three classes of parameter need to be considered:

For all types, the client application supplies parameters to the client stub, which marshals them for transmission to the server. The client application is entirely responsible for managing the memory occupied by the passed parameters. On the server side, the server stub allocates and frees all memory required for the received parameters themselves.

In the case of the pointer types, however, the application and stubs must manage memory not only for the parameters themselves, but also for the pointed-to nodes. In this case, the memory management requirements depend both on the pointer type and on the parameter's directional attributes.

The rules are as follows.

Client-side Allocation

in parameters
For all pointer types, the client application must allocate memory for the pointed-to nodes.

out parameters
For reference pointers, the client application must allocate memory for the pointed-to nodes unless the pointer is part of a data structure created by server manager code. For parameters containing full pointers, the stub allocates memory for the pointed-to nodes.

in, out parameters
For reference pointers, the client application must allocate memory for the pointed-to nodes. For full pointers, on making the call, the client application must allocate memory for the pointed-to node. On return, the stub keeps track of whether each parameter is the original full pointer passed by the client, or a new pointer allocated by the server. If a pointer is unchanged, the returned data overwrites the existing pointed-to node. If a pointer is new, the stub allocates memory for the pointed-to node. When a parameter contains pointers, such as an element in a linked list, the stub keeps track of the chain of references, allocating nodes as necessary.

It is the client application's responsibility to free any memory allocated by the stub for new nodes. Clients can call the routine rpc_sm_client_free() for this purpose.

If the server deletes or eliminates a reference to a pointed to node, an "orphaned" node may be created on the client side. It is the client application's responsibility to keep track of memory that it has allocated for pointed-to nodes and to deal with any nodes for which the server no longer has references.

The reflect_deletions attribute is useful in this regard. See The reflect_deletions Attribute for more information.

Server-side Allocation

in parameters
For all pointer types, the stub manages all memory for pointed-to nodes.

out parameters
For reference pointers, the stub allocates memory for the pointed-to nodes as long as the size of the targets can be determined at compile time. When the manager routine is entered, such reference pointers point to valid storage. For parameters that contain full pointers, the server manager code must allocate memory for pointed-to nodes. Servers can call the routine rpc_sm_allocate() for this purpose.

in, out parameters
For reference pointers, the stub allocates memory for pointed-to nodes if either the size of the pointed to nodes can be determined at compile time or the reference pointers point to values received from the client. When the manager routine is entered, such reference pointers point to valid storage. For full pointers, the stub allocates memory for the original pointed-to nodes. The server manager code must allocate memory if it creates new references. Servers can call the routine rpc_sm_allocate() for this purpose.

The server stub automatically frees all memory allocated by calls to rpc_sm_allocate().

Aliasing

For both out and in, out parameters, when full pointers are aliases, according to the rules specified in Aliasing in Parameter Lists , the stubs maintain the pointed-to objects such that any changes made by the server are reflected to the client for all aliases. The stubs detect and correctly handle aliasing both in the case where an alias exists on initiation of an RPC and in the case where an alias is created by the server.

Default Manager EPVs

The IDL compiler must be able to generate server stubs that contain a default manager EPV, as described in RPC Data Types .

Interface Handle

The stub must declare an interface handle according to the naming conventions specified in RPC Data Types .

Pipes

At the caller user code to caller stub interface and the callee stub to callee user code interface, pipes appear as a simple callback mechanism. The processing of a pipe parameter appears to be synchronous to the user-written code. The mechanism implemented in the RPC stub and run-time system allows these apparent callbacks to happen without a real remote callback; therefore, the mechanism is very efficient.

A pipe is declared in a type definition of an interface definition, and the data type is used as parameters in the operations of the interface. The sequence and origin of stub pipe support calls depends on both the caller and the direction of the pipe; the list that appears later in this discussion provides more detail.

Pipe processing is subject to the following restrictions:

Pipes are defined as type constructors rather than as type attributes because they are manifested at the programming interface in a non-obvious way.

As an example of a pipe, consider the following IDL fragment:

typedef pipe element_t pipe_t;

The client and server stubs must declare pipe processing functions with the following signatures and semantics:

typedef struct pipe_t {
    void (* pull)(
       rpc_ss_pipe_state_t state,
       element_t *buf,
       idl_ulong_int esize,
       idl_ulong_int *ecount
    );
   void (* push)(
      rpc_ss_pipe_state_t state,
      element_t *buf,
      idl_ulong_int  ecount
   );
   void (* alloc)(
      rpc_ss_pipe_state_t state,
      idl_ulong_int bsize,
      element_t **buf,
      idl_ulong_int *bcount
   );
   rpc_ss_pipe_state_t state;
} pipe_t;

The pipe data structure specifies pointers to three separate routines and a pipe state. The client application must implement these routines for the client stub to call, and the server manager must call the associated routines generated in the server stub.

The pull routine is used for an in pipe. It pulls the next chunk of data from the client side into the pipe. The input parameters include the pipe state, the buffer containing a chunk of data, and the size of the buffer in terms of the number of pipe data elements. The output parameter is the actual count of the number of pipe data elements in the buffer.

The push routine is used for an out pipe. It pushes the next chunk of data from the pipe to the caller. The input parameters include the pipe state, the buffer containing a chunk of data, and a count of the number of pipe data elements in the buffer.

The alloc routine allocates a buffer for the pipe data. The input parameters include the pipe state and the requested size of the buffer in bytes. The output parameters include a pointer to the allocated buffer and the actual count of the number of bytes in the buffer. The routine allocates memory from which pipe data can be marshalled or into which pipe data can be marshalled. If less memory is allocated than requested, the RPC runtime uses the smaller memory and makes more callbacks to the caller. If the routine allocates more memory than requested, the excess memory is not used. Given that pipes are intended to process data asynchronously, the alloc routine should not simply allocate a new buffer each time it is called, since the effect would be to allocate space for the whole stream. A reasonable approach is either to declare a buffer statically or allocate it on the first call (per thread), and thereafter simply return the same buffer.

Finally, the state is used to coordinate between these routines.

The following list enumerates which of these objects are necessary in each of the four possible cases, and who is responsible for supplying them. The generalisation to in, out pipes is obvious.

IDL and ACS Type Attributes

The following sections describe IDL and ACS type attributes as they affect the application/stub interface.

The IDL transmit_as Attribute

The transmit_as attribute associates a presented type in the target language with an IDL transmitted type (<xmit_type>). The presented type is the type seen by clients and servers. The transmitted type is the type that the stub passes to the run-time system for transmission. The application must supply routines that perform conversions between the presented and transmitted types, and to release memory used to hold the converted data.

Transmitted Type Routines lists the routines that the application must supply, where <type_id> is the identifier part of the type defined in the statement in which the transmit_as attribute occurs.

Routine Name Routine Use
<type_id>_to_xmit Allocates an instance of the transmitted type and converts from the presented type to the transmitted type (used by both caller and callee).
<type_id>_from_xmit Converts from the transmitted type to the presented type (used by both caller and callee).
<type_id>_free_inst Frees resources used by the presented type, but not the type itself as it is allocated by the stub (used by callee).
<type_id>_free_xmit Frees storage returned by <type_id>_to_xmit routine (used by both caller and callee).

Table: Transmitted Type Routines

The signatures of these routines are as follows:

void <type_id>_to_xmit ( <presented_type> *, (<transmitted_type> **) ) void <type_id>_from_xmit ( (<transmitted_type> *), (<presented_type> *) ) void <type_id>_free_inst ( <presented_type> * ) void <type_id>_free_xmit ( (<transmitted_type> *) )

If the presented type is composed of one or more pointers, then the application's <type_id>_from_xmit routine must allocate the targets of any such pointers. The stub storage release behaviour is as follows.

Suppose that the transmit_as attribute appears either on the type of a parameter or on a component of a parameter and that the parameter has the out or in, out attribute. Then, the <type_id>_free_inst routine is called automatically for the data item which has the transmit_as attribute.

Suppose that the transmit_as attribute appears on the type of a parameter and that the parameter has only the in attribute. Then, the <type_id>_free_inst routine is called automatically.

Finally, suppose that the transmit_as attribute appears on a component of a parameter and that the parameter has only the in attribute. Then, the <type_id>_free_inst routine is not called automatically for the component; the manager application code must release any resources that the component uses, possibly by explicitly calling the <type_id>_free_inst routine.

The <type_id>_free_xmit routine frees any storage that has been allocated for the transmitted type by <type_id>_to_xmit.

The IDL handle Attribute

The handle attribute specifies that a type can serve as a customised handle. Customised handles permit the design of handles that are meaningful to an application. The client application must provide binding and unbinding routines to convert between the custom handle type and the primitive handle type, handle_t.

A primitive handle must contain object UUID and destination information that is meaningful to the client/server run-time support mechanisms. A customised handle may only be defined in a type declaration. It must not be defined in an operation declaration. When a parameter in the first position is a type with the handle attribute, the parameter does double duty. It determines the binding for the call, and it is transmitted to the called procedure as a normal parameter. Types with the handle attribute in other than the first parameter position are treated as ordinary parameters; their handle attribute is ignored, and they do not contribute to the binding process.

The client application must supply the following routines:

handle_t <type_id>_bind ( <type_id> custom_handle ) void <type_id>_unbind ( <type_id> custom_handle, handle_t )

where <type_id> is the identifier of the customised handle data type and custom_handle represents the formal parameters of the customised handle data type. The routine <type_id>_bind must generate and return a primitive binding handle from a customised handle of type <type_id>. The client stub must call <type_id>_bind before it sends the request, and call <type_id>_unbind before it returns to the caller. The <type_id>_unbind routine actions are application-specific and may have no effect.

Interaction of IDL transmit_as and IDL handle Attributes

If a type has both the transmit_as and handle attributes and the type is used as the first parameter in an operation, the <type_id>_bind routine must be invoked before the <type_id>_to_xmit routine.

However, a type that includes the handle attribute in its definition must not be used, directly or indirectly, in the definition of a type with the transmit_as attribute. A type that includes the transmit_as attribute in its definition must not be used, directly or indirectly, in the definition of a type with the handle attribute. The handle attribute is not allowed on a type that contains a transmit_as type.

The ACS represent_as Attribute

The represent_as attribute associates a named local type in the target language (<ACS_repr_type>) with a transfer type (<ACS_named_type>) that is transferred between caller and callee. The user must supply routines that perform conversions between the local and transfer types, and that release memory used to hold the converted data.

Transferred Type Routines lists the routines that the application must supply, where the represent_as attribute has been specified for (<ACS_named_type>).

Routine Name Routine Use
<ACS_named_type>_from_local Allocates an instance of the network type and converts from the local type to the network type (used by both caller and callee).
<ACS_named_type>_to_local Converts from the network type to the local type (used by both caller and callee).
<ACS_named_type>_free_inst Frees storage instance used for the network type (used by both caller and callee).
<ACS_named_type>_free_local Frees storage returned by the routine <ACS_named_type>_from_local (used by callee).

Table: Transferred Type Routines

The signatures of these routines are as follows:

void <ACS_named_type>_from_local ( (<ACS_repr_type> *), (<ACS_named_type> **))
void <ACS_named_type>_to_local ( (<ACS_named_type> *), (<ACS_repr_type> *) )
void 

Suppose that the represent_as attribute is applied either to the type of a parameter or to a component of a parameter and that the parameter has the out or in, out attribute. Then, the <ACS_named_type>_free_local routine is called automatically for the data item that has the type to which the represent_as attribute was applied.

Suppose that the represent_as attribute is applied to the type of a parameter and that the parameter has only the in attribute. Then, the <ACS_named_type>_free_local routine is called automatically.

Finally, suppose that the represent_as attribute is applied to the type of a component of a parameter and that the parameter has only the in attribute. Then, the <ACS_named_type>_free_local routine is not called automatically for the component; the manager application code must release any resources that the component uses, possibly by explicitly calling the <ACS_named_type>_free_local routine.

Interaction of the ACS represent_as Attribute and the IDL handle Attribute

A type must not have both the handle and represent_as attributes.

Interaction of the ACS represent_as Attribute with the IDL transmit_as Attribute

If a type has both the represent_as and transmit_as attributes, the transformations are applied in the appropriate order: on the transmit side, <type_id>_from_local then <type_id>_to_xmit; on the receive side, <type_id>_from_xmit then <type_id>_to_local.

Context Handle Rundown

A context handle is opaque to the caller. However, a caller may distinguish between a null context handle and an active one. A context handle whose value is 0 (zero) is termed a null context handle and does not represent any currently saved context. A context handle with any other value is termed an active context handle and represents saved context.

When making an RPC that will create saved context, the caller must pass a null context handle. The called procedure may return an active context handle. A context handle parameter with only the out attribute (that is, without either the in of in, out attributes) is interpreted as if it were a null context handle at the time of the call. It is the responsibility of the caller to pass the unmodified context handle back to the server on the next call.

The interpretation of the context handle is totally up to the called procedure. If the caller modifies a context handle in any way other than initialising it to 0 (zero) before its first use, then behaviour is unpredictable. It is the responsibility of the callee to return a null context handle when it is no longer maintaining context on behalf of the caller. For example, if the context handle represents an open file and the call closes the file, the callee must set the context handle to 0 (zero) and return it to the caller. If the callee terminates the context and fails to return a null context handle, then the context rundown routine will be erroneously called when the client exits.

For some contexts a context rundown routine may be required. If communications between the caller and the callee break down while the callee is maintaining context for the caller, the run-time system invokes the context rundown routine to enable the callee to clean up this context. When an interface requires context but does not require a context rundown routine, it is sufficient to use parameters that have the context_handle attribute. However, where a rundown routine is required, the user must define a named type that has the context_handle attribute.

By making the type definition, the user implicitly specifies the name of the rundown routine for the context. The declaration of a type with the context_handle attribute and the name <context_type_name> specifies a rundown routine with the name <context_type_name>_rundown. A rundown routine takes one parameter, the context handle of the context that is to be run down, and delivers no result.

For example, if the application declares:

typedef [context_handle] void *my_context

it must supply, in the manager application code, a rundown routine that matches the prototype:

void my_context_rundown ( void *context_handle );

A context handle is valid in only one execution context. Therefore, the opaque data structure that a context handle refers to on a client implicitly includes a binding handle. Whenever an operation has an in or a non-null in, out context handle parameter, and the operation also has a first parameter that is of type handle_t or has the handle attribute, then the binding handle represented by the context handle and the binding handle represented by the first parameter must refer to the same execution context. Furthermore, when an operation has an in or a non-null in, out context handle parameter, any interface-wide binding mechanism-implicit_handle or auto_handle-is ignored for that operation. If an operation has more than one in context handle, all the respective binding handles must refer to the same remote execution context.

Interoperability Requirements on Stubs

Stub code shall conform to interoperability requirements in the following areas:

Operation Numbers

The RPC protocols use operation numbers to inform a server which operation of an interface to invoke. Stubs generate operation numbers consecutively, beginning with 0 (zero), in the order in which operations appear in the IDL source.

Error Handling During Floating-Point Unmarshalling

This section specifies how stubs handle errors that occur when unmarshalling floating-point data. The following list names a set of octet stream representations of floating point values for which stubs must generate errors:

MAX
Some value greater than the largest value that can be represented in the receiver's floating-point representation.

MIN
Some value less than the smallest value that can be represented in the receiver's floating-point representation.

NaN
The logical equivalent to IEEE "not a number".

Minuszero
The logical equivalent to IEEE -0.0.

+INF
Positive infinity (in the format specified in the format label).

-INF
Negative infinity.

Floating Point Error Handling specifies stub behaviour for each of these conditions. The table indicates the value to be unmarshalled or a fault status code that must be returned by the caller (client).


Condition Unmarshalled Value Fault Status Code
MAX undefined rpc_s_fault_fp_overflow
MIN 0.0 None
Minuszero 0.0 None
+INF or NaN undefined rpc_s_fault_fp_error
-INF undefined rpc_s_fault_fp_error


Table: Floating Point Error Handling

When a floating-point error occurs on the server side, the server must return the appropriate fault PDU to the client to generate the fault status specified. The mapping of fault PDU values to fault status codes is specified in Reject Status Codes and Parameters .


Please note that the html version of this specification may contain formatting aberrations. The definitive version is available as an electronic publication on CD-ROM from The Open Group.

Contents Next section Index