2 .\" Must use -- eqn -- with this one
4 .\" @(#)xdr.nts.ms 2.2 88/08/05 4.0 RPCSRC
5 .\" $FreeBSD: src/lib/libc/rpc/PSD.doc/xdr.nts.ms,v 1.1.14.1 2000/11/24 09:36:30 ru Exp $
6 .\" $DragonFly: src/lib/libc/rpc/PSD.doc/xdr.nts.ms,v 1.2 2003/06/17 04:26:45 dillon Exp $
13 .if \\n%=1 .tl ''- % -''
16 .\" prevent excess underlining in nroff
18 .OH 'External Data Representation: Sun Technical Notes''Page %'
19 .EH 'Page %''External Data Representation: Sun Technical Notes'
22 \&External Data Representation: Sun Technical Notes
23 .IX XDR "Sun technical notes"
25 This chapter contains technical notes on Sun's implementation of the
26 External Data Representation (XDR) standard, a set of library routines
27 that allow a C programmer to describe arbitrary data structures in a
28 machinex-independent fashion.
29 For a formal specification of the XDR
31 .I "External Data Representation Standard: Protocol Specification".
32 XDR is the backbone of Sun's Remote Procedure Call package, in the
33 sense that data for remote procedure calls is transmitted using the
34 standard. XDR library routines should be used to transmit data
35 that is accessed (read or written) by more than one type of machine.\**
37 .IX XDR "system routines"
38 For a compete specification of the system External Data Representation
44 This chapter contains a short tutorial overview of the XDR library
45 routines, a guide to accessing currently available XDR streams, and
46 information on defining new streams and data types. XDR was designed
47 to work across different languages, operating systems, and machine
48 architectures. Most users (particularly RPC users) will only need
49 the information in the
51 .I "Floating Point Filters",
53 .I "Enumeration Filters"
55 Programmers wishing to implement RPC and XDR on new machines
56 will be interested in the rest of the chapter, as well as the
57 .I "External Data Representaiton Standard: Protocol Specification",
58 which will be their primary reference.
63 can be used to write XDR routines even in cases where no RPC calls are
67 C programs that want to use XDR routines
70 which contains all the necessary interfaces to the XDR system.
73 contains all the XDR routines,
76 example% \fBcc\0\fIprogram\fP.c\fI
83 Consider the following two programs,
90 main() /* \fIwriter.c\fP */
94 for (i = 0; i < 8; i++) {
95 if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) {
96 fprintf(stderr, "failed!\en");
110 main() /* \fIreader.c\fP */
114 for (j = 0; j < 8; j++) {
115 if (fread((char *)&i, sizeof (i), 1, stdin) != 1) {
116 fprintf(stderr, "failed!\en");
125 The two programs appear to be portable, because (a) they pass
127 checking, and (b) they exhibit the same behavior when executed
128 on two different hardware architectures, a Sun and a VAX.
130 Piping the output of the
134 program gives identical results on a Sun or a VAX.
137 sun% \fBwriter | reader\fP
142 vax% \fBwriter | reader\fP
146 With the advent of local area networks and 4.2BSD came the concept
147 of \*Qnetwork pipes\*U \(em a process produces data on one machine,
148 and a second process consumes data on another machine.
149 A network pipe can be constructed with
153 Here are the results if the first produces data on a Sun,
154 and the second consumes data on a VAX.
157 sun% \fBwriter | rsh vax reader\fP
158 0 16777216 33554432 50331648 67108864 83886080 100663296
162 Identical results can be obtained by executing
166 on the Sun. These results occur because the byte ordering
167 of long integers differs between the VAX and the Sun,
168 even though word size is the same.
169 Note that $16777216$ is $2 sup 24$ \(em
170 when four bytes are reversed, the 1 winds up in the 24th bit.
172 Whenever data is shared by two or more machine types, there is
173 a need for portable data. Programs can be made data-portable by
178 calls with calls to an XDR library routine
180 a filter that knows the standard representation
181 of a long integer in its external form.
182 Here are the revised versions of
188 #include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
190 main() /* \fIwriter.c\fP */
195 xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
196 for (i = 0; i < 8; i++) {
197 if (!xdr_long(&xdrs, &i)) {
198 fprintf(stderr, "failed!\en");
211 #include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
213 main() /* \fIreader.c\fP */
218 xdrstdio_create(&xdrs, stdin, XDR_DECODE);
219 for (j = 0; j < 8; j++) {
220 if (!xdr_long(&xdrs, &i)) {
221 fprintf(stderr, "failed!\en");
230 The new programs were executed on a Sun,
231 on a VAX, and from a Sun to a VAX;
232 the results are shown below.
235 sun% \fBwriter | reader\fP
239 vax% \fBwriter | reader\fP
243 sun% \fBwriter | rsh vax reader\fP
250 .IX XDR "portable data"
251 Integers are just the tip of the portable-data iceberg. Arbitrary
252 data structures present portability problems, particularly with
253 respect to alignment and pointers. Alignment on word boundaries
254 may cause the size of a structure to vary from machine to machine.
255 And pointers, which are very convenient to use, have no meaning
256 outside the machine where they are defined.
259 \&A Canonical Standard
260 .IX XDR "canonical standard"
262 XDR's approach to standardizing data representations is
264 That is, XDR defines a single byte order (Big Endian), a single
265 floating-point representation (IEEE), and so on. Any program running on
266 any machine can use XDR to create portable data by translating its
267 local representation to the XDR standard representations; similarly, any
268 program running on any machine can read portable data by translating the
269 XDR standard representaions to its local equivalents. The single standard
270 completely decouples programs that create or send portable data from those
271 that use or receive portable data. The advent of a new machine or a new
272 language has no effect upon the community of existing portable data creators
273 and users. A new machine joins this community by being \*Qtaught\*U how to
274 convert the standard representations and its local representations; the
275 local representations of other machines are irrelevant. Conversely, to
276 existing programs running on other machines, the local representations of
277 the new machine are also irrelevant; such programs can immediately read
278 portable data produced by the new machine because such data conforms to the
279 canonical standards that they already understand.
281 There are strong precedents for XDR's canonical approach. For example,
282 TCP/IP, UDP/IP, XNS, Ethernet, and, indeed, all protocols below layer five
283 of the ISO model, are canonical protocols. The advantage of any canonical
284 approach is simplicity; in the case of XDR, a single set of conversion
285 routines is written once and is never touched again. The canonical approach
286 has a disadvantage, but it is unimportant in real-world data transfer
287 applications. Suppose two Little-Endian machines are transferring integers
288 according to the XDR standard. The sending machine converts the integers
289 from Little-Endian byte order to XDR (Big-Endian) byte order; the receiving
290 machine performs the reverse conversion. Because both machines observe the
291 same byte order, their conversions are unnecessary. The point, however, is
292 not necessity, but cost as compared to the alternative.
294 The time spent converting to and from a canonical representation is
295 insignificant, especially in networking applications. Most of the time
296 required to prepare a data structure for transfer is not spent in conversion
297 but in traversing the elements of the data structure. To transmit a tree,
298 for example, each leaf must be visited and each element in a leaf record must
299 be copied to a buffer and aligned there; storage for the leaf may have to be
300 deallocated as well. Similarly, to receive a tree, storage must be
301 allocated for each leaf, data must be moved from the buffer to the leaf and
302 properly aligned, and pointers must be constructed to link the leaves
303 together. Every machine pays the cost of traversing and copying data
304 structures whether or not conversion is required. In networking
305 applications, communications overhead\(emthe time required to move the data
306 down through the sender's protocol layers, across the network and up through
307 the receiver's protocol layers\(emdwarfs conversion overhead.
312 The XDR library not only solves data portability problems, it also
313 allows you to write and read arbitrary C constructs in a consistent,
314 specified, well-documented manner. Thus, it can make sense to use the
315 library even when the data is not shared among machines on a network.
317 The XDR library has filter routines for
318 strings (null-terminated arrays of bytes),
319 structures, unions, and arrays, to name a few.
320 Using more primitive routines,
321 you can write your own specific XDR routines
322 to describe arbitrary data structures,
323 including elements of arrays, arms of unions,
324 or objects pointed at from other structures.
325 The structures themselves may contain arrays of arbitrary elements,
326 or pointers to other structures.
328 Let's examine the two programs more closely.
329 There is a family of XDR stream creation routines
330 in which each member treats the stream of bits differently.
331 In our example, data is manipulated using standard I/O routines,
333 .I xdrstdio_create ().
334 .IX xdrstdio_create() "" "\fIxdrstdio_create()\fP"
335 The parameters to XDR stream creation routines
336 vary according to their function.
339 takes a pointer to an XDR structure that it initializes,
342 that the input or output is performed on, and the operation.
345 for serializing in the
349 for deserializing in the
353 Note: RPC users never need to create XDR streams;
354 the RPC system itself creates these streams,
355 which are then passed to the users.
359 .IX xdr_long() "" "\fIxdr_long()\fP"
360 primitive is characteristic of most XDR library
361 primitives and all client XDR routines.
362 First, the routine returns
367 Second, for each data type,
369 there is an associated XDR routine of the form:
380 is long, and the corresponding XDR routine is
383 The client could also define an arbitrary structure
385 in which case the client would also supply the routine
387 describing each field by calling XDR routines
388 of the appropriate type.
389 In all cases the first parameter,
391 can be treated as an opaque handle,
392 and passed to the primitive routines.
394 XDR routines are direction independent;
395 that is, the same routines are called to serialize or deserialize data.
396 This feature is critical to software engineering of portable data.
397 The idea is to call the same routine for either operation \(em
398 this almost guarantees that serialized data can also be deserialized.
399 One routine is used by both producer and consumer of networked data.
400 This is implemented by always passing the address
401 of an object rather than the object itself \(em
402 only in the case of deserialization is the object modified.
403 This feature is not shown in our trivial example,
404 but its value becomes obvious when nontrivial data structures
405 are passed among machines.
406 If needed, the user can obtain the
407 direction of the XDR operation.
409 .I "XDR Operation Directions"
410 section below for details.
412 Let's look at a slightly more complicated example.
413 Assume that a person's gross assets and liabilities
414 are to be exchanged among processes.
415 Also assume that these values are important enough
416 to warrant their own data type:
425 The corresponding XDR routine describing this structure would be:
429 bool_t /* \fITRUE is success, FALSE is failure\fP */
430 xdr_gnumbers(xdrs, gp)
434 if (xdr_long(xdrs, &gp->g_assets) &&
435 xdr_long(xdrs, &gp->g_liabilities))
440 Note that the parameter
442 is never inspected or modified;
443 it is only passed on to the subcomponent routines.
444 It is imperative to inspect the return value of each XDR routine call,
445 and to give up immediately and return
447 if the subroutine fails.
449 This example also shows that the type
451 is declared as an integer whose only values are
455 (0). This document uses the following definitions:
464 Keeping these conventions in mind,
466 can be rewritten as follows:
470 xdr_gnumbers(xdrs, gp)
474 return(xdr_long(xdrs, &gp->g_assets) &&
475 xdr_long(xdrs, &gp->g_liabilities));
478 This document uses both coding styles.
480 \&XDR Library Primitives
481 .IX "library primitives for XDR"
482 .IX XDR "library primitives"
484 This section gives a synopsis of each XDR primitive.
485 It starts with basic data types and moves on to constructed data types.
486 Finally, XDR utilities are discussed.
487 The interface to these primitives
488 and utilities is defined in the include file
490 automatically included by
494 .IX "XDR library" "number filters"
496 The XDR library provides primitives to translate between numbers
497 and their corresponding external representations.
498 Primitives cover the set of numbers in:
501 [signed, unsigned] * [short, int, long]
504 Specifically, the eight primitives are:
507 bool_t xdr_char(xdrs, cp)
511 bool_t xdr_u_char(xdrs, ucp)
515 bool_t xdr_int(xdrs, ip)
519 bool_t xdr_u_int(xdrs, up)
523 bool_t xdr_long(xdrs, lip)
527 bool_t xdr_u_long(xdrs, lup)
531 bool_t xdr_short(xdrs, sip)
535 bool_t xdr_u_short(xdrs, sup)
541 is an XDR stream handle.
542 The second parameter is the address of the number
543 that provides data to the stream or receives data from it.
546 if they complete successfully, and
550 \&Floating Point Filters
551 .IX "XDR library" "floating point filters"
553 The XDR library also provides primitive routines
554 for C's floating point types:
557 bool_t xdr_float(xdrs, fp)
561 bool_t xdr_double(xdrs, dp)
567 is an XDR stream handle.
568 The second parameter is the address
569 of the floating point number that provides data to the stream
570 or receives data from it.
573 if they complete successfully, and
577 Note: Since the numbers are represented in IEEE floating point,
578 routines may fail when decoding a valid IEEE representation
579 into a machine-specific representation, or vice-versa.
581 \&Enumeration Filters
582 .IX "XDR library" "enumeration filters"
584 The XDR library provides a primitive for generic enumerations.
585 The primitive assumes that a C
587 has the same representation inside the machine as a C integer.
588 The boolean type is an important instance of the
590 The external representation of a boolean is always
603 bool_t xdr_enum(xdrs, ep)
607 bool_t xdr_bool(xdrs, bp)
611 The second parameters
615 are addresses of the associated type that provides data to, or
616 receives data from, the stream
620 .IX "XDR library" "no data"
622 Occasionally, an XDR routine must be supplied to the RPC system,
623 even when no data is passed or required.
624 The library provides such a routine:
627 bool_t xdr_void(); /* \fIalways returns TRUE\fP */
630 \&Constructed Data Type Filters
631 .IX "XDR library" "constructed data type filters"
633 Constructed or compound data type primitives
634 require more parameters and perform more complicated functions
635 then the primitives discussed above.
636 This section includes primitives for
637 strings, arrays, unions, and pointers to structures.
639 Constructed data type primitives may use memory management.
640 In many cases, memory is allocated when deserializing data with
642 Therefore, the XDR package must provide means to deallocate memory.
643 This is done by an XDR operation,
645 To review, the three XDR directional operations are
652 .IX "XDR library" "strings"
654 In C, a string is defined as a sequence of bytes
655 terminated by a null byte,
656 which is not considered when calculating string length.
657 However, when a string is passed or manipulated,
658 a pointer to it is employed.
659 Therefore, the XDR library defines a string to be a
661 and not a sequence of characters.
662 The external representation of a string is drastically different
663 from its internal representation.
664 Externally, strings are represented as
665 sequences of ASCII characters,
666 while internally, they are represented with character pointers.
667 Conversion between the two representations
668 is accomplished with the routine
670 .IX xdr_string() "" \fIxdr_string()\fP
673 bool_t xdr_string(xdrs, sp, maxlength)
680 is the XDR stream handle.
683 is a pointer to a string (type
687 specifies the maximum number of bytes allowed during encoding or decoding.
688 its value is usually specified by a protocol. For example, a protocol
689 specification may say that a file name may be no longer than 255 characters.
693 if the number of characters exceeds
701 small. If it is too big you can blow the heap, since
709 .IX xdr_string() "" \fIxdr_string()\fP
710 is similar to the behavior of other routines
711 discussed in this section. The direction
713 is easiest to understand. The parameter
715 points to a string of a certain length;
716 if the string does not exceed
718 the bytes are serialized.
720 The effect of deserializing a string is subtle.
721 First the length of the incoming string is determined;
726 is dereferenced; if the the value is
728 then a string of the appropriate length is allocated and
730 is set to this string.
731 If the original value of
733 is non-null, then the XDR package assumes
734 that a target area has been allocated,
735 which can hold strings no longer than
737 In either case, the string is decoded into the target area.
738 The routine then appends a null character to the string.
742 operation, the string is obtained by dereferencing
757 .IX "XDR library" "byte arrays"
759 Often variable-length arrays of bytes are preferable to strings.
760 Byte arrays differ from strings in the following three ways:
761 1) the length of the array (the byte count) is explicitly
762 located in an unsigned integer,
763 2) the byte sequence is not terminated by a null character, and
764 3) the external representation of the bytes is the same as their
765 internal representation.
768 .IX xdr_bytes() "" \fIxdr_bytes()\fP
769 converts between the internal and external
770 representations of byte arrays:
773 bool_t xdr_bytes(xdrs, bpp, lp, maxlength)
779 The usage of the first, second and fourth parameters
780 are identical to the first, second and third parameters of
783 The length of the byte area is obtained by dereferencing
787 is set to the byte length when deserializing.
790 .IX "XDR library" "arrays"
792 The XDR library package provides a primitive
793 for handling arrays of arbitrary elements.
796 routine treats a subset of generic arrays,
797 in which the size of array elements is known to be 1,
798 and the external description of each element is built-in.
799 The generic array primitive,
801 .IX xdr_array() "" \fIxdr_array()\fP
802 requires parameters identical to those of
805 the size of array elements,
806 and an XDR routine to handle each of the elements.
807 This routine is called to encode or decode
808 each element of the array.
812 xdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element)
818 bool_t (*xdr_element)();
822 is the address of the pointer to the array.
827 when the array is being deserialized,
828 XDR allocates an array of the appropriate size and sets
831 The element count of the array is obtained from
833 when the array is serialized;
835 is set to the array length when the array is deserialized.
838 is the maximum number of elements that the array is allowed to have;
840 is the byte size of each element of the array
843 can be used to obtain this value).
846 .IX xdr_element() "" \fIxdr_element()\fP
847 routine is called to serialize, deserialize, or free
848 each element of the array.
851 Before defining more constructed data types, it is appropriate to
852 present three examples.
856 A user on a networked machine can be identified by
857 (a) the machine name, such as
861 man page; (b) the user's UID: see the
863 man page; and (c) the group numbers to which the user belongs:
866 man page. A structure with this information and its associated
867 XDR routine could be coded like this:
872 char *nu_machinename;
877 #define NLEN 255 /* \fImachine names < 256 chars\fP */
878 #define NGRPS 20 /* \fIuser can't be in > 20 groups\fP */
881 xdr_netuser(xdrs, nup)
885 return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
886 xdr_int(xdrs, &nup->nu_uid) &&
887 xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen,
888 NGRPS, sizeof (int), xdr_int));
894 A party of network users could be implemented
898 The declaration and its associated XDR routines
905 struct netuser *p_nusers;
907 #define PLEN 500 /* \fImax number of users in a party\fP */
914 return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
915 sizeof (struct netuser), xdr_netuser));
921 The well-known parameters to
926 can be combined into a structure.
927 An array of these structures can make up a history of commands.
928 The declarations and XDR routines might look like:
936 #define ALEN 1000 /* \fIargs cannot be > 1000 chars\fP */
937 #define NARGC 100 /* \fIcommands cannot have > 100 args\fP */
943 #define NCMDS 75 /* \fIhistory is no more than 75 commands\fP */
946 xdr_wrap_string(xdrs, sp)
950 return(xdr_string(xdrs, sp, ALEN));
961 return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
962 sizeof (char *), xdr_wrap_string));
969 xdr_history(xdrs, hp)
973 return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
974 sizeof (struct cmd), xdr_cmd));
977 The most confusing part of this example is that the routine
979 is needed to package the
981 routine, because the implementation of
983 only passes two parameters to the array element description routine;
985 supplies the third parameter to
988 By now the recursive nature of the XDR library should be obvious.
989 Let's continue with more constructed data types.
992 .IX "XDR library" "opaque data"
994 In some protocols, handles are passed from a server to client.
995 The client passes the handle back to the server at some later time.
996 Handles are never inspected by clients;
997 they are obtained and submitted.
998 That is to say, handles are opaque.
1001 .IX xdr_opaque() "" \fIxdr_opaque()\fP
1002 primitive is used for describing fixed sized, opaque bytes.
1005 bool_t xdr_opaque(xdrs, p, len)
1012 is the location of the bytes;
1014 is the number of bytes in the opaque object.
1015 By definition, the actual data
1016 contained in the opaque object are not machine portable.
1018 \&Fixed Sized Arrays
1019 .IX "XDR library" "fixed sized arrays"
1021 The XDR library provides a primitive,
1023 for fixed-length arrays.
1027 #define NLEN 255 /* \fImachine names must be < 256 chars\fP */
1028 #define NGRPS 20 /* \fIuser belongs to exactly 20 groups\fP */
1031 char *nu_machinename;
1037 xdr_netuser(xdrs, nup)
1039 struct netuser *nup;
1043 if (!xdr_string(xdrs, &nup->nu_machinename, NLEN))
1045 if (!xdr_int(xdrs, &nup->nu_uid))
1047 if (!xdr_vector(xdrs, nup->nu_gids, NGRPS, sizeof(int),
1055 \&Discriminated Unions
1056 .IX "XDR library" "discriminated unions"
1058 The XDR library supports discriminated unions.
1059 A discriminated union is a C union and an
1061 value that selects an \*Qarm\*U of the union.
1064 struct xdr_discrim {
1069 bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm)
1073 struct xdr_discrim *arms;
1074 bool_t (*defaultarm)(); /* \fImay equal NULL\fP */
1076 First the routine translates the discriminant of the union located at
1078 The discriminant is always an
1080 Next the union located at
1085 is a pointer to an array of
1088 Each structure contains an ordered pair of
1090 If the union's discriminant is equal to the associated
1094 is called to translate the union.
1097 structure array is denoted by a routine of value
1099 (0). If the discriminant is not found in the
1103 procedure is called if it is non-null;
1104 otherwise the routine returns
1108 Suppose the type of a union may be integer,
1109 character pointer (a string), or a
1112 Also, assume the union and its current type
1113 are declared in a structure.
1118 enum utype { INTEGER=1, STRING=2, GNUMBERS=3 };
1121 enum utype utype; /* \fIthe union's discriminant\fP */
1129 The following constructs and XDR procedure (de)serialize
1130 the discriminated union:
1134 struct xdr_discrim u_tag_arms[4] = {
1135 { INTEGER, xdr_int },
1136 { GNUMBERS, xdr_gnumbers }
1137 { STRING, xdr_wrap_string },
1138 { __dontcare__, NULL }
1139 /* \fIalways terminate arms with a NULL xdr_proc\fP */
1143 xdr_u_tag(xdrs, utp)
1147 return(xdr_union(xdrs, &utp->utype, &utp->uval,
1153 was presented above in
1154 .I "The XDR Library"
1156 .I xdr_wrap_string()
1157 was presented in example C.
1162 (the last parameter) is
1164 in this example. Therefore the value of the union's discriminant
1165 may legally take on only values listed in the
1167 array. This example also demonstrates that
1168 the elements of the arm's array do not need to be sorted.
1170 It is worth pointing out that the values of the discriminant
1171 may be sparse, though in this example they are not.
1173 practice to assign explicitly integer values to each element of the
1174 discriminant's type.
1175 This practice both documents the external
1176 representation of the discriminant and guarantees that different
1177 C compilers emit identical discriminant values.
1181 using the other primitives in this section.
1184 .IX "XDR library" "pointers"
1186 In C it is often convenient to put pointers
1187 to another structure within a structure.
1190 .IX xdr_reference() "" \fIxdr_reference()\fP
1191 primitive makes it easy to serialize, deserialize, and free
1192 these referenced structures.
1195 bool_t xdr_reference(xdrs, pp, size, proc)
1205 the pointer to the structure;
1208 is the size in bytes of the structure (use the C function
1210 to obtain this value); and
1212 is the XDR routine that describes the structure.
1213 When decoding data, storage is allocated if
1218 There is no need for a primitive
1220 to describe structures within structures,
1221 because pointers are always sufficient.
1231 are NOT interchangeable external representations of data.
1234 Suppose there is a structure containing a person's name
1237 structure containing the person's gross assets and liabilities.
1243 struct gnumbers *gnp;
1246 The corresponding XDR routine for this structure is:
1254 if (xdr_string(xdrs, &pp->name, NLEN) &&
1255 xdr_reference(xdrs, &pp->gnp,
1256 sizeof(struct gnumbers), xdr_gnumbers))
1261 .IX "pointer semantics and XDR"
1262 .I "Pointer Semantics and XDR"
1264 In many applications, C programmers attach double meaning to
1265 the values of a pointer. Typically the value
1267 (or zero) means data is not needed,
1268 yet some application-specific interpretation applies.
1269 In essence, the C programmer is encoding
1270 a discriminated union efficiently
1271 by overloading the interpretation of the value of a pointer.
1272 For instance, in example E a
1277 the person's assets and liabilities are unknown.
1278 That is, the pointer value encodes two things:
1279 whether or not the data is known;
1280 and if it is known, where it is located in memory.
1281 Linked lists are an extreme example of the use
1282 of application-specific pointer interpretation.
1286 .IX xdr_reference() "" \fIxdr_reference()\fP
1287 cannot and does not attach any special
1288 meaning to a null-value pointer during serialization.
1289 That is, passing an address of a pointer whose value is
1293 when serialing data will most likely cause a memory fault and, on the UNIX
1294 system, a core dump.
1299 pointers. For more information about its use, see
1305 After reading the section on
1307 return here and extend example E so that
1308 it can correctly deal with
1318 primitives, implement a generic pointer handling primitive
1319 that implicitly deals with
1321 pointers. That is, implement
1324 \&Non-filter Primitives
1325 .IX "XDR" "non-filter primitives"
1327 XDR streams can be manipulated with
1328 the primitives discussed in this section.
1331 u_int xdr_getpos(xdrs)
1334 bool_t xdr_setpos(xdrs, pos)
1343 .IX xdr_getpos() "" \fIxdr_getpos()\fP
1344 returns an unsigned integer
1345 that describes the current position in the data stream.
1346 Warning: In some XDR streams, the returned value of
1349 the routine returns a \-1 in this case
1350 (though \-1 should be a legitimate value).
1354 .IX xdr_setpos() "" \fIxdr_setpos()\fP
1355 sets a stream position to
1357 Warning: In some XDR streams, setting a position is impossible;
1362 This routine will also fail if the requested position is out-of-bounds.
1363 The definition of bounds varies from stream to stream.
1367 .IX xdr_destroy() "" \fIxdr_destroy()\fP
1368 primitive destroys the XDR stream.
1370 after calling this routine is undefined.
1372 \&XDR Operation Directions
1373 .IX XDR "operation directions"
1374 .IX "direction of XDR operations"
1376 At times you may wish to optimize XDR routines by taking
1377 advantage of the direction of the operation \(em
1384 always contains the direction of the XDR operation.
1385 Programmers are not encouraged to take advantage of this information.
1386 Therefore, no example is presented here. However, an example in the
1388 topic below, demonstrates the usefulness of the
1393 .IX "XDR" "stream access"
1395 An XDR stream is obtained by calling the appropriate creation routine.
1396 These creation routines take arguments that are tailored to the
1397 specific properties of the stream.
1399 Streams currently exist for (de)serialization of data to or from
1402 streams, TCP/IP connections and UNIX files, and memory.
1404 \&Standard I/O Streams
1405 .IX "XDR" "standard I/O streams"
1407 XDR streams can be interfaced to standard I/O using the
1408 .I xdrstdio_create()
1409 .IX xdrstdio_create() "" \fIxdrstdio_create()\fP
1414 #include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
1417 xdrstdio_create(xdrs, fp, x_op)
1423 .I xdrstdio_create()
1424 initializes an XDR stream pointed to by
1426 The XDR stream interfaces to the standard I/O library.
1429 is an open file, and
1431 is an XDR direction.
1434 .IX "XDR" "memory streams"
1436 Memory streams allow the streaming of data into or out of
1437 a specified area of memory:
1440 #include <rpc/rpc.h>
1443 xdrmem_create(xdrs, addr, len, x_op)
1451 .IX xdrmem_create() "" \fIxdrmem_create()\fP
1452 initializes an XDR stream in local memory.
1453 The memory is pointed to by parameter
1457 is the length in bytes of the memory.
1462 are identical to the corresponding parameters of
1463 .I xdrstdio_create ().
1464 Currently, the UDP/IP implementation of RPC uses
1465 .I xdrmem_create ().
1466 Complete call or result messages are built in memory before calling the
1470 \&Record (TCP/IP) Streams
1471 .IX "XDR" "record (TCP/IP) streams"
1473 A record stream is an XDR stream built on top of
1474 a record marking standard that is built on top of the
1475 UNIX file or 4.2 BSD connection interface.
1478 #include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
1481 sendsize, recvsize, iohandle, readproc, writeproc)
1483 u_int sendsize, recvsize;
1485 int (*readproc)(), (*writeproc)();
1489 provides an XDR stream interface that allows for a bidirectional,
1490 arbitrarily long sequence of records.
1491 The contents of the records are meant to be data in XDR form.
1492 The stream's primary use is for interfacing RPC to TCP connections.
1493 However, it can be used to stream data into or out of normal
1498 is similar to the corresponding parameter described above.
1499 The stream does its own data buffering similar to that of standard I/O.
1504 determine the size in bytes of the output and input buffers, respectively;
1505 if their values are zero (0), then predetermined defaults are used.
1506 When a buffer needs to be filled or flushed, the routine
1510 is called, respectively.
1511 The usage and behavior of these
1512 routines are similar to the UNIX system calls
1517 the first parameter to each of these routines is the opaque parameter
1519 The other two parameters
1524 (byte count) are identical to the system routines.
1531 then it has the following form:
1536 * returns the actual number of bytes transferred.
1541 xxx(iohandle, buf, len)
1546 The XDR stream provides means for delimiting records in the byte stream.
1547 The implementation details of delimiting records in a stream are
1549 .I "Advanced Topics"
1551 The primitives that are specific to record streams are as follows:
1555 xdrrec_endofrecord(xdrs, flushnow)
1560 xdrrec_skiprecord(xdrs)
1568 .I xdrrec_endofrecord()
1569 .IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fP
1570 causes the current outgoing data to be marked as a record.
1577 will be called; otherwise,
1579 will be called when the output buffer has been filled.
1582 .I xdrrec_skiprecord()
1583 .IX xdrrec_skiprecord() "" \fIxdrrec_skiprecord()\fP
1584 causes an input stream's position to be moved past
1585 the current record boundary and onto the
1586 beginning of the next record in the stream.
1588 If there is no more data in the stream's input buffer,
1591 .IX xdrrec_eof() "" \fIxdrrec_eof()\fP
1594 That is not to say that there is no more data
1595 in the underlying file descriptor.
1597 \&XDR Stream Implementation
1598 .IX "XDR" "stream implementation"
1599 .IX "stream implementation in XDR"
1601 This section provides the abstract data types needed
1602 to implement new instances of XDR streams.
1607 The following structure defines the interface to an XDR stream:
1611 enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
1614 enum xdr_op x_op; /* \fIoperation; fast added param\fP */
1616 bool_t (*x_getlong)(); /* \fIget long from stream\fP */
1617 bool_t (*x_putlong)(); /* \fIput long to stream\fP */
1618 bool_t (*x_getbytes)(); /* \fIget bytes from stream\fP */
1619 bool_t (*x_putbytes)(); /* \fIput bytes to stream\fP */
1620 u_int (*x_getpostn)(); /* \fIreturn stream offset\fP */
1621 bool_t (*x_setpostn)(); /* \fIreposition offset\fP */
1622 caddr_t (*x_inline)(); /* \fIptr to buffered data\fP */
1623 VOID (*x_destroy)(); /* \fIfree private area\fP */
1625 caddr_t x_public; /* \fIusers' data\fP */
1626 caddr_t x_private; /* \fIpointer to private data\fP */
1627 caddr_t x_base; /* \fIprivate for position info\fP */
1628 int x_handy; /* \fIextra private word\fP */
1633 field is the current operation being performed on the stream.
1634 This field is important to the XDR primitives,
1635 but should not affect a stream's implementation.
1636 That is, a stream's implementation should not depend
1643 are private to the particular
1644 stream's implementation.
1647 is for the XDR client and should never be used by
1648 the XDR stream implementations or the XDR primitives.
1653 are macros for accessing operations. The operation
1655 takes two parameters:
1656 an XDR *, and an unsigned integer, which is a byte count.
1657 The routine returns a pointer to a piece of
1658 the stream's internal buffer.
1659 The caller can then use the buffer segment for any purpose.
1660 From the stream's point of view, the bytes in the
1661 buffer segment have been consumed or put.
1662 The routine may return
1664 if it cannot return a buffer segment of the requested size.
1667 routine is for cycle squeezers.
1668 Use of the resulting buffer is not data-portable.
1669 Users are encouraged not to use this feature.)
1675 blindly get and put sequences of bytes
1676 from or to the underlying stream;
1679 if they are successful, and
1681 otherwise. The routines have identical parameters (replace
1686 xxxbytes(xdrs, buf, bytecount)
1696 long numbers from and to the data stream.
1697 It is the responsibility of these routines
1698 to translate the numbers between the machine representation
1699 and the (standard) external representation.
1704 can be helpful in accomplishing this.
1705 The higher-level XDR implementation assumes that
1706 signed and unsigned long integers contain the same number of bits,
1707 and that nonnegative integers
1708 have the same bit representations as unsigned integers.
1711 if they succeed, and
1713 otherwise. They have identical parameters:
1721 Implementors of new XDR streams must make an XDR structure
1722 (with new operation routines) available to clients,
1723 using some kind of create routine.
1726 .IX XDR "advanced topics"
1728 This section describes techniques for passing data structures that
1729 are not covered in the preceding sections. Such structures include
1730 linked lists (of arbitrary lengths). Unlike the simpler examples
1731 covered in the earlier sections, the following examples are written
1732 using both the XDR C library routines and the XDR data description
1735 .I "External Data Representation Standard: Protocol Specification"
1737 language in complete detail.
1740 .IX XDR "linked lists"
1742 The last example in the
1744 topic earlier in this chapter
1745 presented a C data structure and its associated XDR
1746 routines for a individual's gross assets and liabilities.
1747 The example is duplicated below:
1757 xdr_gnumbers(xdrs, gp)
1759 struct gnumbers *gp;
1761 if (xdr_long(xdrs, &(gp->g_assets)))
1762 return(xdr_long(xdrs, &(gp->g_liabilities)));
1767 Now assume that we wish to implement a linked list of such information.
1768 A data structure could be constructed as follows:
1772 struct gnumbers_node {
1773 struct gnumbers gn_numbers;
1774 struct gnumbers_node *gn_next;
1777 typedef struct gnumbers_node *gnumbers_list;
1780 The head of the linked list can be thought of as the data object;
1781 that is, the head is not merely a convenient shorthand for a
1782 structure. Similarly the
1784 field is used to indicate whether or not the object has terminated.
1785 Unfortunately, if the object continues, the
1787 field is also the address of where it continues. The link addresses
1788 carry no useful information when the object is serialized.
1790 The XDR data description of this linked list is described by the
1791 recursive declaration of
1801 struct gnumbers_node {
1802 gnumbers gn_numbers;
1803 gnumbers_node *gn_next;
1807 In this description, the boolean indicates whether there is more data
1808 following it. If the boolean is
1810 then it is the last data field of the structure. If it is
1812 then it is followed by a gnumbers structure and (recursively) by a
1814 Note that the C declaration has no boolean explicitly declared in it
1817 field implicitly carries the information), while the XDR data
1818 description has no pointer explicitly declared in it.
1820 Hints for writing the XDR routines for a
1822 follow easily from the XDR description above. Note how the primitive
1824 is used to implement the XDR union above.
1829 xdr_gnumbers_node(xdrs, gn)
1833 return(xdr_gnumbers(xdrs, &gn->gn_numbers) &&
1834 xdr_gnumbers_list(xdrs, &gp->gn_next));
1838 xdr_gnumbers_list(xdrs, gnp)
1842 return(xdr_pointer(xdrs, gnp,
1843 sizeof(struct gnumbers_node),
1844 xdr_gnumbers_node));
1848 The unfortunate side effect of XDR'ing a list with these routines
1849 is that the C stack grows linearly with respect to the number of
1850 node in the list. This is due to the recursion. The following
1851 routine collapses the above two mutually recursive into a single,
1857 xdr_gnumbers_list(xdrs, gnp)
1862 gnumbers_list *nextp;
1865 more_data = (*gnp != NULL);
1866 if (!xdr_bool(xdrs, &more_data)) {
1872 if (xdrs->x_op == XDR_FREE) {
1873 nextp = &(*gnp)->gn_next;
1875 if (!xdr_reference(xdrs, gnp,
1876 sizeof(struct gnumbers_node), xdr_gnumbers)) {
1880 gnp = (xdrs->x_op == XDR_FREE) ?
1881 nextp : &(*gnp)->gn_next;
1888 The first task is to find out whether there is more data or not,
1889 so that this boolean information can be serialized. Notice that
1890 this statement is unnecessary in the
1892 case, since the value of more_data is not known until we
1893 deserialize it in the next statement.
1895 The next statement XDR's the more_data field of the XDR union.
1896 Then if there is truly no more data, we set this last pointer to
1898 to indicate the end of the list, and return
1900 because we are done. Note that setting the pointer to
1902 is only important in the
1904 case, since it is already
1912 Next, if the direction is
1916 is set to indicate the location of the next pointer in the list.
1917 We do this now because we need to dereference gnp to find the
1918 location of the next item in the list, and after the next
1919 statement the storage pointed to by
1921 will be freed up and no be longer valid. We can't do this for all
1922 directions though, because in the
1924 direction the value of
1926 won't be set until the next statement.
1928 Next, we XDR the data in the node using the primitive
1929 .I xdr_reference ().
1933 which we used before, but it does not
1934 send over the boolean indicating whether there is more data.
1935 We use it instead of
1937 because we have already XDR'd this information ourselves. Notice
1938 that the xdr routine passed is not the same type as an element
1939 in the list. The routine passed is
1941 for XDR'ing gnumbers, but each element in the list is actually of
1945 .I xdr_gnumbers_node()
1946 because it is recursive, and instead use
1948 which XDR's all of the non-recursive part. Note that this trick
1949 will work only if the
1951 field is the first item in each element, so that their addresses
1952 are identical when passed to
1953 .I xdr_reference ().
1957 to point to the next item in the list. If the direction is
1959 we set it to the previously saved value, otherwise we can
1962 to get the proper value. Though harder to understand than the
1963 recursive version, this non-recursive routine is far less likely
1964 to blow the C stack. It will also run more efficiently since
1965 a lot of procedure call overhead has been removed. Most lists
1966 are small though (in the hundreds of items or less) and the
1967 recursive version should be sufficient for them.