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
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.
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.
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.
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 server stub automatically frees all memory allocated by calls to rpc_sm_allocate().
For both out and in, out parameters, when full pointers are
aliases, according to the rules specified in
The IDL compiler must be able to generate server stubs that contain a
default manager EPV, as described in
The stub must declare an interface handle according to the naming
conventions specified in
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:
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 sections describe IDL and ACS type attributes as they affect the application/stub interface.
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.
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). |
The signatures of these routines are as follows:
<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 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:
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.
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 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.
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). |
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.
A type must not have both the handle and represent_as attributes.
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.
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:
it must supply, in the manager application code, a rundown routine that
matches the prototype:
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.
Stub code shall conform to interoperability requirements in the following areas:
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.
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:
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 |
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
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 |