XDR (EXTERNAL DATA REPRESENTION)(3n,L) XDR (EXTERNAL DATA REPRESENTATION)(3n,L)
-------------------------------------------------------------------------------
XDR (External Data Representation)
PURPOSE
Allows programmers to describe basic data types in a uniform representation.
LIBRARY
Internet Library (libc.a)
SYNTAX
#include <rpc/rpc.h>
DESCRIPTION
XDR provides programmers with a specification of uniform representations for
basic data types. XDR does not depend on machine languages, operating systems,
or architectures; thus, networked computers can share data regardless of the
machine on which the data is produced or consumed.
For basic data types such as integers and strings, XDR provides primitives that
serialize, or translate, information from the local host's representation to
XDR representation, and deserialize, or translate, from the XDR representation
to the local host's representation. XDR also uses constructor primitives that
allow the use of the basic data types to create more complex data types, such
as arrays and discriminated unions.
XDR describes input and output data structures in a data description language
that resembles the C programming language. It is important to remember that C
language constructs define the code for programs while XDR standardizes the
representation of data types in the programming code. Representing data in
standardized formats resolves situations that can occur if different byte
ordering exists on networked machines and enables machines with different
structure alignment algorithms to communicate with each other.
The XDR routines are not dependent on direction. That is, the same routine is
called to serialize and deserialize data. To achieve this independence, XDR
passes the addresses of the objects instead of passing the object itself.
XDR is based on the assumption that bytes (or 8 bits of data, which are also
called an octet) can be ported and encoded on media that can preserve the
meaning of the bytes across the hardware boundaries of data. For example,
bytes are ported and encoded from low order to high order in local area
networks.
XDR does not represent bit fields or bit maps. It represents data in blocks of
multiples of 4 bytes (32 bits). The bytes are numbered from 0 (zero) to the
Processed Nov. 7, 1990 XDR (External Data Representation)(3n,L) 1
XDR (EXTERNAL DATA REPRESENTION)(3n,L) XDR (EXTERNAL DATA REPRESENTATION)(3n,L)
value of n-1, where the value (n mod 4) = 0. They are read or written to a
byte stream in the order that byte m precedes byte m+1.
XDR SUBROUTINES
The XDR subroutines discussed in this section cover the following:
o Library primitives for basic data types and constructed data types. Basic
data types include the number filters (for integers, floating-point and
double-precision numbers), enumeration filters, and the routine for passing
no data. Constructed data types include the filters for strings, arrays,
unions, pointers, and opaque data.
o Data stream creation routines that are used to call streams for serializing
(and deserializing) data to or from standard I/O file streams, TCP/IP
connections, AIX files, and memory.
o Implementation of new XDR streams.
o Passing linked lists using XDR.
Before the XDR routines are discussed in detail, XDR data type representations
are introduced and defined in the next section to make the discussion of the
routines easier to understand.
XDR Data Type Representation
While many of XDR's data representations are similar to the data types used in
C language constructs, there are some differences. For that reason, the data
objects converted to XDR representation are briefly described in this section.
More detailed information about data types can be found in IBM AIX C Language
Guide and Reference
INTEGERS: An XDR integer is a numerical integer value in the range [-
2,147,483,648 to 2,147,483,647] that occupies 32 bits. An integer is
represented in two's complement notation. Its most significant byte is 0 and
least significant byte is 3.
UNSIGNED INTEGERS: An XDR integer is a numerical integer value that encodes a
nonnegative integer from the range [0 to 4294967295] that occupies 32 bits. It
is represented by an unsigned binary number whose most significant byte is 0
and least significant byte is 3. The shortened form is u_.
ENUMERATIONS: Enumerations have the same representation as integers. They are
used to describe subsets of integers. Enumerations are defined as follows:
typedef enum { name = value, ... } type-name;
For example, the colors red, yellow, and blue are described in an enumerated
type by the following:
typedef enum { RED = 2, YELLOW = 3, BLUE = 5 } colors;
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 2
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
BOOLEANS: A Boolean is an enumeration that takes the following form:
typedef enum { FALSE = 0, TRUE = 1 } boolean;
FLOATING-POINT DATA: An XDR floating point is data that encodes normalized
single floating-point numbers that conform to IEEE standard and occupy 32 bits
(4 bytes). A floating-point number is made up of an integer with an exponent.
The integer can contain a fraction value. Its most significant bit is 0 and
least significant bit is 31. The representation for floating points is the
following:
(-1)(S*)2(E-Bias*)1.F
The following describes the IEEE coding standard for the fields represented in
this notation:
S The sign of the number. The value 0 specifies positive and the value
1, negative. The most significant bit is 0.
E Exponent of the number in base 2. Floats devote 8 bits to this field.
It is biased by 127. The most significant bit is 1.
F Fractional part of the number's mantissa in base 2. Floats devote 23
bits to this field. The most significant bit is 9.
Note: Consult the IEEE specification when encoding signed 0, signed infinity
(overflow), and denormalized numbers (underflow). Under IEEE
specifications, the value of NaN depends on your operating system. NaN
represents the phrase not a number. It is not recommended for
describing data types.
DOUBLE-PRECISION DATA: XDR double-precision data encodes double-precision,
floating-point numbers that conform to IEEE standard and occupy 64 bits (8
bytes). A double-precision point is made up of an integer with an exponent.
The integer can contain a fractional value. The most significant bit is 0 and
least significant bit is 63. Double-precisions can be represented in this
following form:
(-1)(S*)2(E-Bias*)1.F
The following describes the IEEE coding standard for the fields represented in
this notation:
S The sign of the number. The value 0 specifies positive and the value
1, negative. The most significant bit is 0.
E Exponent of the number in base 2. Doubles devote 11 bits to this
field. It is biased by 1023. The most significant bit is 1.
F Fractional part of the number's mantissa in base 2. Doubles devote 52
bits to this field. The most significant bit is 12.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 3
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
Note: Consult the IEEE specification when encoding signed zero, signed
infinity (overflow), and denormalized numbers (underflow). Under IEEE
specifications, the value of NaN depends on your operating system. NaN
represents the phrase not a number. It is not recommended for
describing data types.
OPAQUE DATA: XDR opaque data is data of a fixed size that is passed to another
machine without being interpreted. It is encoded in multiples of 4 bytes and
defined by the following:
typedef opaque type-name[n];
opaque name[n];
In the definition, n is the static number of bytes needed to contain the opaque
data. If n is not a multiple of four, the n bytes are followed by the number
of bytes needed to make the opaque data object's total byte count a multiple of
four.
COUNTED BYTE STRINGS: XDR-counted byte strings are strings of n bytes
(numbered 0 through n-1) encoded as an unsigned integer followed by the actual
bytes of the string. For example, the counted byte string "examples" is
encoded as "8examples" (8 bytes, and then the actual bytes for the word
"examples").
If n is not a multiple of four, the n bytes are followed by the number of bytes
needed to make the opaque data object's total byte count a multiple of four.
The data description of strings follows:
typedef string type-name<n>;
typedef string type-name<>;
string name <n>;
string name<>;
The XDR data description language uses "<" and ">" (angle brackets) for objects
with variable lengths, and "[" and "]" (square brackets) for objects with fixed
lengths.
The constant n specifies the maximum number of bytes a string can contain. If
n is not specified, XDR assumes the maximum length is 2(32)-1. The constant n
is listed in a protocol specification. For example, if a protocol specifies
that a file name can be no longer than 255 bytes, it is represented as "string
filename<255>;".
FIXED ARRAYS: XDR fixed arrays are sets of homogenous, or identical, elements
of fixed sizes. The array's elements are encoded in their natural order of 0
to n-1. The data description for fixed-size arrays of homogeneous elements is
defined as follows:
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 4
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
typedef elementtype type-name[n];
elementtype name[n];
COUNTED ARRAYS: XDR-counted arrays are sets of homogenous, or identical,
elements of varying lengths. The array is encoded starting with the element
count specified by an unsigned integer (n) followed by each array element from
0 through n-1.
The data description for counted arrays follows:
typedef elementtype type-name<n>;
typedef elementtype type-name<>;
elementtype name<n>;
elementtype name<>;
The constant n specifies the maximum number of an element count of an array.
If n is not specified, XDR assumes the maximum length is 2(32)-1. The constant
n is listed in a protocol.
STRUCTURES: XDR structures are sets of components put together to create a
specific data set. They are very similar to the standard C language
structures.
A structure's components are encoded in the order of their declaration in the
structure. The data description for structures follows:
typedef struct {
component-type component-name;
...
} type-name;
DISCRIMINATED UNIONS: An XDR discriminated union is a set of data composed of
a discriminant and another data type. The discriminant is an enumeration. The
other data type is selected from a set of prearranged types according to the
value of the discriminant. The component types are called arms of the union.
The discriminated union is encoded starting with the discriminant followed by
the arm.
The data description for discriminated unions is as follows:
typedef union switch (discriminant-type) {
discriminant-value: arm-type;
...
default: default-arm-type;
} type-name;
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 5
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
Note: The default arm is optional. If it is not specified, a union cannot
encode discriminant values that are not specified. Most specifications
do not use default arms.
XDR Library Routines
XDR routines are organized as a library of primitives that define the data
types as well as create data streams. In this section, the routines are
grouped by function. The filter primitives for basic and constructed data
types appear first, followed by the non-filter primitives for manipulating XDR
streams.
When using XDR with RPC (Remote Procedure Call), it is important to note that
RPC clients do not create data streams themselves. The RPC system creates the
streams itself. RPC passes the information about the data streams as opaque
data in the form of handles. This opaque data handle is referred to in
routines as the xdrs parameter.
Programmers who use C language programs with XDR routines must include the
<rpc/xdr.h> file, which contains the necessary XDR interfaces.
Since XDR allows programmers to read and write C language constructs,
programmers can also write their own XDR routines to define other data types.
For each data type, there is an XDR routine associated with it. These XDR
routines take the following form:
xdr_xxx (xdrs, fp)
XDR *xdrs;
xxx *fp;
{
}
The xxx parameter represents a data type. The xdrs parameter is an opaque
handle that points to an XDR stream. The opaque handle pointer is passed to
the primitive XDR routines. The fp parameter points to an address of a data
value that provides data to the stream or receives data from it.
Unless noted otherwise, XDR routines return the value 1 if they succeed and the
value 0 if they do not.
Filter Primitives
Filter primitives define basic and constructed data types. Basic data types
include numbers, floating points, and generic enumerations. Constructed data
types include strings, byte arrays, opaque data, pointers and unions.
Constructed data type primitives require more parameters and perform more
complicated functions, such as memory management.
BASIC DATA TYPES: The XDR basic data types include number filters,
floating-point filters, and enumeration filters. Also included with these
primitives is a routine for use when no data is exchanged.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 6
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
Number Filters
The XDR library provides primitives that translate between types of numbers and
external representations. The XDR number filters cover the signed and unsigned
integers as well as the signed and unsigned short and long integers. The
following list of routines are the XDR library number filters.
xdr_int (xdrs, ip)
XDR *xdrs;
int *ip;
The xdr_int filter primitive translates between C language integers and
their external representations. The xdrs parameter is an XDR stream
handle. The ip parameter points to the address of the number that
provides data to the XDR stream or receives data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
xdr_u_int (xdrs, up)
XDR *xdrs;
u_int *up;
The xdr_u_int filter primitive translates between C language unsigned
integers and their external representations. The xdrs parameter is an
XDR stream handle. The up parameter points to the address of the number
that provides data to the XDR stream or receives data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
xdr_long (xdrs, lip)
XDR *xdrs;
long *lip;
The xdr_long filter primitive translates between C language long integers
and their external representations. The xdrs parameter is an XDR stream
handle. The lip parameter points to the address of the number that
provides data to the XDR stream or receives data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
xdr_u_long (xdrs, lup)
XDR *xdrs;
u_long *lup;
The xdr_u_long filter primitive translates between C language unsigned
long integers and their external representations. The xdrs parameter is
an XDR stream handle. The lup parameter points to the address of the
number that provides data to the XDR stream or receives data from it.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 7
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
xdr_short (xdrs, sip)
XDR *xdrs;
short *sip;
The xdr_short filter primitive translates between C language short
integers and their external representations. The xdrs parameter is an
XDR stream handle. The sip parameter points to the address of the number
that provides data to the XDR stream or receives data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
xdr_u_short (xdrs, sup)
XDR *xdrs;
u_short *sup;
The xdr_u_short filter primitive translates between C language unsigned
short integers and their external representations. The xdrs parameter is
an XDR stream handle. The sup parameter points to the address of the
number that provides data to the XDR stream or receives data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Floating-Point Filters
The XDR library provides primitives that translate between floating-point data
and their external representations. Floating-point data encodes an integer
with an exponent. Floats and double-precision numbers compose floating-point
data.
Note: Numbers are represented as IEEE standard floating points. Routines may
fail when decoding IEEE representations into machine-specific
representations or vice-versa.
xdr_float (xdrs, fp)
XDR *xdrs;
float *fp;
The xdr_float filter translates between C floats (normalized single
floating-point numbers) and their external representations. The xdrs
parameter is an XDR stream handle. The fp parameter points to the
address of the float that provides data to the XDR stream or receives
data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 8
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
xdr_double (xdrs, dp)
XDR *xdrs;
double *dp;
The xdr_double filter translates between C double-precision numbers and
their external representations. The xdrs parameter is an XDR stream
handle. The dp parameter points to the address of the double-precision
number that provides data to the XDR stream or receives data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Enumeration Filters
The XDR library provides a primitive for generic enumerations that is based on
the assumption that a C enumeration value (enum) has the same representation.
There is a special enumeration in XDR known as Boolean.
xdr_enum (xdrs, ep)
XDR *xdrs;
enum_t *ep;
The enum filter primitive translates between C language enums, which are
actually integers, and their external representations. The xdrs parameter is
an XDR stream handle. The ep parameter points to the address of the
enumeration data that provides data to the XDR stream or receives data from it.
Upon successful completion, this routine returns the value TRUE. Otherwise, it
returns the value FALSE.
xdr_bool (xdrs, bp)
XDR *xdrs;
bool_t *bp;
The bool filter primitive translates between Booleans and their external
representations which is either 1 (for TRUE) or 0 (for FALSE). The xdrs
parameter is an XDR stream handle. The bp parameter points to the
address of the Boolean data that provides data to the XDR stream or
receives data from it.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
No Data
From time to time, an XDR routine must be supplied to the RPC system, but no
data is required or passed. The XDR library provides the following primitive
for this function:
xdr_void ()
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 9
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
The xdr_void primitive has no function parameters, and the routine always
returns the value 1.
CONSTRUCTED DATA TYPE FILTERS: Constructed data type filters allow complex
data types to be created from basic data types. They require more parameters
in order to perform more complicated functions than basic data types. The
constructed data types can use memory management. Memory is allocated when
deserializing data with the XDR_DECODE subroutines. Memory is deallocated
through the XDR_FREE subroutines.
Strings
A string is defined as a sequence of bytes terminated by a null byte. The null
byte does not figure into the length of the string. Externally, strings are
represented by a sequence of ASCII characters. Internally, XDR represents them
as pointers to characters. The XDR library includes primitives for strings and
wrap strings.
xdr_string (xdrs, sp, maxlength)
XDR *xdrs;
char **sp;
u_int maxlength;
The xdr_string filter primitive translates between strings and their
external representation. The xdrs parameter points to the XDR stream
handle. The sp parameter points to the address of the pointer to the
string. The maxlength parameter specifies the maximum length of the
string allowed during encoding or decoding. This value is set in a
protocol. For example, if a protocol specification specifies that a file
name cannot be longer than 255 characters, a string cannot exceed 255
characters.
The routine returns 0 if the number of characters exceeds maxlength, or 1
if it does not.
When serializing a string, the sp parameter points to a string of a
certain length. If the string does not exceed maxlength, the bytes are
serialized.
When deserializing a string, the length of the incoming string is
determined. The string must not exceed maxlength. Next, sp is
dereferenced. If the value of *sp is NULL, a string of the appropriate
length is allocated and *sp is set to this string. If the original value
of *sp is not NULL, XDR assumes that a target area has been allocated to
hold the strings that are no longer than specified by maxlength. The
string is decoded into the target area, and the routine appends a null
character to the string.
In the XDR_FREE subroutine, the string is obtained by dereferencing sp.
If the value of the string is not NULL, the data allocated to the string
is freed and the pointer is set to NULL.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 10
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
xdr_wrapstring (xdrs, sp)
XDR *xdrs
char **sp
The xdr_wrapstring filter primitive calls the xdr_string routine with the
maximum length set as the maximum value of an unsigned integer. This is
a useful routine since it passes only two parameters instead of the three
required by xdr_string. The xdrs parameter points to the XDR stream
handle. The sp parameter points to the address of the pointer to the
string.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Byte Arrays
The XDR library provides a primitive for byte arrays. Although similar to
strings, byte arrays differ from strings by having a byte count. That is, the
length of the array is set by an unsigned integer. They also differ since byte
arrays are not terminated with a null character. External and internal
representation of byte arrays are the same.
xdr_bytes (xdrs, bpp, lp, maxlength)
XDR *xdrs;
char **bpp;
u_int *lp;
u_int maxlength;
The xdr_bytes filter primitive translates between counted byte strings
and their external representation. The xdr_bytes primitive handles a
subset of generic arrays, in which the size of the element is 1, and each
element's external description is built-in.
The xdrs parameter points to the XDR stream handle. The bpp parameter
points to the address of the pointer to the byte array. The lp parameter
points to the length of the byte area. When serializing, XDR gets the
length of the byte area by dereferencing lp. When deserializing, *lp is
set to the byte length. The maxlength parameter specifies the maximum
number of bytes allowed when XDR encodes or decodes messages.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Arrays
The XDR library provides a filter primitive for handling arrays of arbitrary
elements. Arrays of this type are handled in much the same way as a byte
array, which handles a subset of generic arrays where the size of the elements
and their external description is predetermined. This primitive for generic
arrays elements requires an additional parameter to define the size of the
array and to call an XDR routine to encode or decode each element in the array.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 11
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
xdr_array (xdrs, arrp, sizep,maxlength, elsize, elproc)
XDR *xdrs;
char **arrp;
u_int *sizep;
u_int maxlength;
u_int elsize;
xdrproc_t elproc;
The xdr_array filter primitive translates between sets of arbitrary
elements and their corresponding external representations.
The xdrs parameter points to the XDR stream handle. The arrp parameter
points to the address of the pointer to the array. The sizep parameter
points to the address of the element count of the array. The maxlength
parameter specifies the maximum number of array elements. The elsize
parameter specifies the size in bytes of each of the array's elements.
The elproc parameter specifies the name of the XDR routine called to
serialize, deserialize, or free each element in the array.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Fixed-Length Arrays
XDR does not provide a primitive for defining a fixed-length array.
Programmers can set the size of fixed length arrays by including conditional
statements in the syntax of an xdr_array routine.
The following examples show how to construct a fixed-length array. First, a
new data structure is defined, and then an XDR routine that serializes (and
deserializes) the new structure is coded. The following data structure defines
a network user as "netuser":
struct netuser {
char *nu_machinename;
int nu_uid;
u_int nu_glen;
int nu_gids;
};
#define NLEN 255
#define NGRPS 20
The nu_machinename parameter specifies the network user's computer host name,
which can be obtained by using the gethostname command. The nu_uid parameter
specifies the network user's user ID, which can be obtained by using the
geteuid command. The glen parameter specifies the length of the group array
while the nu_gids parameter specifies the network user's group IDs, which can
be obtained by using the getgroups command. "NLEN" sets the local host name
length maximum at 255 characters. "NGRPS" sets the maximum number of groups
the user can be in at 20 groups.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 12
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
The XDR routine generated to serialize and deserialize the "netuser" structure
is coded as follows:
bool_t
xdr_netuser (xdrs, nup)
XDR *xdrs;
struct netuser *nup;
{
return (xdr_string(xdrs,& nup-> nu_machinename, NLEN) &&
xdr_int (xdrs, & nup->nu_uid) &&
xdr_array (xdrs,& nup->nu_gids,& nup->nu_glen, NGRPS,
sizeof (int), xdr_int));
}
The xdrs parameter identifies an XDR stream handle. The nup parameter points
to the address of the structure "netuser".
To code a routine to use fixed-size arrays, the preceding example can be
rewritten as follows:
#define NLEN 255
#define NGRPS 20
struct netuser {
char *nu_machinename;
int nu_uid;
int nu_gids;
};
bool_t
xdr_netuser (xdrs, nup)
XDR *xdrs;
struct netuser *nup;
{
int i;
if (!xdr_string(xdrs;& nup-> nu_machinename, NLEN))
return (FALSE);
if (!xdr_int (xdrs, & nup->nu_uid))
return (FALSE);
for (i = 0; i < NGRPS; i+++) {
if (!xdr_int (xdrs, & nup->nu_gids [i]))
return (FALSE);
}
return (TRUE);
}
This program sets the size of the fixed-array using the parameters as specified
in the preceding examples.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 13
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
Opaque Data
Opaque data is composed of bytes of a fixed size that are not interpreted as
they pass through the data streams. Opaque data bytes, such as handles, are
passed back and forth from the servers to clients without being inspected by
the client. The client uses the data as it is and then returns it to the
server. By definition, the actual data contained in the opaque object is not
portable between computers.
bool_t
xdr_opaque (xdrs, p, len)
XDR *xdrs;
char *p;
u_int len;
The xdr_opaque filter primitive translates between opaque data and its
external representation. The xdrs parameter points to the XDR stream
handle. The p parameter points to the address of the opaque object while
the len parameter specifies the size, in bytes, of the object.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Discriminated Unions
A discriminated union is a C language union, which is an object that holds
several data types, where one arm of the union is an enumeration value, or
discriminant, that holds a specific object that is processed over the system
first. The discriminant is an enumeration value (enum_t).
xdr_union (xdrs, dscmp, unp, armchoices, defaultarm)
XDR *xdrs;
enum_t *dscmp;
char *unp;
struct xdr_discrim *armchoices;
xdrproc_t defaultarm;
The xdr_union filter primitive translates between discriminated unions
and their external representations.
The xdrs parameter points to the XDR stream handle. The dscmp parameter
points to the address of the union's discriminant. The discriminant is
an enum_t value. The unp parameter is a character pointer to the address
of the union. The armchoices parameter points to an array of structures
that define other data types. The defaultarm parameter is a structure
provided in case no discriminants are found.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Pointers to Structures
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 14
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
The XDR library provides the primitive for pointers so that structures
referenced within other structures can be serialized, deserialized, and freed
without causing problems. The xdr_reference primitive cannot attach special
meaning to a NULL pointer during serialization. Attempting to pass the address
of a NULL pointer can cause a memory fault. Programmers must be sure to
describe data with a two-armed discriminated union. One arm is used when the
pointer is valid. The other is used when the pointer is NULL.
xdr_reference (xdrs, pp, size, proc)
XDR *xdrs;
char **pp;
u_int size;
xdrproc_t proc;
The xdr_reference filter primitive provides chase pointers to structures
within structures.
The xdrs parameter points to the XDR stream handle. The pp parameter
points to the address of the pointer to the structure. When decoding
data, XDR allocates storage if the pointer is NULL. The size parameter
specifies the size of the structure pointed to. The proc parameter
specifies the XDR procedure that describes the structure.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Non-Filter Primitives
The XDR non-filter primitives are used to manipulate XDR streams.
u_int
xdr_getpos (xdrs)
XDR *xdrs;
The xdr_getpos routine returns an unsigned integer that describes the
current position in the data stream. The xdrs parameter points to the
XDR stream handle.
In some XDR streams, this routine returns the value -1 even if the value
has no meaning.
bool_t
xdr_setpos (xdrs, pos)
XDR *xdrs;
u_int pos;
The xdr_setpos primitive changes the current position in the XDR stream.
The xdrs parameter points to the XDR stream handle. The pos parameter is
the new position setting.
Upon successfully repositioning the stream, the routine returns the value
1. In some XDR streams, you cannot set a position. If you try to set a
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 15
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
position in one of these XDR streams, the routine fails and the value 0
is returned. This routine also fails if you request a position that is
not within the stream's boundaries. (Boundaries vary across streams.)
void
xdr_destroy (xdrs)
XDR *xdrs;
The xdrs_destroy routine destroys the XDR stream pointed to by the xdrs
parameter, and frees the private data structures allocated to the stream.
The use of the XDR stream handle is undefined after it is destroyed.
XDR Operation Directions
The value represented by "xdrs->x_op" is either XDR_ENCODE, XDR_DECODE, or
XDR_FREE. These operation values are handled internally by the XDR routines
themselves. This means the same XDR routine can be called to serialize and
deserialize data.
Data Stream Access
XDR data streams are obtained by calling creation routines. These creation
routines take arguments specifically designed to the properties of the stream.
There are existing XDR data streams for serializing (and deserializing) data in
standard input/output files, memory, and TCP/IP connections and files.
Note: RPC clients do not need to create XDR streams. The RPC system creates
them and passes them to the clients.
Standard I/O Streams
XDR data streams serialize and deserialize standard input/output by calling the
standard input/output creation routine, xdrstdio_create.
#include <stdio.h>
#include <rpc/rpc.h>
void
xdrstdio_create (xdrs, file, x_op)
XDR *xdrs;
FILE *file;
enum xdr_op x_op;
The xdrstdio_create routine initializes the XDR data stream pointed to by
the xdrs parameter. The file parameter points to the standard
input/output device from which data is written or read.
The x_op parameter specifies an XDR direction. The possible choices are
XDR_ENCODE, XDR_DECODE, or XDR_FREE.
Memory Streams
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 16
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
XDR data streams serialize and deserialize data from memory by calling the XDR
memory creation routine, xdrmem_create. In RPC, UDP/IP implementation of
remote procedure calls use this routine to build complete call and reply
messages in memory before sending the message to the recipient.
#include <rpc/rpc.h>
void
xdrmem_create (xdrs, addr, len, x_op)
XDR *xdrs;
char *addr;
u_int len;
enum xdr_op x_op;
The xdrmem_create routine initializes in local memory the XDR stream
pointed at by the xdrs parameter. The addr parameter points to the
memory where the XDR stream's data is written to or read from. The len
parameter specifies the length of the memory in bytes. The x_op
parameter specifies the XDR direction. The possible choices are
XDR_ENCODE, XDR_DECODE, or XDR_FREE.
Record Streams
Record streams are XDR streams built on top of record fragments, which are
built on TCP/IP streams. TCP/IP is a connection protocol for a transporting
large streams of data at one time, which contrasts with transporting a single
data packet at a time. The primary use of a record stream is to interface
remote procedure calls to TCP connections. It can also be used to stream data
into or out of normal files.
XDR provides a record creation routine, xdrrec_create, for initializing record
streams, and three routines for marking, or delimiting, the records in the data
streams. These routines are discussed in the following:
#include <rpc/rpc.h>
void
xdrrec_create (xdrs, sendsize, recvsize, iohandle readproc, writeproc)
XDR *xdrs;
u_int sendsize;
u_int recvsize;
caddr_t iohandle;
int (*readproc) (), (*writeproc) ();
The xdrrec_create provides an XDR stream that can contain long sequences
of records, and handle them in both the encoding and decoding directions.
The record contents contain data in XDR form.
The xdrs parameter points to the XDR stream handle for the stream being
called. The sendsize parameter sets the size of the input buffer where
data is written to. The recvsize parameter sets the size of the output
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 17
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
buffer where data is read from. If no value is specified, the buffers
are set to the system defaults.
The iohandle parameter points to the input/output buffer's handle, which
is opaque. The readproc parameter points to the routine to call when a
buffer needs to be filled, and the writeproc parameter points to the
routine to call when a buffer needs to be flushed. These routines are
similar to the read and write system calls.
The readproc and writeproc routines take the following form:
int
process (iohandle, buf, nbytes)
char *iohandle;
char *buf;
int nbytes;
The process parameter identifies which routine (read or write) to call.
The readproc routine reads the number of bytes set by the nbytes
parameter and places the bytes into the buffer pointed to by the buf
parameter. The writeproc writes to the data stream the number of bytes
specified by the nbytes parameter from the buffer specified by the buf
parameter.
boot_t
xdrrec_endofrecord (xdrs, flushnow)
XDR *xdrs;
boot_t flushnow;
The xdrrec_endofrecord routine causes the current outgoing data to be
marked as a record. The xdrs parameter points to the XDR stream handle.
If the flushnow flag is used as a parameter with the value TRUE, the
stream's writeproc routine is called to write out the completed record.
Otherwise, writeproc is called when the output buffer is full.
bool_t
xdrrec_skiprecord (xdrs)
XDR *xdrs;
The xdrrec_skiprecord routine causes the position of an input stream to
move past the current record boundary to the beginning of the next record
in the stream.
bool_t
xdrrec_eof (xdrs)
XDR *xdrs;
The xdrrec_eof routine checks the buffer for an input stream. It returns
the value 1 when there is no more input in the stream's buffer. If it
returns the value 0, there is more input in the stream.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 18
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
Note: Do not confuse this to mean that there is no more data in the
underlying file descriptor.
Implementation of New XDR Streams
XDR streams can be created and implemented by programmers. Implementors must
make an XDR structure routine that includes operation routines available to
clients using a creation routine.
The abstract data types required for programmers to implement their own XDR
streams are provided in the following:
enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
typedef struct {
enum xdr_op x_op;
struct xdr_ops {
bool_t (*x_getlong) ();
boot_t (*x_putlong) ();
boot_t (*x_getbytes) ();
boot_t (*x_putbytes) ();
u_int (*x_getpostn) ();
boot_t (*x_setpostn) ();
caddr_t (*x_inline) ();
VOID (*x_destroy) ();
} *x_ops;
caddr_t x_public;
caddr_t x_private;
caddr_t x_base;
int x_handy;
} XDR;
The x_op parameter specifies the current operation being performed on the
stream. This field is important to the XDR primitives but does not affect the
implementation of the stream because the stream's implementation does not
depend on the value.
The following set of parameters are pointers to XDR stream manipulation
routines:
"x_getlong" Gets long integer values from the data stream.
"x_putlong" Puts long integer values into the data stream.
"x_getbytes" Gets bytes from the data stream.
"x_putbytes" Puts bytes into the data stream.
"x_getpostn" Returns stream offset.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 19
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
"x_setpostn" Repositions offset.
"x_inline" Points to internal data buffer which can be used for any purpose.
"x_destroy" Frees private data structure.
Macros for accessing the x_getpostn, x_setposn, and x_destroy routines are
defined earlier in this XDR section. See "Non-Filter Primitives."
The x_inline operation is defined as follows:
long *
x_inline (xdrs, len)
XDR *xdrs;
int len;
This routine returns a pointer to an internal piece of the buffer of a
stream, which is pointed to by the xdrs parameter. The len parameter
specifies the size, in bytes, of the buffer. If the routine cannot find
a buffer segment of the requested size, it may return the value 0. The
buffer can be used for any purpose, but the buffer is not data-portable.
The x_getbytes operation gets byte sequences from the underlying XDR stream,
while the x_putbytes operation puts byte sequences into the stream. The
routines appear as follows:
bool_t
operation (xdrs, buf, bytecount)
XDR *xdrs;
char *buf;
u_int bytecount;
The xdrs parameter parameter points to the XDR stream handle. The buf
parameter specifies the buffer and the bytecount specifies the size of
the byte sequence being put or obtained from the data stream.
The x_getlong operation gets long numbers from the underlying XDR stream, while
the x_putlong operation puts long numbers into the stream. These routines
translate the numbers between the machine representation and the XDR
representation. The routines appear as follows:
bool_t
operation (xdrs, lp)
XDR *xdrs;
long *lp
The xdrs parameter points to the XDR stream handle. The lp parameter
points to the address of the stream receiving and acquiring the numbers.
Upon successful completion, this routine returns the value TRUE.
Otherwise, it returns the value FALSE.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 20
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
Note: Higher level XDR implementations assume that signed and unsigned long
integers contain the same number of bits, and that nonnegative integers
and unsigned integers have the same bit representations.
The x_public, x_private, x_base and x_handy fields are specific to a stream's
implementation. The x_public parameter specifies user data that is private to
the stream's implementation and is not used by the XDR primitive that calls it.
The x_private parameter is a pointer to the implementation data. The x_base
parameter contains the position information in the data stream that is private
to the user implementation. The x_handy data can contain extra information as
necessary.
Passing Linked Lists Using XDR
This section describes how to pass linked lists of arbitrary length using XDR.
To help illustrate the functions of the XDR routine for encoding, decoding, or
freeing linked lists, the following example creates a data structure and
defines its associated XDR routine before creating the linked list. In the
example, a data structure and its associated XDR routines are created to list a
person's gross assets and liabilities. The data structure and its associated
XDR routine can be coded as follows:
struct gnumbers {
long g_assets;
long g_liabilities;
};
bool_t
xdr_gnumbers (xdrs, gp)
XDR *xdrs;
struct gnumbers *gp;
{
if (xdr_long (xdrs, &(gp->g_assets)))
return (xdr_long (xdrs, &( gp->g_liabilities)));
return(FALSE);
}
The xdrs parameter points to the XDR data stream handle, and the gp parameter
points to the address of the structure that provides the data to or from the
XDR stream.
To create a linked list of the assets and liabilities structure, the following
structure could be constructed:
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 21
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
typedef struct gnode {
struct gnumbers gn_numbers;
struct gnnode *nxt;
};
typedef struct gnnode *gnumbers_list;
The head of the linked list defines the data object. The nxt parameter
specifies whether the object has terminated. If the object continues, the nxt
parameter points to the address of the structure where the object continues.
However, when the object is serialized, the link addresses no longer contain
useful information.
The XDR data description of this linked list can be described by the recursive
type declaration of the "gnumbers_list" as follows:
struct gnumbers {
unsigned g_assets;
unsigned g_liabilities;
};
typedef union switch (boolean) {
case TRUE: struct {
struct gnumbers current_element;
gnumbers_list rest_of_list;
};
case FALSE: struct ();
} gnumbers_list:
In this description, the Boolean indicates whether data follows it. The value
of the Boolean is FALSE when no data follows it. The value of the Boolean is
TRUE, when it is followed by the rest of the object ("gnumbers" structure and
"gnumbers_list"). The data structure has no Boolean explicitly declared in it;
however the nxt parameter implicitly carries the information. Also note that
the XDR data description has no pointer explicitly declared in it.
To write a set of XDR routines to serialize or deserialize a linked list of
entries, you can use the XDR description of the data that has no pointer. The
set contains the mutually recursive routines xdr_gnumbers_list, xdr_wrap_list,
and xdr_gnnode, as the illustrated in the following:
bool_t
xdr_gnnode (xdrs, gp)
XDR *xdrs;
struct gnnode *gp;
{
return (xdr_gnumbers (xdrs, &( gp->gn_numbers)) &&
xdr_gnumbers_list (xdrs, &( gp->nxt)));
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 22
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
}
bool_t
xdr_wrap_list (xdrs, glp)
XDR *xdrs;
gnumbers_list *glp;
{
return (xdr_reference (xdrs, glp,
sizeof(struct gnnode), xdr_gnnode));
}
struct xdr_discrim choices [2] = {
/*
* called if another node needs serializing or deserializing
*/
{ TRUE, xdr_wrap_list },
/*
* called when no more nodes need serializing or deserializing
*/
{ FALSE, xdr_void }
}
bool_t
xdr_gnumbers_list (xdrs, glp)
XDR *xdrs;
gnumbers_list *glp;
{
bool_t more_data;
more_data = (*glp != (gnumbers_list)NULL);
return (xdr_union (xdrs, &more_data,
glp, choices, NULL));
}
The entry routine "xdr_gnumbers_list" translates between the Boolean value
"more_data" and the list pointer values. When there is no more data, the
"xdr_union" routine calls the "xdr_void" routine which terminates the
recursion. Otherwise, "xdr_union" calls "xdr_wrap_list" to dereference the
list pointers. The "xdr_gnnode" routine actually serializes (or deserializes)
the data of the linked list's current node. It then recursively calls
"xdr_gnumbers_list" to process the remainder of the list.
These routines function correctly in all three directions (XDR_ENCODE,
XDR_DECODE, and XDR_FREE) for linked lengths of any lengths (including zero).
The Boolean "more_data" is always initialized, but when XDR_DECODE is called,
"more_data" is overwritten by an externally generated value. The value of the
"bool_t" is lost in the stack, but its value is reflected in the pointers to
the list.
Because of the recursion involved with these routines, when you use them to
serialize or deserialize a list, the stack grows in linear proportion to the
number of nodes in the list. The routines can become difficult to code because
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 23
XDR (External Data Represention)(3n,L) XDR (EXTERNAL DATA REPRESENTAION)(3N,L)
of the number of primitives involved. The following routine shows how to
collapse the recursive routines:
bool_t
xdr_gnumbers_list (xdrs, glp)
XDR *xdrs;
gnumbers_list *glp;
{
bool_t more_data;
bool_t freeing
gnumbers_list *next; /*the next value of glp*/
freeing = (xdrs->x_op ==XDR_FREE);
while (TRUE) {
more_data = (*glp != (gnumbers_list)NULL);
if (!xdr_bool (xdrs, &more_data))
return (FALSE) ;
if (!more_data)
return (TRUE) ; /* we are done */
if ( freeing)
next = &((*glp)->nxt);
if (!xdr_reference (xdrs, glp sizeof(struct gnnode),
xdr_gnumbers))
return (FALSE);
glp = (freeing) ? next : &((*glp)->nxt);
}
}
The glp parameter acts as the address of the pointer to the head of the
remainder of the list to be serializes or deserialized. The glp parameter is
set to the address of the current node's nxt field at the end of the "while"
loop. The discriminated union is implemented inline. The "more_data" variable
is used in the same manner as in the preceding routines, and its value is
recomputed and reserialized (or redeserialized) at each repeat of the loop.
This example inspects the direction of the operation "(xdrs->x_op)".
Since *glp is a pointer to a node, the pointer is dereferenced by the
"xdr_reference" routine. The sizeof parameter sets the size of a node (data
values plus the "nxt" pointer), while "xdr_numbers" only serializes or
deserializes the data values.
RELATED INFORMATION
In this book: "Remote Procedure Call (RPC)."
The chapter on RPC in AIX Operating System Programming Tools and Interfaces.
Processed Nov. 7, 1990 XDR (EXTERNAL DATA REPRESENTAION)(3N,L) 24