ONC+ Developer's Guide

Passing Arbitrary Data Types

Data types passed to and received from remote procedures can be any of a set of predefined types, or can be programmer-defined types. RPC handles arbitrary data structures, regardless of different machines' byte orders or structure layout conventions, by always converting them to a standard transfer format called external data representation (XDR) before sending them over the transport. The conversion from a machine representation to XDR is called serializing, and the reverse process is called deserializing.

The translator arguments of rpc_call() and rpc_reg() can specify an XDR primitive procedure, like xdr_u_int(), or a programmer-supplied routine that processes a complete argument structure. Argument processing routines must take only two arguments: a pointer to the result and a pointer to the XDR handle.

Table 4-1 XDR Primitive Type Routines

XDR Primitive Routines 

xdr_int()

xdr_netobj()

xdr_u_long()

xdr_enum()

xdr_long()

xdr_float()

xdr_u_int()

xdr_bool()

xdr_short()

xdr_double()

xdr_u_short()

xdr_wrapstring()

xdr_char()

xdr_quadruple()

xdr_u_char()

xdr_void()

xdr_hyper()

xdr_u_hyper()

For the convenience of ANSI C programmers who are accustomed to the fixed-width integer types found in int_types.h, the routines xdr_char(), xdr_short(), xdr_int(), and xdr_hyper() (and the unsigned versions of each) have equivalent functions with names familiar to ANSI C, as indicated in Table 4-2.

Table 4-2 Primitive Type Equivalences

Function 

Equivalent 

xdr_char()

xdr_int8_t()

xdr_u_char()

xdr_u_int8_t()

xdr_short()

xdr_int16_t()

xdr_u_short()

xdr_u_int16_t()

xdr_int()

xdr_int32_t()

xdr_u_int()

xdr_u_int32_t()

xdr_hyper()

xdr_int64_t()

xdr_u_hyper()

xdr_u_int64_t()

The nonprimitive xdr_string(), which takes more than two parameters, is called from xdr_wrapstring().

For an example of a programmer-supplied routine, the structure:

struct simple {
 	int a;
 	short b;
 } simple;

contains the calling arguments of a procedure. The XDR routine xdr_simple() translates the argument structure as shown in Example 4-3.


Example 4-3 xdr_simple Routine

#include <rpc/rpc.h>
#include "simple.h"
 
bool_t
xdr_simple(xdrsp, simplep)
	XDR *xdrsp;
	struct simple *simplep;
{
	if (!xdr_int(xdrsp, &simplep->a))
		return (FALSE);
	if (!xdr_short(xdrsp, &simplep->b))
		return (FALSE);
	return (TRUE);
}

An equivalent routine can be generated automatically by rpcgen.

An XDR routine returns nonzero (a C TRUE) if it completes successfully, and zero otherwise. A complete description of XDR is provided in Appendix C, XDR Protocol Specification.

Table 4-3
 Prefabricated Routines

xdr_array()

xdr_bytes()

xdr_reference()

xdr_vector()

xdr_union()

xdr_pointer()

xdr_string()

xdr_opaque()

For example, to send a variable-sized array of integers, it is packaged in a structure containing the array and its length:

struct varintarr {
 	int *data;
 	int arrlnth;
 } arr;

Translate the array with xdr_varintarr(), as shown in Example 4-4.


Example 4-4 xdr_varintarr Syntax Use

bool_t
xdr_varintarr(xdrsp, arrp)
	XDR *xdrsp;
	struct varintarr *arrp;
{
	return(xdr_array(xdrsp, (caddr_t)&arrp->data,
		(u_int *)&arrp->arrlnth, MAXLEN,
		sizeof(int), xdr_int));
}

The arguments of xdr_array() are the XDR handle, a pointer to the array, a pointer to the size of the array, the maximum array size, the size of each array element, and a pointer to the XDR routine to translate each array element. If the size of the array is known in advance, use xdr_vector(), as shown in Example 4-5.


Example 4-5 xdr_vector Syntax Use

int intarr[SIZE];

bool_t
xdr_intarr(xdrsp, intarr)
	XDR *xdrsp;
	int intarr[];
{
	return (xdr_vector(xdrsp, intarr, SIZE,
				sizeof(int),
xdr_int));
}

XDR converts quantities to 4-byte multiples when serializing. For arrays of characters, each character occupies 32 bits. xdr_bytes() packs characters. It has four parameters similar to the first four parameters of xdr_array().

Null-terminated strings are translated by xdr_string(). It is like xdr_bytes() with no length parameter. On serializing it gets the string length from strlen(), and on deserializing it creates a null-terminated string.

Example 4-6 calls the built-in functions xdr_string() and xdr_reference(), which translates pointers to pass a string, and struct simple from the previous examples.


Example 4-6 xdr_reference Syntax Use

struct finalexample {
	char *string;
	struct simple *simplep;
} finalexample;

bool_t
xdr_finalexample(xdrsp, finalp)
	XDR *xdrsp;
	struct finalexample *finalp;
{
	if (!xdr_string(xdrsp, &finalp->string,
			MAXSTRLEN))
		return (FALSE);
	if (!xdr_reference( xdrsp, &finalp->simplep,
			sizeof(struct simple), xdr_simple))
		return (FALSE);
	return (TRUE);

}

Note that xdr_simple() could have been called here instead of xdr_reference().