[mod.sources] v06i091: Sun RPC Source

sources-request@mirror.UUCP (08/06/86)

Submitted by: cca!SUN.COM!marks (Mark Stein)
Mod.sources: Volume 6, Issue 91
Archive-name: rpc2/Part03

[  All I did was verity that the shar files unpacked correctly.  -r$  ]

Sun RPC source (part 3 of 11).  This software package contains code
and documentation for Revision 3.0 of the Sun Remote Procedure Call
library.  In addition, a beta version of the XDR/RPC protocol compiler
is included.  Comments about this latest release may be mailed to
sun!rpc or rpc@sun.com.

Sun RPC is a product of Sun Microsystems, Inc. and is provided for
unrestricted use provided that this legend is included on all tape
media and as a part of the software program in whole or part.  Users
may copy or modify Sun RPC without charge, but are not authorized to
license or distribute it to anyone else except as part of a product or
program developed by the user.

- - - - - - - - - C U T - H E R E - - - - - - - - - - - - - - - - - -
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	rpc/doc/xdr.spec.p1
# This archive created: Mon Jul 14 16:55:03 1986
export PATH; PATH=/bin:/usr/bin:$PATH
for d in rpc rpc/doc rpc/rpclib rpc/tools rpc/toys rpc/rpclib/profiled rpc/rpcgen rpc/rpcgen/test
do
	if test ! -d $d
	then
		echo "shar: Making directory $d"
		mkdir $d
		chmod 755 $d
	fi
done
echo shar: "extracting 'rpc/doc/xdr.spec.p1'" '(49809 characters)'
if test -f 'rpc/doc/xdr.spec.p1'
then
	echo shar: "will not over-write existing file 'rpc/doc/xdr.spec.p1'"
else
sed 's/^X//' << \SHAR_EOF > 'rpc/doc/xdr.spec.p1'
X.\" @(#)c3.xdr.spec 1.1 86/02/25 SMI; for 3.0 FCS
X.PL RIGHT
X.EQ
Xdelim $$
X.EN
X.TL
XExternal Data Representation
X.br
XProtocol Specification
X.bp
X.NH
XIntroduction
X.LP
XThis manual describes library routines that allow a C programmer to 
Xdescribe arbitrary data structures in a machine-independent fashion.
XThe eXternal Data Representation (XDR) standard
Xis the backbone of Sun's Remote Procedure Call package,
Xin the sense that data for remote procedure calls
Xis transmitted using the standard.
XXDR library routines should be used to transmit data
Xthat is accessed (read or written) by more than one type of machine.
X.LP
XThis manual contains a description of XDR library routines,
Xa guide to accessing currently available XDR streams,
Xinformation on defining new streams and data types,
Xand a formal definition of the XDR standard.
XXDR was designed to work across different languages,
Xoperating systems, and machine architectures.
XMost users (particularly RPC users)
Xonly need the information in sections 2 and 3 of this document.
XProgrammers wishing to implement RPC and XDR on new machines
Xwill need the information in sections 4 through 6.
XAdvanced topics, not necessary for all implementations,
Xare covered in section 7.
X.LP
XOn Sun systems,
XC programs that want to use XDR routines
Xmust include the file
X.LW <rpc/rpc.h> ,
Xwhich contains all the necessary interfaces to the XDR system.
XSince the C library
X.LW libc.a
Xcontains all the XDR routines,
Xcompile as normal.
X.LS
X% \f(LBcc\0\fIprogram\fP.c\fL
X.Lf
X.NH 2
XJustification
X.LP
XConsider the following two programs,
X.LW writer :
X.LS
X#include <stdio.h>
X.sp.5
Xmain()			/* writer.c */
X{
X	long i;
X.sp.5
X	for (i = 0; i < 8; i++) {
X		if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) {
X			fprintf(stderr, "failed!\en");
X			exit(1);
X		}
X	}
X}
X.Lf
Xand
X.LW reader :
X.LS
X#include <stdio.h>
X.sp.5
Xmain()			/* reader.c */
X{
X	long i, j;
X.sp.5
X	for (j = 0; j < 8; j++) {
X		if (fread((char *)&i, sizeof (i), 1, stdin) != 1) {
X			fprintf(stderr, "failed!\en");
X			exit(1);
X		}
X		printf("%ld ", i);
X	}
X	printf("\en");
X}
X.Lf
XThe two programs appear to be portable, because
X(a) they pass
X.LW lint
Xchecking, and
X(b) they exhibit the same behavior when executed
Xon two different hardware architectures, a Sun and a VAX.
X.LP
XPiping the output of the
X.LW writer
Xprogram to the
X.LW reader
Xprogram gives identical results on a Sun or a VAX.\(dd
X.FS \(dd
XVAX is a trademark of Digital Equipment Corporation.
X.FE
X.LS
Xsun% writer | reader
X0 1 2 3 4 5 6 7
Xsun%
X.Lf
X.LS
Xvax% writer | reader
X0 1 2 3 4 5 6 7
Xvax%
X.Lf
XWith the advent of local area networks and Berkeley's 4.2 BSD
X.UX
Xcame the concept of ``network pipes'' \(em
Xa process produces data on one machine,
Xand a second process consumes data on another machine.
XA network pipe can be constructed with
X.LW writer
Xand
X.LW reader .
XHere are the results if the first produces data on a Sun,
Xand the second consumes data on a VAX.
X.LS
Xsun% writer | rsh vax reader
X0 16777216 33554432 50331648 67108864 83886080 100663296
X117440512
Xsun%
X.Lf
XIdentical results can be obtained by executing
X.LW writer
Xon the VAX and
X.LW reader
Xon the Sun.
XThese results occur because the byte ordering
Xof long integers differs between the VAX and the Sun,
Xeven though word size is the same.
XNote that $16777216$ is $2 sup 24$ \(em
Xwhen four bytes are reversed, the 1 winds up in the 24th bit.
X.LP
XWhenever data is shared by two or more machine types,
Xthere is a need for portable data.
XPrograms can be made data-portable by replacing the
X.LW read()
Xand
X.LW write()
Xcalls with calls to an XDR library routine
X.LW xdr_long() ,
Xa filter that knows the standard representation
Xof a long integer in its external form.
XHere are the revised versions of
X.LW writer :
X.LS
X#include <stdio.h>
X#include <rpc/rpc.h>	/* xdr is a sub-library of rpc */
X.sp.5
Xmain()		/* writer.c */
X{
X	XDR xdrs;
X	long i;
X.sp.5
X	xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
X	for (i = 0; i < 8; i++) {
X		if (!xdr_long(&xdrs, &i)) {
X			fprintf(stderr, "failed!\en");
X			exit(1);
X		}
X	}
X}
X.Lf
Xand
X.LW reader :
X.LS
X#include <stdio.h>
X#include <rpc/rpc.h>	/* xdr is a sub-library of rpc */
X.sp.5
Xmain()		/* reader.c */
X{
X	XDR xdrs;
X	long i, j;
X.sp.5
X	xdrstdio_create(&xdrs, stdin, XDR_DECODE);
X	for (j = 0; j < 8; j++) {
X		if (!xdr_long(&xdrs, &i)) {
X			fprintf(stderr, "failed!\en");
X			exit(1);
X		}
X		printf("%ld ", i);
X	}
X	printf("\en");
X}
X.Lf
XThe new programs were executed on a Sun,
Xon a VAX, and from a Sun to a VAX;
Xthe results are shown below.
X.LS
Xsun% writer | reader
X0 1 2 3 4 5 6 7
Xsun%
X.Lf
X.LS
Xvax% writer | reader
X0 1 2 3 4 5 6 7
Xvax%
X.Lf
X.LS
Xsun% writer | rsh vax reader
X0 1 2 3 4 5 6 7
Xsun%
X.Lf
XDealing with integers is just the tip of the portable-data iceberg.
XArbitrary data structures present portability problems,
Xparticularly with respect to alignment and pointers.
XAlignment on word boundaries may cause the
Xsize of a structure to vary from machine to machine.
XPointers are convenient to use,
Xbut have no meaning outside the machine where they are defined.
X.NH 2
XThe XDR Library
X.LP
XThe XDR library solves data portability problems.
XIt allows you to write and read arbitrary C constructs
Xin a consistent, specified, well-documented manner.
XThus, it makes sense to use the library even when the data
Xis not shared among machines on a network.
X.LP
XThe XDR library has filter routines for
Xstrings (null-terminated arrays of bytes),
Xstructures, unions, and arrays, to name a few.
XUsing more primitive routines,
Xyou can write your own specific XDR routines
Xto describe arbitrary data structures,
Xincluding elements of arrays, arms of unions,
Xor objects pointed at from other structures.
XThe structures themselves may contain arrays of arbitrary elements,
Xor pointers to other structures.
X.LP
XLet's examine the two programs more closely.
XThere is a family of XDR stream creation routines
Xin which each member treats the stream of bits differently.
XIn our example, data is manipulated using standard I/O routines,
Xso we use
X.LW xdrstdio_create() .
XThe parameters to XDR stream creation routines
Xvary according to their function.
XIn our example,
X.LW xdrstdio_create()
Xtakes a pointer to an XDR structure that it initializes,
Xa pointer to a
X.LW FILE
Xthat the input or output is performed on, and the operation.
XThe operation may be
X.LW XDR_ENCODE
Xfor serializing in the
X.LW writer
Xprogram, or
X.LW XDR_DECODE
Xfor deserializing in the
X.LW reader
Xprogram.
X.LP
XNote: RPC clients never need to create XDR streams;
Xthe RPC system itself creates these streams,
Xwhich are then passed to the clients.
X.LP
XThe
X.LW xdr_long()
Xprimitive is characteristic of most XDR library 
Xprimitives and all client XDR routines.
XFirst, the routine returns
X.LW FALSE
X(0) if it fails, and
X.LW TRUE
X(1) if it succeeds.
XSecond, for each data type,
X.LW xxx ,
Xthere is an associated XDR routine of the form:
X.LS
Xxdr_xxx(xdrs, fp)
X	XDR *xdrs;
X	xxx *fp;
X{
X}
X.Lf
XIn our case,
X.LW xxx
Xis long, and the corresponding XDR routine is
Xa primitive,
X.LW xdr_long . 
XThe client could also define an arbitrary structure
X.LW xxx
Xin which case the client would also supply the routine
X.LW xdr_xxx ,
Xdescribing each field by calling XDR routines
Xof the appropriate type.
XIn all cases the first parameter,
X.LW xdrs
Xcan be treated as an opaque handle,
Xand passed to the primitive routines.
X.LP
XXDR routines are direction independent;
Xthat is, the same routines are called to serialize or deserialize data.
XThis feature is critical to software engineering of portable data.
XThe idea is to call the same routine for either operation \(em
Xthis almost guarantees that serialized data can also be deserialized.
XOne routine is used by both producer and consumer of networked data.
XThis is implemented by always passing the address
Xof an object rather than the object itself \(em
Xonly in the case of deserialization is the object modified.
XThis feature is not shown in our trivial example,
Xbut its value becomes obvious when nontrivial data structures
Xare passed among machines.
XIf needed, you can obtain the direction of the XDR operation.
XSee section 3.7 for details.
X.LP
XLet's look at a slightly more complicated example.
XAssume that a person's gross assets and liabilities
Xare to be exchanged among processes.
XAlso assume that these values are important enough
Xto warrant their own data type:
X.LS
Xstruct gnumbers {
X	long g_assets;
X	long g_liabilities;
X};
X.Lf
XThe corresponding XDR routine describing this structure would be:
X.LS
Xbool_t  		/* TRUE is success, FALSE is failure */
Xxdr_gnumbers(xdrs, gp)
X	XDR *xdrs;
X	struct gnumbers *gp;
X{
X	if (xdr_long(xdrs, &gp->g_assets) &&
X	    xdr_long(xdrs, &gp->g_liabilities))
X		return(TRUE);
X	return(FALSE);
X}
X.Lf
XNote that the parameter
X.LW xdrs
Xis never inspected or modified;
Xit is only passed on to the subcomponent routines.
XIt is imperative to inspect the return value of each XDR routine call,
Xand to give up immediately and return
X.LW FALSE
Xif the subroutine fails.
X.LP
XThis example also shows that the type
X.LW bool_t
Xis declared as an integer whose only values are
X.LW TRUE
X(1) and
X.LW FALSE
X(0).  This document uses the following definitions:
X.LS
X#define bool_t	int
X#define TRUE	1
X#define FALSE	0
X.sp.5
X#define enum_t int	/* enum_t used for generic enums */
X.Lf
X.LP
XKeeping these conventions in mind,
X.LW xdr_gnumbers()
Xcan be rewritten as follows:
X.LS
Xxdr_gnumbers(xdrs, gp)
X	XDR *xdrs;
X	struct gnumbers *gp;
X{
X	return(xdr_long(xdrs, &gp->g_assets) &&
X		xdr_long(xdrs, &gp->g_liabilities));
X}
X.Lf
XThis document uses both coding styles.
X.bp
X.NH
XXDR Library Primitives
X.LP
XThis section gives a synopsis of each XDR primitive.
XIt starts with basic data types and moves on to constructed data types.
XFinally, XDR utilities are discussed.
XThe interface to these primitives
Xand utilities is defined in the include file
X.LW <rpc/xdr.h> ,
Xautomatically included by
X.LW <rpc/rpc.h> .
X.NH 2
XNumber Filters
X.LP
XThe XDR library provides primitives to translate between numbers
Xand their corresponding external representations.
XPrimitives cover the set of numbers in:
X.EQ
X[signed, unsigned] * [short, int, long]
X.EN
XSpecifically, the six primitives are:
X.LS
Xbool_t xdr_int(xdrs, ip)
X	XDR *xdrs;
X	int *ip;
X.sp.5
Xbool_t xdr_u_int(xdrs, up)
X	XDR *xdrs;
X	unsigned *up;
X.sp.5
Xbool_t xdr_long(xdrs, lip)
X	XDR *xdrs;
X	long *lip;
X.sp.5
Xbool_t xdr_u_long(xdrs, lup)
X	XDR *xdrs;
X	u_long *lup;
X.sp.5
Xbool_t xdr_short(xdrs, sip)
X	XDR *xdrs;
X	short *sip;
X.sp.5
Xbool_t xdr_u_short(xdrs, sup)
X	XDR *xdrs;
X	u_short *sup;
X.Lf
XThe first parameter,
X.LW xdrs ,
Xis an XDR stream handle.
XThe second parameter is the address of the number
Xthat provides data to the stream or receives data from it.
XAll routines return
X.LW TRUE
Xif they complete successfully, and
X.LW FALSE
Xotherwise.
X.NH 2
XFloating Point Filters
X.LP
XThe XDR library also provides primitive routines
Xfor C's floating point types:
X.LS
Xbool_t xdr_float(xdrs, fp)
X	XDR *xdrs;
X	float *fp;
X.sp.5
Xbool_t xdr_double(xdrs, dp)
X	XDR *xdrs;
X	double *dp;
X.Lf
XThe first parameter,
X.LW xdrs
Xis an XDR stream handle.
XThe second parameter is the address
Xof the floating point number that provides data to the stream
Xor receives data from it.
XAll routines return
X.LW TRUE
Xif they complete successfully, and
X.LW FALSE
Xotherwise.
X.LP
XNote: Since the numbers are represented in IEEE floating point,
Xroutines may fail when decoding a valid IEEE representation
Xinto a machine-specific representation, or vice-versa.
X.NH 2
XEnumeration Filters
X.LP
XThe XDR library provides a primitive for generic enumerations.
XThe primitive assumes that a C
X.LW enum
Xhas the same representation inside the machine as a C integer.
XThe boolean type is an important instance of the
X.LW enum .
XThe external representation of a boolean is always one
X.LW TRUE ) (
Xor zero
X.LW FALSE ). (
X.LS
X#define bool_t	int
X#define FALSE	0
X#define TRUE	1
X.sp.5
X#define enum_t int
X.sp.5
Xbool_t xdr_enum(xdrs, ep)
X	XDR *xdrs;
X	enum_t *ep;
X.sp.5
Xbool_t xdr_bool(xdrs, bp)
X	XDR *xdrs;
X	bool_t *bp;
X.Lf
XThe second parameters
X.LW ep
Xand
X.LW bp
Xare addresses of the associated type
Xthat provides data to, or receives data from, the stream
X.LW xdrs .
XThe routines return
X.LW TRUE
Xif they complete successfully, and
X.LW FALSE
Xotherwise.
X.NH 2
XNo Data
X.LP
XOccasionally, an XDR routine must be supplied to the RPC system,
Xeven when no data is passed or required.
XThe library provides such a routine:
X.LS
Xbool_t xdr_void();  /* always returns TRUE */
X.Lf
X.NH 2
XConstructed Data Type Filters
X.LP
XConstructed or compound data type primitives
Xrequire more parameters and perform more complicated functions
Xthen the primitives discussed above.
XThis section includes primitives for
Xstrings, arrays, unions, and pointers to structures.
X.LP
XConstructed data type primitives may use memory management.
XIn many cases, memory is allocated when deserializing data with
X.LW XDR_DECODE .
XTherefore, the XDR package must provide means to deallocate memory.
XThis is done by an XDR operation,
X.LW XDR_FREE .
XTo review, the three XDR directional operations are
X.LW XDR_ENCODE ,
X.LW XDR_DECODE ,
Xand
X.LW XDR_FREE .
X.NH 3
XStrings
X.LP
XIn C, a string is defined as a sequence of bytes
Xterminated by a null byte,
Xwhich is not considered when calculating string length.
XHowever, when a string is passed or manipulated,
Xa pointer to it is employed.
XTherefore, the XDR library defines a string to be a
X.LW "char *" ,
Xand not a sequence of characters.
XThe external representation of a string is drastically different
Xfrom its internal representation.
XExternally, strings are represented as
Xsequences of ASCII characters,
Xwhile internally, they are represented with character pointers.
XConversion between the two representations
Xis accomplished with the routine
X.LW xdr_string() :
X.LS
Xbool_t xdr_string(xdrs, sp, maxlength)
X	XDR *xdrs;
X	char **sp;
X	u_int maxlength;
X.Lf
XThe first parameter
X.LW xdrs
Xis the XDR stream handle.
XThe second parameter
X.LW sp
Xis a pointer to a string (type
X.LW "char **" ).
XThe third parameter
X.LW maxlength
Xspecifies the maximum number of bytes allowed during encoding or decoding;
Xits value is usually specified by a protocol.
XFor example, a protocol specification may say
Xthat a file name may be no longer than 255 characters.
XThe routine returns
X.LW FALSE
Xif the number of characters exceeds
X.LW maxlength ,
Xand
X.LW TRUE
Xif it doesn't.
X.LP
XThe behavior of
X.LW xdr_string()
Xis similar to the behavior of other routines
Xdiscussed in this section.  The direction
X.LW XDR_ENCODE
Xis easiest to understand.  The parameter
X.LW sp
Xpoints to a string of a certain length;
Xif it does not exceed
X.LW maxlength ,
Xthe bytes are serialized.
X.LP
XThe effect of deserializing a string is subtle.
XFirst the length of the incoming string is determined;
Xit must not exceed
X.LW maxlength .
XNext
X.LW sp
Xis dereferenced; if the the value is
X.LW NULL ,
Xthen a string of the appropriate length is allocated and
X.LW *sp
Xis set to this string.
XIf the original value of
X.LW *sp
Xis non-null, then the XDR package assumes
Xthat a target area has been allocated,
Xwhich can hold strings no longer than
X.LW maxlength .
XIn either case, the string is decoded into the target area.
XThe routine then appends a null character to the string.
X.LP
XIn the
X.LW XDR_FREE
Xoperation, the string is obtained by dereferencing
X.LW sp .
XIf the string is not
X.LW NULL ,
Xit is freed and
X.LW *sp
Xis set to
X.LW NULL .
XIn this operation,
X.LW xdr_string
Xignores the
X.LW maxlength
Xparameter.
X.NH 3
XByte Arrays
X.LP
XOften variable-length arrays of bytes are preferable to strings.
XByte arrays differ from strings in the following three ways: 
X1) the length of the array (the byte count) is explicitly
Xlocated in an unsigned integer,
X2) the byte sequence is not terminated by a null character, and
X3) the external representation of the bytes is the same as their
Xinternal representation.
XThe primitive
X.LW xdr_bytes()
Xconverts between the internal and external
Xrepresentations of byte arrays:
X.LS
Xbool_t xdr_bytes(xdrs, bpp, lp, maxlength)
X	XDR *xdrs;
X	char **bpp;
X	u_int *lp;
X	u_int maxlength;
X.Lf
XThe usage of the first, second and fourth parameters
Xare identical to the first, second and third parameters of
X.LW xdr_string() ,
Xrespectively.
XThe length of the byte area is obtained by dereferencing
X.LW lp
Xwhen serializing;
X.LW *lp
Xis set to the byte length when deserializing.
X.NH 3
XArrays
X.LP
XThe XDR library package provides a primitive
Xfor handling arrays of arbitrary elements.
XThe
X.LW xdr_bytes()
Xroutine treats a subset of generic arrays,
Xin which the size of array elements is known to be 1,
Xand the external description of each element is built-in.
XThe generic array primitive,
X.LW xdr_array()
Xrequires parameters identical to those of
X.LW xdr_bytes()
Xplus two more:
Xthe size of array elements,
Xand an XDR routine to handle each of the elements.
XThis routine is called to encode or decode
Xeach element of the array.
X.LS
Xbool_t
Xxdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element)
X	XDR *xdrs;
X	char **ap;
X	u_int *lp;
X	u_int maxlength;
X	u_int elementsiz;
X	bool_t (*xdr_element)();
X.Lf
XThe parameter
X.LW ap
Xis the address of the pointer to the array.
XIf
X.LW *ap
Xis
X.LW NULL
Xwhen the array is being deserialized,
XXDR allocates an array of the appropriate size and sets
X.LW *ap
Xto that array.
XThe element count of the array is obtained from
X.LW *lp
Xwhen the array is serialized;
X.LW *lp
Xis set to the array length when the array is deserialized. 
XThe parameter
X.LW maxlength
Xis the maximum number of elements that the array is allowed to have;
X.LW elementsiz
Xis the byte size of each element of the array
X(the C function
X.LW sizeof()
Xcan be used to obtain this value).
XThe routine
X.LW xdr_element
Xis called to serialize, deserialize, or free
Xeach element of the array.
X.NH 4
XExamples
X.LP
XBefore defining more constructed data types,
Xit is appropriate to present three examples.
X.LP
X.I "Example A"
X.LP
XA user on a networked machine can be identified by 
X(a) the machine name, such as
X.LW krypton :
Xsee
X.I gethostname (3);
X(b) the user's UID: see
X.I geteuid (2);
Xand (c) the group numbers to which the user belongs: see
X.I getgroups (2).
XA structure with this information and its associated XDR routine
Xcould be coded like this:
X.LS
Xstruct netuser {
X	char	*nu_machinename;
X	int 	nu_uid;
X	u_int	nu_glen;
X	int 	*nu_gids;
X};
X#define NLEN 255	/* machine names < 256 chars */
X#define NGRPS 20	/* user can't be in > 20 groups */
X.sp.5
Xbool_t
Xxdr_netuser(xdrs, nup)
X	XDR *xdrs;
X	struct netuser *nup;
X{
X	return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
X	    xdr_int(xdrs, &nup->nu_uid) &&
X	    xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen, NGRPS,
X		sizeof (int), xdr_int));
X}
X.Lf
X.LP
X.I "Example B"
X.LP
XA party of network users could be implemented
Xas an array of
X.LW netuser
Xstructure.
XThe declaration and its associated XDR routines
Xare as follows:
X.LS
Xstruct party {
X	u_int p_len;
X	struct netuser *p_nusers;
X};
X#define PLEN 500 /* max number of users in a party */
X.sp.5
Xbool_t
Xxdr_party(xdrs, pp)
X	XDR *xdrs;
X	struct party *pp;
X{
X	return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
X	    sizeof (struct netuser), xdr_netuser));
X}
X.Lf
X.LP
X.I "Example C"
X.LP
XThe well-known parameters to
X.LW main() ,
X.LW argc
Xand
X.LW argv
Xcan be combined into a structure.
XAn array of these structures can make up a history of commands.
XThe declarations and XDR routines might look like:
X.LS no
Xstruct cmd {
X	u_int c_argc;
X	char **c_argv;
X};
X#define ALEN 1000	/* args cannot be > 1000 chars */
X#define NARGC 100	/* commands cannot have > 100 args */
X.sp.5
Xstruct history {
X	u_int h_len;
X	struct cmd *h_cmds;
X};
X#define NCMDS 75  /* history is no more than 75 commands */
X.sp.5
Xbool_t
Xxdr_wrap_string(xdrs, sp)
X	XDR *xdrs;
X	char **sp;
X{
X	return(xdr_string(xdrs, sp, ALEN));
X}
X.sp.5
Xbool_t
Xxdr_cmd(xdrs, cp)
X	XDR *xdrs;
X	struct cmd *cp;
X{
X	return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
X	    sizeof (char *), xdr_wrap_string));
X}
X.sp.5
Xbool_t
Xxdr_history(xdrs, hp)
X	XDR *xdrs;
X	struct history *hp;
X{
X	return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
X	    sizeof (struct cmd), xdr_cmd));
X}
X.Lf
XThe most confusing part of this example is that the routine
X.LW xdr_wrap_string()
Xis needed to package the
X.LW xdr_string()
Xroutine, because the implementation of
X.LW xdr_array()
Xonly passes two parameters to the array element description routine;
X.LW xdr_wrap_string()
Xsupplies the third parameter to
X.LW xdr_string() .
X.LP
XBy now the recursive nature of the XDR library should be obvious.
XLet's continue with more constructed data types.
X.NH 3
XOpaque Data
X.LP
XIn some protocols, handles are passed from a server to client.
XThe client passes the handle back to the server at some later time.
XHandles are never inspected by clients;
Xthey are obtained and submitted.
XThat is to say, handles are opaque.
XThe primitive
X.LW xdr_opaque()
Xis used for describing fixed sized, opaque bytes.
X.LS
Xbool_t xdr_opaque(xdrs, p, len)
X	XDR *xdrs;
X	char *p;
X	u_int len;
X.Lf
XThe parameter
X.LW p
Xis the location of the bytes;
X.LW len
Xis the number of bytes in the opaque object.
XBy definition, the actual data
Xcontained in the opaque object are not machine portable.
X.NH 3
XFixed Sized Arrays
X.LP
XThe XDR library does not provide a primitive for fixed-length arrays
X(the primitive
X.LW xdr_array()
Xis for varying-length arrays).
XExample A could be rewritten to use fixed-sized arrays
Xin the following fashion:
X.LS no
X#define NLEN 255	/* machine names must be < 256 chars */
X#define NGRPS 20	/* user can't belong to > 20 groups */
X.sp.5
Xstruct netuser {
X	char *nu_machinename;
X	int nu_uid;
X	int nu_gids[NGRPS];
X};
X.sp.5
Xbool_t
Xxdr_netuser(xdrs, nup)
X	XDR *xdrs;
X	struct netuser *nup;
X{
X	int i;
X.sp.5
X	if (!xdr_string(xdrs, &nup->nu_machinename, NLEN))
X		return(FALSE);
X	if (!xdr_int(xdrs, &nup->nu_uid))
X		return(FALSE);
X	for (i = 0; i < NGRPS; i++) {
X		if (!xdr_int(xdrs, &nup->nu_gids[i]))
X			return(FALSE);
X	}
X	return(TRUE);
X}
X.Lf
X.LP
XExercise:
XRewrite example A so that it uses varying-length arrays and so that the
X.LW netuser
Xstructure contains the actual
X.LW nu_gids
Xarray body as in the example above.
X.NH 3
XDiscriminated Unions
X.LP
XThe XDR library supports discriminated unions.
XA discriminated union is a C union and an
X.LW enum_t
Xvalue that selects an ``arm'' of the union.
X.LS
Xstruct xdr_discrim {
X	enum_t value;
X	bool_t (*proc)();
X};
X.sp.5
Xbool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm)
X	XDR *xdrs;
X	enum_t *dscmp;
X	char *unp;
X	struct xdr_discrim *arms;
X	bool_t (*defaultarm)();  /* may equal NULL */
X.Lf
XFirst the routine translates the discriminant of the union located at 
X.LW *dscmp .
XThe discriminant is always an
X.LW enum_t .
XNext the union located at
X.LW *unp
Xis translated.
XThe parameter
X.LW arms
Xis a pointer to an array of
X.LW xdr_discrim
Xstructures. 
XEach structure contains an order pair of
X.LW [value,proc] .
XIf the union's discriminant is equal to the associated
X.LW value ,
Xthen the
X.LW proc
Xis called to translate the union.
XThe end of the
X.LW xdr_discrim
Xstructure array is denoted by a routine of value
X.LW NULL
X(0).  If the discriminant is not found in the
X.LW arms
Xarray, then the
X.LW defaultarm
Xprocedure is called if it is non-null;
Xotherwise the routine returns
X.LW FALSE .
X.LP
X.I "Example D"
X.LP
XSuppose the type of a union may be integer,
Xcharacter pointer (a string), or a
X.LW gnumbers
Xstructure.
XAlso, assume the union and its current type
Xare declared in a structure.
XThe declaration is:
X.LS
Xenum utype { INTEGER=1, STRING=2, GNUMBERS=3 };
X.sp.5
Xstruct u_tag {
X	enum utype utype;	/* the union's discriminant */
X	union {
X		int ival;
X		char *pval;
X		struct gnumbers gn;
X	} uval;
X};
X.Lf
XThe following constructs and XDR procedure (de)serialize
Xthe discriminated union:
X.LS
Xstruct xdr_discrim u_tag_arms[4] = {
X	{ INTEGER, xdr_int },
X	{ GNUMBERS, xdr_gnumbers }
X	{ STRING, xdr_wrap_string },
X	{ __dontcare__, NULL }
X	/* always terminate arms with a NULL xdr_proc */
X}
X.sp.5
Xbool_t
Xxdr_u_tag(xdrs, utp)
X	XDR *xdrs;
X	struct u_tag *utp;
X{
X	return(xdr_union(xdrs, &utp->utype, &utp->uval,
X		u_tag_arms, NULL));
X}
X.Lf
XThe routine
X.LW xdr_gnumbers()
Xwas presented in Section 2;
X.LW xdr_wrap_string()
Xwas presented in example C.
XThe default arm parameter to
X.LW xdr_union()
X(the last parameter) is
X.LW NULL
Xin this example.  Therefore the value of the union's discriminant
Xmay legally take on only values listed in the
X.LW u_tag_arms
Xarray.  This example also demonstrates that
Xthe elements of the arm's array do not need to be sorted.
X.LP
XIt is worth pointing out that the values of the discriminant
Xmay be sparse, though in this example they are not.
XIt is always good
Xpractice to assign explicitly integer values to each element of the
Xdiscriminant's type.
XThis practice both documents the external
Xrepresentation of the discriminant and guarantees that different
XC compilers emit identical discriminant values.
X.LP
XExercise: Implement
X.LW xdr_union()
Xusing the other primitives in this section.
X.NH 3
XPointers
X.LP
XIn C it is often convenient to put pointers
Xto another structure within a structure.
XThe primitive
X.LW xdr_reference()
Xmakes it easy to serialize, deserialize, and free
Xthese referenced structures.
X.LS
Xbool_t xdr_reference(xdrs, pp, size, proc)
X	XDR *xdrs;
X	char **pp;
X	u_int ssize;
X	bool_t (*proc)();
X.Lf
X.LP
XParameter
X.LW pp
Xis the address of
Xthe pointer to the structure;
Xparameter
X.LW ssize
Xis the size in bytes of the structure
X(use the C function
X.LW sizeof()
Xto obtain this value); and
X.LW proc
Xis the XDR routine that describes the structure.
XWhen decoding data, storage is allocated if
X.LW *pp
Xis
X.LW NULL .
X.LP
XThere is no need for a primitive
X.LW xdr_struct()
Xto describe structures within structures,
Xbecause pointers are always sufficient.
X.LP
XExercise: Implement
X.LW xdr_reference()
Xusing
X.LW xdr_array() .
XWarning:
X.LW xdr_reference()
Xand
X.LW xdr_array()
Xare NOT interchangeable external representations of data.
X.LP
X.I "Example E"
X.LP
XSuppose there is a structure containing a person's name
Xand a pointer to a
X.LW gnumbers
Xstructure containing the person's gross assets and liabilities.
XThe construct is:
X.LS
Xstruct pgn {
X	char *name;
X	struct gnumbers *gnp;
X};
X.Lf
XThe corresponding XDR routine for this structure is:
X.LS
Xbool_t
Xxdr_pgn(xdrs, pp)
X	XDR *xdrs;
X	struct pgn *pp;
X{
X	if (xdr_string(xdrs, &pp->name, NLEN) &&
X	  xdr_reference(xdrs, &pp->gnp,
X	  sizeof(struct gnumbers), xdr_gnumbers))
X		return(TRUE);
X	return(FALSE);
X}
X.Lf
X.NH 4
XPointer Semantics and XDR
X.LP
XIn many applications,
XC programmers attach double meaning to the values of a pointer.
XTypically the value
X.LW NULL
X(or zero) means data is not needed,
Xyet some application-specific interpretation applies.
XIn essence, the C programmer is encoding
Xa discriminated union efficiently
Xby overloading the interpretation of the value of a pointer.
XFor instance, in example E a
X.LW NULL
Xpointer value for
X.LW gnp
Xcould indicate that
Xthe person's assets and liabilities are unknown.
XThat is, the pointer value encodes two things:
Xwhether or not the data is known;
Xand if it is known, where it is located in memory.
XLinked lists are an extreme example of the use
Xof application-specific pointer interpretation.
X.LP
XThe primitive
X.LW xdr_reference()
Xcannot and does not attach any special
Xmeaning to a null-value pointer during serialization.
XThat is, passing an address of a pointer whose value is
X.LW NULL
Xto
X.LW xdr_reference()
Xwhen serialing data will most likely cause a memory fault and, on
X.UX ,
Xa core dump for debugging.
X.LP
XIt is the explicit responsibility of the programmer
Xto expand non-dereferenceable pointers into their specific semantics.
XThis usually involves describing data with a two-armed discriminated union.
XOne arm is used when the pointer is valid;
Xthe other is used when the pointer is invalid
X.LW NULL ). (
XSection 7 has an example (linked lists encoding) that deals
Xwith invalid pointer interpretation.
X.LP
XExercise:
XAfter reading Section 7, return here and extend example E so that
Xit can correctly deal with null pointer values.
X.LP
XExercise:
XUsing the
X.LW xdr_union() ,
X.LW xdr_reference()
Xand
X.LW xdr_void()
Xprimitives, implement a generic pointer handling primitive
Xthat implicitly deals with
X.LW NULL
Xpointers.  The XDR library does not provide such a primitive
Xbecause it does not want to give the illusion
Xthat pointers have meaning in the external world.
X.NH 2
XNon-filter Primitives
X.LP
XXDR streams can be manipulated with
Xthe primitives discussed in this section.
X.LS
Xu_int xdr_getpos(xdrs)
X	XDR *xdrs;
X.sp.5
Xbool_t xdr_setpos(xdrs, pos)
X	XDR *xdrs;
X	u_int pos;
X.sp.5
Xxdr_destroy(xdrs)
X	XDR *xdrs;
X.Lf
XThe routine
X.LW xdr_getpos()
Xreturns an unsigned integer
Xthat describes the current position in the data stream.
XWarning: In some XDR streams, the returned value of
X.LW xdr_getpos()
Xis meaningless;
Xthe routine returns a \-1 in this case
X(though \-1 should be a legitimate value).
X.LP
XThe routine
X.LW xdr_setpos()
Xsets a stream position to
X.LW pos .
XWarning: In some XDR streams, setting a position is impossible;
Xin such cases,
X.LW xdr_setpos()
Xwill return
X.LW FALSE .
XThis routine will also fail if the requested position is out-of-bounds.
XThe definition of bounds varies from stream to stream.
X.LP
XThe
X.LW xdr_destroy()
Xprimitive destroys the XDR stream.
XUsage of the stream
Xafter calling this routine is undefined.
X.NH 2
XXDR Operation Directions
X.LP
XAt times you may wish to optimize XDR routines by taking
Xadvantage of the direction of the operation \(em
X.LW XDR_ENCODE ,
X.LW XDR_DECODE ,
Xor
X.LW XDR_FREE .
XThe value
X.LW xdrs->x_op
Xalways contains the
Xdirection of the XDR operation.
XProgrammers are not encouraged to take advantage of this information.
XTherefore, no example is presented here.
XHowever, an example in Section 7
Xdemonstrates the usefulness of the
X.LW xdrs->x_op
Xfield.
X.bp
X.NH
XXDR Stream Access
X.LP
XAn XDR stream is obtained by calling the appropriate creation routine.
XThese creation routines take arguments that are tailored to the
Xspecific properties of the stream.
X.LP
XStreams currently exist for (de)serialization of data to or from
Xstandard I/O
X.LW FILE
Xstreams, TCP/IP connections and
X.UX
Xfiles, and memory.
XSection 5 documents the XDR object and how to make
Xnew XDR streams when they are required.
X.NH 2
XStandard I/O Streams
X.LP
XXDR streams can be interfaced to standard I/O using the
X.LW xdrstdio_create()
Xroutine as follows:
X.LS
X#include <stdio.h>
X#include <rpc/rpc.h>	/* xdr streams part of rpc */
X.sp.5
Xvoid
Xxdrstdio_create(xdrs, fp, x_op)
X	XDR *xdrs;
X	FILE *fp;
X	enum xdr_op x_op;
X.Lf
XThe routine
X.LW xdrstdio_create()
Xinitializes an XDR stream pointed to by
X.LW xdrs .
XThe XDR stream interfaces to the standard I/O library.
XParameter
X.LW fp
Xis an open file, and
X.LW x_op
Xis an XDR direction.
X.NH 2
XMemory Streams
X.LP
XMemory streams allow the streaming of data into or out of
Xa specified area of memory:
X.LS
X#include <rpc/rpc.h>
X.sp.5
Xvoid
Xxdrmem_create(xdrs, addr, len, x_op)
X	XDR *xdrs;
X	char *addr;
X	u_int len;
X	enum xdr_op x_op;
X.Lf
XThe routine
X.LW xdrmem_create()
Xinitializes an XDR stream in local memory.
XThe memory is pointed to by parameter
X.LW addr ;
Xparameter
X.LW len
Xis the length in bytes of the memory.
XThe parameters
X.LW xdrs
Xand
X.LW x_op
Xare identical to the corresponding parameters of
X.LW xdrstdio_create() .
XCurrently, the UDP/IP implementation of RPC uses
X.LW xdrmem_create() .
XComplete call or result messages are built in memory before calling the
X.LW sendto()
Xsystem routine.
X.NH 2
XRecord (TCP/IP) Streams
X.LP
XA record stream is an XDR stream built on top of
Xa record marking standard that is built on top of the
X.UX
Xfile or 4.2 BSD connection interface.
X.LS
X#include <rpc/rpc.h>	/* xdr streams part of rpc */
X.sp.5
Xxdrrec_create(xdrs,
X  sendsize, recvsize, iohandle, readproc, writeproc)
X	XDR *xdrs;
X	u_int sendsize, recvsize;
X	char *iohandle;
X	int (*readproc)(), (*writeproc)();
X.Lf
XThe routine
X.LW xdrrec_create()
Xprovides an XDR stream interface that allows for a bidirectional,
Xarbitrarily long sequence of records.
XThe contents of the records are meant to be data in XDR form.
XThe stream's primary use is for interfacing RPC to TCP connections.
XHowever, it can be used to stream data into or out of normal
X.UX
Xfiles.
X.LP
XThe parameter
X.LW xdrs
Xis similar to the corresponding parameter described above.
XThe stream does its own data buffering similar to that of standard I/O.
XThe parameters
X.LW sendsize
Xand
X.LW recvsize
Xdetermine the size in bytes of the output and input buffers, respectively;
Xif their values are zero (0), then predetermined defaults are used.
XWhen a buffer needs to be filled or flushed, the routine
X.LW readproc
Xor
X.LW writeproc
Xis called, respectively.
XThe usage and behavior of these
Xroutines are similar to the
X.UX
Xsystem calls
X.LW read()
Xand
X.LW write() .
XHowever,
Xthe first parameter to each of these routines is the opaque parameter
X.LW iohandle .
XThe other two parameters
X.LW buf "" (
Xand
X.LW nbytes )
Xand the results
X(byte count) are identical to the system routines.
XIf
X.LW xxx
Xis
X.LW readproc
Xor
X.LW writeproc ,
Xthen it has the following form:
X.LS
X/*
X * returns the actual number of bytes transferred.
X * -1 is an error
X */
Xint
Xxxx(iohandle, buf, len)
X	char *iohandle;
X	char *buf;
X	int nbytes;
X.Lf
XThe XDR stream provides means for delimiting records in the byte stream.
XThe implementation details of delimiting records in a stream
Xare discussed in appendix 1.
XThe primitives that are specific to record streams are as follows:
X.LS
Xbool_t
Xxdrrec_endofrecord(xdrs, flushnow)
X	XDR *xdrs;
X	bool_t flushnow;
X.sp.5
Xbool_t
Xxdrrec_skiprecord(xdrs)
X	XDR *xdrs;
X.sp.5
Xbool_t
Xxdrrec_eof(xdrs)
X	XDR *xdrs;
X.Lf
XThe routine
X.LW xdrrec_endofrecord()
Xcauses the current outgoing data to be marked as a record.
XIf the parameter
X.LW flushnow
Xis
X.LW TRUE ,
Xthen the stream's
X.LW writeproc()
Xwill be called; otherwise,
X.LW writeproc()
Xwill be called when the output buffer has been filled.
X.LP
XThe routine
X.LW xdrrec_skiprecord()
Xcauses an input stream's position to be moved past
Xthe current record boundary and onto the
Xbeginning of the next record in the stream.
X.LP
XIf there is no more data in the stream's input buffer,
Xthen the routine
X.LW xdrrec_eof()
Xreturns
X.LW TRUE .
XThat is not to say that there is no more data
Xin the underlying file descriptor.
X.bp
X.NH
XXDR Stream Implementation
X.LP
XThis section provides the abstract data types needed
Xto implement new instances of XDR streams.
X.NH 2
XThe XDR Object
X.LP
XThe following structure defines the interface to an XDR stream:
X.LS
Xenum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
X.sp.5
Xtypedef struct {
X	enum xdr_op x_op;	/* operation; fast added param */
X	struct xdr_ops {
X		bool_t  (*x_getlong)();  /* get long from stream */
X		bool_t  (*x_putlong)();  /* put long to stream */
X		bool_t  (*x_getbytes)(); /* get bytes from stream */
X		bool_t  (*x_putbytes)(); /* put bytes to stream */
X		u_int   (*x_getpostn)(); /* return stream offset */
X		bool_t  (*x_setpostn)(); /* reposition offset */
X		caddr_t (*x_inline)();   /* ptr to buffered data */
X		VOID    (*x_destroy)();  /* free private area */
X	} *x_ops;
X	caddr_t	x_public;	/* users' data */
X	caddr_t	x_private;	/* pointer to private data */
X	caddr_t	x_base;		/* private for position info */
X	int		x_handy;	/* extra private word */
X} XDR;
X.Lf
XThe
X.LW x_op
Xfield is the current operation being performed on the stream.
XThis field is important to the XDR primitives,
Xbut should not affect a stream's implementation.
XThat is, a stream's implementation should not depend
Xon this value.
XThe fields
X.LW x_private ,
X.LW x_base ,
Xand
X.LW x_handy
Xare private to the particular
Xstream's implementation.
XThe field
X.LW x_public
Xis for the XDR client and should never be used by
Xthe XDR stream implementations or the XDR primitives.
X.LP
XMacros for accessing  operations
X.LW x_getpostn() ,
X.LW x_setpostn() ,
Xand
X.LW x_destroy()
Xwere defined in Section 3.6.
XThe operation
X.LW x_inline()
Xtakes two parameters:
Xan XDR *, and an unsigned integer, which is a byte count.
XThe routine returns a pointer to a piece of
Xthe stream's internal buffer.
XThe caller can then use the buffer segment for any purpose.
XFrom the stream's point of view, the bytes in the
Xbuffer segment have been consumed or put.
XThe routine may return
X.LW NULL
Xif it cannot return a buffer segment of the requested size.
X(The
X.LW x_inline
Xroutine is for cycle squeezers.
XUse of the resulting buffer is not data-portable.
XUsers are encouraged not to use this feature.) 
X.LP
XThe operations
X.LW x_getbytes()
Xand
X.LW x_putbytes()
Xblindly get and put sequences of bytes
Xfrom or to the underlying stream;
Xthey return
X.LW TRUE
Xif they are successful, and
X.LW FALSE
Xotherwise.  The routines have identical parameters (replace
X.LW xxx ):
X.LS
Xbool_t
Xxxxbytes(xdrs, buf, bytecount)
X	XDR *xdrs;
X	char *buf;
X	u_int bytecount;
X.Lf
XThe operations
X.LW x_getlong()
Xand
X.LW x_putlong()
Xreceive and put
Xlong numbers from and to the data stream.
XIt is the responsibility of these routines
Xto translate the numbers between the machine representation
Xand the (standard) external representation.
XThe
X.UX
Xprimitives
X.LW htonl()
Xand
X.LW ntohl()
Xcan be helpful in accomplishing this.
XSection 6 defines the standard representation of numbers.
XThe higher-level XDR implementation assumes that
Xsigned and unsigned long integers contain the same number of bits,
Xand that nonnegative integers
Xhave the same bit representations as unsigned integers.
XThe routines return
X.I TRUE
Xif they succeed, and
X.LW FALSE
Xotherwise.  They have identical parameters:
X.LS
Xbool_t
Xxxxlong(xdrs, lp)
X	XDR *xdrs;
X	long *lp;
X.Lf
XImplementors of new XDR streams must make an XDR structure
X(with new operation routines) available to clients,
Xusing some kind of create routine.
X.bp
X.NH
XXDR Standard
X.LP
XThis section defines the external data representation standard.
XThe standard is independent of languages,
Xoperating systems and hardware architectures.
XOnce data is shared among machines, it should not matter that the data
Xwas produced on a Sun, but is consumed by a VAX (or vice versa).
XSimilarly the choice of operating systems should have no influence
Xon how the data is represented externally.
XFor programming languages,
Xdata produced by a C program should be readable
Xby a Fortran or Pascal program.
X.LP
XThe external data representation standard depends on the assumption that
Xbytes (or octets) are portable.
XA byte is defined to be eight bits of data.
XIt is assumed that hardware
Xthat encodes bytes onto various media
Xwill preserve the bytes' meanings
Xacross hardware boundaries.
XFor example, the Ethernet standard suggests that bytes be
Xencoded ``little endian'' style.
XBoth Sun and VAX hardware implementations
Xadhere to the standard.
X.LP
XThe XDR standard also suggests a language used to describe data.
XThe language is a bastardized C;
Xit is a data description language, not a programming language.
X(The Xerox Courier Standard uses bastardized Mesa
Xas its data description language.)
X.NH 2
XBasic Block Size
X.LP
XThe representation of all items requires
Xa multiple of four bytes (or 32 bits) of data.
XThe bytes are numbered
X$0$ through $n-1$, where $(n ~ \fRmod\fP ~ 4) = 0$.
XThe bytes are read or written to some byte stream
Xsuch that byte $m$ always precedes byte $m+1$.
X.NH 2
XInteger
X.LP
XAn XDR signed integer is a 32-bit datum
Xthat encodes an integer in the range
X.LW [-2147483648,2147483647] . 
XThe integer is represented in two's complement notation. 
XThe most and least significant bytes are 0 and 3, respectively.
XThe data description of integers is
X.LW integer .
X.NH 2
XUnsigned Integer
X.LP
XAn XDR unsigned integer is a 32-bit datum
Xthat encodes a nonnegative integer in the range
X.LW [0,4294967295] .
XIt is represented by an unsigned binary number whose most
Xand least significant bytes are 0 and 3, respectively.
XThe data description of unsigned integers is
X.LW unsigned .
X.NH 2
XEnumerations
X.LP
XEnumerations have the same representation as integers.
XEnumerations are handy for describing subsets of the integers.
XThe data description of enumerated data is as follows:
X.LS
Xtypedef enum { name = value, .... } type-name;
X.Lf
XFor example the three colors red, yellow and blue
Xcould be described by an enumerated type:
X.LS
Xtypedef enum { RED = 2, YELLOW = 3, BLUE = 5 } colors;
X.Lf
X.NH 2
XBooleans
X.LP
XBooleans are important enough and occur frequently enough
Xto warrant their own explicit type in the standard.
XBoolean is an enumeration with the
Xfollowing form:
X.LS
Xtypedef enum { FALSE = 0, TRUE = 1 } boolean;
X.Lf
X.NH 2
XHyper Integer and Hyper Unsigned
X.LP
XThe standard also defines 64-bit (8-byte) numbers called 
X.LW "hyper integer"
Xand
X.LW "hyper unsigned" .
XTheir representations are the obvious extensions of 
Xthe integer and unsigned defined above.
XThe most and least significant bytes are 0 and 7, respectively.
X.NH 2
XFloating Point and Double Precision
X.LP
XThe standard defines the encoding for the floating point data types
X.LW float
X(32 bits or 4 bytes) and
X.LW double
X(64 bits or 8 bytes).
XThe encoding used is the IEEE standard for normalized
Xsingle- and double-precision floating point numbers.
XSee the IEEE floating point standard for more information.
XThe standard encodes the following three fields,
Xwhich describe the floating point number:
X.IP \fIS\fP
XThe sign of the number.
XValues 0 and 1 represent 
Xpositive and negative, respectively.
X.IP \fIE\fP
XThe exponent of the number, base 2.
XFloats devote 8 bits to this field,
Xwhile doubles devote 11 bits.
XThe exponents for float and double are
Xbiased by 127 and 1023, respectively.
X.IP \fIF\fP
XThe fractional part of the number's mantissa, base 2.
XFloats devote 23 bits to this field,
Xwhile doubles devote 52 bits.
X.LP
XTherefore, the floating point number is described by:
X.EQ
X(-1) sup S * 2 sup { E - Bias } * 1.F
X.EN
X.LP
XJust as the most and least significant bytes of a number are 0 and 3,
Xthe most and least significant bits of
Xa single-precision floating point number are 0 and 31.
XThe beginning bit (and most significant bit) offsets
Xof $S$, $E$, and $F$ are 0, 1, and 9, respectively.
X.LP
XDoubles have the analogous extensions.
XThe beginning bit (and
Xmost significant bit) offsets of $S$, $E$, and $F$
Xare 0, 1, and 12, respectively.
X.LP
XThe IEEE specification should be consulted concerning the encoding for
Xsigned zero, signed infinity (overflow), and denormalized numbers (underflow).
XUnder IEEE specifications, the ``NaN'' (not a number)
Xis system dependent and should not be used.
X.NH 2
XOpaque Data
X.LP
XAt times fixed-sized uninterpreted data
Xneeds to be passed among machines.
XThis data is called
X.LW opaque
Xand is described as:
X.LS
Xtypedef opaque type-name[n];
Xopaque name[n];
X.Lf
Xwhere
X.LW n
Xis the (static) number of bytes necessary to contain the opaque data.
XIf
X.LW n
Xis not a multiple of four, then the
X.LW n
Xbytes are followed by enough (up to 3) zero-valued bytes
Xto make the total byte count of the opaque object a multiple of four.
X.NH 2
XCounted Byte Strings
X.LP
XThe standard defines a string of $n$ (numbered $0$ through $n-1$)
Xbytes to be the number $n$ encoded as
X.LW unsigned ,
Xand followed by the $n$ bytes of the string.
XIf $n$ is not a multiple of four,
Xthen the $n$ bytes are followed by
Xenough (up to 3) zero-valued bytes
Xto make the total byte count a multiple of four.
XThe data description of strings is as follows:
X.LS
Xtypedef string type-name<N>;
Xtypedef string type-name<>;
Xstring name<N>;
Xstring name<>;
X.Lf
XNote that the data description language uses angle brackets (< and >)
Xto denote anything that is varying-length
X(as opposed to square brackets to denote fixed-length sequences of data).
X.LP
XThe constant
X.LW N
Xdenotes an upper bound of the number of bytes that a
Xstring may contain.
XIf
X.LW N
Xis not specified, it is assumed to be $2 sup 32 - 1$,
Xthe maximum length.
XThe constant
X.LW N
Xwould normally be found in a protocol specification.
XFor example, a filing protocol may state
Xthat a file name can be no longer than 255 bytes, such as:
X.LS
Xstring filename<255>;
X.Lf
X.LP
XThe XDR specification does not say what the
Xindividual bytes of a string represent;
Xthis important information is left to higher-level specifications.
XA reasonable default is to assume
Xthat the bytes encode ASCII characters.
X.NH 2
XFixed Arrays
X.LP
XThe data description for fixed-size arrays of
Xhomogeneous elements is as follows:
X.LS
Xtypedef elementtype type-name[n];
Xelementtype name[n];
X.Lf
XFixed-size arrays of elements numbered $0$ through $n-1$
Xare encoded by individually encoding the elements of the array
Xin their natural order, $0$ through $n-1$.
X.NH 2
XCounted Arrays
X.LP
XCounted arrays provide the ability to encode varyiable-length arrays
Xof homogeneous elements.
XThe array is encoded as:
Xthe element count $n$ (an unsigned integer),
Xfollowed by the encoding of each of the array's elements,
Xstarting with element $0$ and progressing through element $n-1$.
XThe data description for counted arrays
Xis similar to that of counted strings:
X.LS
Xtypedef elementtype type-name<N>;
Xtypedef elementtype type-name<>;
Xelementtype name<N>;
Xelementtype name<>;
X.Lf
XAgain, the constant
X.LW N
Xspecifies the maximum acceptable
Xelement count of an array; if
X.LW N
Xis  not specified, it is assumed to be $2 sup 32 - 1$.
X.NH 2
XStructures
X.LP
XThe data description for structures is very similar to
Xthat of standard C:
X.LS
Xtypedef struct {
X	component-type component-name;
X	...
X} type-name;
X.Lf
XThe components of the structure are encoded 
Xin the order of their declaration in the structure.
X.NH 2
XDiscriminated Unions
X.LP
XA discriminated union is a type composed of a discriminant followed by a type
Xselected from a set of prearranged types according to the value of the
Xdiscriminant.
XThe type of the discriminant is always an enumeration.
XThe component types are called ``arms'' of the union.
XThe discriminated union is encoded as its discriminant followed by
Xthe encoding of the implied arm.
XThe data description for discriminated unions is as follows:
X.LS
Xtypedef union switch (discriminant-type) {
X	discriminant-value: arm-type;
X	...
X	default: default-arm-type;
X} type-name;
X.Lf
XThe default arm is optional.
XIf it is not specified, then a valid
Xencoding of the union cannot take on unspecified discriminant values.
XMost specifications neither need nor use default arms.
X.NH 2
XMissing Specifications
X.LP
XThe standard lacks representations for bit fields and bitmaps,
Xsince the standard is based on bytes.
XThis is not to say that no specification should be attempted.
X.NH 2
XLibrary Primitive / XDR Standard Cross Reference
X.LP
XThe following table describes the association between
Xthe C library primitives discussed in Section 3,
Xand the standard data types defined in this section:
X.LP
X.TS
Xbox;
XcfBI s s
XcfI cfI cfI
XrfL | cfL | l.
X.sp.1
XPrimitives and Data Types
X.sp.1
X_
XC Primitive	XDR Type	Sections
X_
Xxdr_int
Xxdr_long	integer	3.1, 6.2
Xxdr_short
X_
Xxdr_u_int
Xxdr_u_long	unsigned	3.1, 6.3
Xxdr_u_short
X_
X-	hyper integer	6.6
X	hyper unsigned
X_
Xxdr_float	float	3.2, 6.7
X_
Xxdr_double	double	3.2, 6.7
X_
Xxdr_enum	enum_t	3.3, 6.4
X_
Xxdr_bool	bool_t	3.3, 6.5
X_
Xxdr_string	string	3.5.1, 6.9
Xxdr_bytes		3.5.2
X_
Xxdr_array	\fR(varying arrays)\fP	3.5.3, 6.11
X_
X-	\fR(fixed arrays)\fP	3.5.5, 6.10
X_
Xxdr_opaque	opaque	3.5.4, 6.8
X_
Xxdr_union	union	3.5.6, 6.13
X_
Xxdr_reference	-	3.5.7
X_
X-	struct	6.6
X.TE
X.TN "Primitives and Data Types"
X.bp
X.NH
XAdvanced Topics
X.LP
XThis section describes techniques for passing data structures
Xthat are not covered in the preceding sections.
XSuch structures include linked lists (of arbitrary lengths).
XUnlike the simpler examples covered in the earlier sections,
Xthe following examples are written using both
Xthe XDR C library routines and the XDR data description language.
XSection 6 describes the XDR data definition language used below.
X.NH 2
XLinked Lists
X.LP
XThe last example in Section 2 presented a C data structure and its
Xassociated XDR routines for a person's gross assets and liabilities.
XThe example is duplicated below:
X.LS
Xstruct gnumbers {
X	long g_assets;
X	long g_liabilities;
X};
X.sp.5
Xbool_t
Xxdr_gnumbers(xdrs, gp)
X	XDR *xdrs;
X	struct gnumbers *gp;
X{
X	if (xdr_long(xdrs, &(gp->g_assets)))
X		return(xdr_long(xdrs, &(gp->g_liabilities)));
X	return(FALSE);
X}
X.Lf
XNow assume that we wish to implement a linked list of such information.
XA data structure could be constructed as follows:
X.LS
Xtypedef struct gnnode {
X	struct gnumbers gn_numbers;
X	struct gnnode *nxt;
X};
X.sp.5
Xtypedef struct gnnode *gnumbers_list;
X.Lf
XThe head of the linked list can be thought of as the data object;
Xthat is, the head is not merely a convenient shorthand for a structure.
XSimilarly the
X.LW nxt
Xfield is used to indicate whether or not the object has terminated.
XUnfortunately, if the object continues, the
X.LW nxt
Xfield is also the address
Xof where it continues.
XThe link addresses carry no useful information when
Xthe object is serialized.
X.LP
XThe XDR data description of this linked list is described by the
Xrecursive type declaration of gnumbers_list:
X.LS
Xstruct gnumbers {
X	unsigned g_assets;
X	unsigned g_liabilities;
X};
X.Lf
X.LS
Xtypedef union switch (boolean) {
X	case TRUE: struct {
X		struct gnumbers current_element;
X		gnumbers_list rest_of_list;
X	};
X	case FALSE: struct {};
X} gnumbers_list;
X.Lf
XIn this description,
Xthe boolean indicates whether there is more data following it.
XIf the boolean is
X.LW FALSE ,
Xthen it is the last data field of the structure.
XIf it is
X.LW TRUE ,
Xthen it is followed by a
X.LW gnumbers
Xstructure and (recursively) by a
X.LW gnumbers_list
X(the rest of the object).
XNote that the C declaration has no boolean explicitly declared in it
X(though the
X.LW nxt
Xfield implicitly carries the information), while
Xthe XDR data description has no pointer explicitly declared in it.
X.LP
XHints for writing a set of XDR routines to successfully (de)serialize
Xa linked list of entries can be taken
Xfrom the XDR description of the pointer-less data.
XThe set consists of the mutually recursive routines
X.LW xdr_gnumbers_list ,
X.LW xdr_wrap_list ,
Xand
X.LW xdr_gnnode .
X.LS
Xbool_t
Xxdr_gnnode(xdrs, gp)
X	XDR *xdrs;
X	struct gnnode *gp;
X{
X	return(xdr_gnumbers(xdrs, &(gp->gn_numbers)) &&
X		xdr_gnumbers_list(xdrs, &(gp->nxt)) );
X}
X.Lf
SHAR_EOF
if test 49809 -ne "`wc -c < 'rpc/doc/xdr.spec.p1'`"
then
	echo shar: "error transmitting 'rpc/doc/xdr.spec.p1'" '(should have been 49809 characters)'
fi
chmod 444 'rpc/doc/xdr.spec.p1'
fi
exit 0
#	End of shell archive