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 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; typedef string type-name<>; string name ; 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; typedef elementtype type-name<>; elementtype name; 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 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 #include 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 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 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