ONC+ RPC Developer's Guide

Exit Print View

Updated: July 2014
 
 

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 the byte orders or structure layout conventions of different machines. RPC always converts these structures 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.

The XDR Primitive Type Routines are:

xdr_int()
xdr_double()
xdr_netobj()
xdr_u_short()
xdr_u_long()
xdr_wrapstring()
xdr_enum()
xdr_char()
xdr_long()
xdr_quadruple()
xdr_float()
xdr_u_char()
xdr_u_int()
xdr_void()
xdr_bool()
xdr_hyper()
xdr_short()
xdr_u_hyper()

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 the following table.

Table 4-1  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().

The following example of a programmer-supplied routine contains the calling arguments of a procedure.

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

The XDR routine xdr_simple() translates the argument structure as shown in the following code example.

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);
}

rpcgen can automatically generate an equivalent routine.

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.

The following list shows 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, the routine 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 the following code example.

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 the following code example.

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(), which is like xdr_bytes() with no length parameter. On serializing xdr_string() gets the string length from strlen(), and on deserializing it creates a null-terminated string.

The following example calls the built-in functions xdr_string() and xdr_reference(), which translates pointers to pass a string, and struct simple from 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().