2 .\" Must use -- eqn -- with this one
4 .\" @(#)xdr.nts.ms 2.2 88/08/05 4.0 RPCSRC
11 .if \\n%=1 .tl ''- % -''
14 .\" prevent excess underlining in nroff
16 .OH 'External Data Representation: Sun Technical Notes''Page %'
17 .EH 'Page %''External Data Representation: Sun Technical Notes'
20 \&External Data Representation: Sun Technical Notes
21 .IX XDR "Sun technical notes"
23 This chapter contains technical notes on Sun's implementation of the
24 External Data Representation (XDR) standard, a set of library routines
25 that allow a C programmer to describe arbitrary data structures in a
26 machinex-independent fashion.
27 For a formal specification of the XDR
29 .I "External Data Representation Standard: Protocol Specification".
30 XDR is the backbone of Sun's Remote Procedure Call package, in the
31 sense that data for remote procedure calls is transmitted using the
32 standard. XDR library routines should be used to transmit data
33 that is accessed (read or written) by more than one type of machine.\**
35 .IX XDR "system routines"
36 For a compete specification of the system External Data Representation
42 This chapter contains a short tutorial overview of the XDR library
43 routines, a guide to accessing currently available XDR streams, and
44 information on defining new streams and data types. XDR was designed
45 to work across different languages, operating systems, and machine
46 architectures. Most users (particularly RPC users) will only need
47 the information in the
49 .I "Floating Point Filters",
51 .I "Enumeration Filters"
53 Programmers wishing to implement RPC and XDR on new machines
54 will be interested in the rest of the chapter, as well as the
55 .I "External Data Representaiton Standard: Protocol Specification",
56 which will be their primary reference.
61 can be used to write XDR routines even in cases where no RPC calls are
65 C programs that want to use XDR routines
68 which contains all the necessary interfaces to the XDR system.
71 contains all the XDR routines,
74 example% \fBcc\0\fIprogram\fP.c\fI
81 Consider the following two programs,
88 main() /* \fIwriter.c\fP */
92 for (i = 0; i < 8; i++) {
93 if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) {
94 fprintf(stderr, "failed!\en");
108 main() /* \fIreader.c\fP */
112 for (j = 0; j < 8; j++) {
113 if (fread((char *)&i, sizeof (i), 1, stdin) != 1) {
114 fprintf(stderr, "failed!\en");
123 The two programs appear to be portable, because (a) they pass
125 checking, and (b) they exhibit the same behavior when executed
126 on two different hardware architectures, a Sun and a VAX.
128 Piping the output of the
132 program gives identical results on a Sun or a VAX.
135 sun% \fBwriter | reader\fP
140 vax% \fBwriter | reader\fP
144 With the advent of local area networks and 4.2BSD came the concept
145 of \*Qnetwork pipes\*U \(em a process produces data on one machine,
146 and a second process consumes data on another machine.
147 A network pipe can be constructed with
151 Here are the results if the first produces data on a Sun,
152 and the second consumes data on a VAX.
155 sun% \fBwriter | rsh vax reader\fP
156 0 16777216 33554432 50331648 67108864 83886080 100663296
160 Identical results can be obtained by executing
164 on the Sun. These results occur because the byte ordering
165 of long integers differs between the VAX and the Sun,
166 even though word size is the same.
167 Note that $16777216$ is $2 sup 24$ \(em
168 when four bytes are reversed, the 1 winds up in the 24th bit.
170 Whenever data is shared by two or more machine types, there is
171 a need for portable data. Programs can be made data-portable by
176 calls with calls to an XDR library routine
178 a filter that knows the standard representation
179 of a long integer in its external form.
180 Here are the revised versions of
186 #include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
188 main() /* \fIwriter.c\fP */
193 xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
194 for (i = 0; i < 8; i++) {
195 if (!xdr_long(&xdrs, &i)) {
196 fprintf(stderr, "failed!\en");
209 #include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
211 main() /* \fIreader.c\fP */
216 xdrstdio_create(&xdrs, stdin, XDR_DECODE);
217 for (j = 0; j < 8; j++) {
218 if (!xdr_long(&xdrs, &i)) {
219 fprintf(stderr, "failed!\en");
228 The new programs were executed on a Sun,
229 on a VAX, and from a Sun to a VAX;
230 the results are shown below.
233 sun% \fBwriter | reader\fP
237 vax% \fBwriter | reader\fP
241 sun% \fBwriter | rsh vax reader\fP
248 .IX XDR "portable data"
249 Integers are just the tip of the portable-data iceberg. Arbitrary
250 data structures present portability problems, particularly with
251 respect to alignment and pointers. Alignment on word boundaries
252 may cause the size of a structure to vary from machine to machine.
253 And pointers, which are very convenient to use, have no meaning
254 outside the machine where they are defined.
257 \&A Canonical Standard
258 .IX XDR "canonical standard"
260 XDR's approach to standardizing data representations is
262 That is, XDR defines a single byte order (Big Endian), a single
263 floating-point representation (IEEE), and so on. Any program running on
264 any machine can use XDR to create portable data by translating its
265 local representation to the XDR standard representations; similarly, any
266 program running on any machine can read portable data by translating the
267 XDR standard representaions to its local equivalents. The single standard
268 completely decouples programs that create or send portable data from those
269 that use or receive portable data. The advent of a new machine or a new
270 language has no effect upon the community of existing portable data creators
271 and users. A new machine joins this community by being \*Qtaught\*U how to
272 convert the standard representations and its local representations; the
273 local representations of other machines are irrelevant. Conversely, to
274 existing programs running on other machines, the local representations of
275 the new machine are also irrelevant; such programs can immediately read
276 portable data produced by the new machine because such data conforms to the
277 canonical standards that they already understand.
279 There are strong precedents for XDR's canonical approach. For example,
280 TCP/IP, UDP/IP, XNS, Ethernet, and, indeed, all protocols below layer five
281 of the ISO model, are canonical protocols. The advantage of any canonical
282 approach is simplicity; in the case of XDR, a single set of conversion
283 routines is written once and is never touched again. The canonical approach
284 has a disadvantage, but it is unimportant in real-world data transfer
285 applications. Suppose two Little-Endian machines are transferring integers
286 according to the XDR standard. The sending machine converts the integers
287 from Little-Endian byte order to XDR (Big-Endian) byte order; the receiving
288 machine performs the reverse conversion. Because both machines observe the
289 same byte order, their conversions are unnecessary. The point, however, is
290 not necessity, but cost as compared to the alternative.
292 The time spent converting to and from a canonical representation is
293 insignificant, especially in networking applications. Most of the time
294 required to prepare a data structure for transfer is not spent in conversion
295 but in traversing the elements of the data structure. To transmit a tree,
296 for example, each leaf must be visited and each element in a leaf record must
297 be copied to a buffer and aligned there; storage for the leaf may have to be
298 deallocated as well. Similarly, to receive a tree, storage must be
299 allocated for each leaf, data must be moved from the buffer to the leaf and
300 properly aligned, and pointers must be constructed to link the leaves
301 together. Every machine pays the cost of traversing and copying data
302 structures whether or not conversion is required. In networking
303 applications, communications overhead\(emthe time required to move the data
304 down through the sender's protocol layers, across the network and up through
305 the receiver's protocol layers\(emdwarfs conversion overhead.
310 The XDR library not only solves data portability problems, it also
311 allows you to write and read arbitrary C constructs in a consistent,
312 specified, well-documented manner. Thus, it can make sense to use the
313 library even when the data is not shared among machines on a network.
315 The XDR library has filter routines for
316 strings (null-terminated arrays of bytes),
317 structures, unions, and arrays, to name a few.
318 Using more primitive routines,
319 you can write your own specific XDR routines
320 to describe arbitrary data structures,
321 including elements of arrays, arms of unions,
322 or objects pointed at from other structures.
323 The structures themselves may contain arrays of arbitrary elements,
324 or pointers to other structures.
326 Let's examine the two programs more closely.
327 There is a family of XDR stream creation routines
328 in which each member treats the stream of bits differently.
329 In our example, data is manipulated using standard I/O routines,
331 .I xdrstdio_create ().
332 .IX xdrstdio_create() "" "\fIxdrstdio_create()\fP"
333 The parameters to XDR stream creation routines
334 vary according to their function.
337 takes a pointer to an XDR structure that it initializes,
340 that the input or output is performed on, and the operation.
343 for serializing in the
347 for deserializing in the
351 Note: RPC users never need to create XDR streams;
352 the RPC system itself creates these streams,
353 which are then passed to the users.
357 .IX xdr_long() "" "\fIxdr_long()\fP"
358 primitive is characteristic of most XDR library
359 primitives and all client XDR routines.
360 First, the routine returns
365 Second, for each data type,
367 there is an associated XDR routine of the form:
378 is long, and the corresponding XDR routine is
381 The client could also define an arbitrary structure
383 in which case the client would also supply the routine
385 describing each field by calling XDR routines
386 of the appropriate type.
387 In all cases the first parameter,
389 can be treated as an opaque handle,
390 and passed to the primitive routines.
392 XDR routines are direction independent;
393 that is, the same routines are called to serialize or deserialize data.
394 This feature is critical to software engineering of portable data.
395 The idea is to call the same routine for either operation \(em
396 this almost guarantees that serialized data can also be deserialized.
397 One routine is used by both producer and consumer of networked data.
398 This is implemented by always passing the address
399 of an object rather than the object itself \(em
400 only in the case of deserialization is the object modified.
401 This feature is not shown in our trivial example,
402 but its value becomes obvious when nontrivial data structures
403 are passed among machines.
404 If needed, the user can obtain the
405 direction of the XDR operation.
407 .I "XDR Operation Directions"
408 section below for details.
410 Let's look at a slightly more complicated example.
411 Assume that a person's gross assets and liabilities
412 are to be exchanged among processes.
413 Also assume that these values are important enough
414 to warrant their own data type:
423 The corresponding XDR routine describing this structure would be:
427 bool_t /* \fITRUE is success, FALSE is failure\fP */
428 xdr_gnumbers(xdrs, gp)
432 if (xdr_long(xdrs, &gp->g_assets) &&
433 xdr_long(xdrs, &gp->g_liabilities))
438 Note that the parameter
440 is never inspected or modified;
441 it is only passed on to the subcomponent routines.
442 It is imperative to inspect the return value of each XDR routine call,
443 and to give up immediately and return
445 if the subroutine fails.
447 This example also shows that the type
449 is declared as an integer whose only values are
453 (0). This document uses the following definitions:
462 Keeping these conventions in mind,
464 can be rewritten as follows:
468 xdr_gnumbers(xdrs, gp)
472 return(xdr_long(xdrs, &gp->g_assets) &&
473 xdr_long(xdrs, &gp->g_liabilities));
476 This document uses both coding styles.
478 \&XDR Library Primitives
479 .IX "library primitives for XDR"
480 .IX XDR "library primitives"
482 This section gives a synopsis of each XDR primitive.
483 It starts with basic data types and moves on to constructed data types.
484 Finally, XDR utilities are discussed.
485 The interface to these primitives
486 and utilities is defined in the include file
488 automatically included by
492 .IX "XDR library" "number filters"
494 The XDR library provides primitives to translate between numbers
495 and their corresponding external representations.
496 Primitives cover the set of numbers in:
499 [signed, unsigned] * [short, int, long]
502 Specifically, the eight primitives are:
505 bool_t xdr_char(xdrs, cp)
509 bool_t xdr_u_char(xdrs, ucp)
513 bool_t xdr_int(xdrs, ip)
517 bool_t xdr_u_int(xdrs, up)
521 bool_t xdr_long(xdrs, lip)
525 bool_t xdr_u_long(xdrs, lup)
529 bool_t xdr_short(xdrs, sip)
533 bool_t xdr_u_short(xdrs, sup)
539 is an XDR stream handle.
540 The second parameter is the address of the number
541 that provides data to the stream or receives data from it.
544 if they complete successfully, and
548 \&Floating Point Filters
549 .IX "XDR library" "floating point filters"
551 The XDR library also provides primitive routines
552 for C's floating point types:
555 bool_t xdr_float(xdrs, fp)
559 bool_t xdr_double(xdrs, dp)
565 is an XDR stream handle.
566 The second parameter is the address
567 of the floating point number that provides data to the stream
568 or receives data from it.
571 if they complete successfully, and
575 Note: Since the numbers are represented in IEEE floating point,
576 routines may fail when decoding a valid IEEE representation
577 into a machine-specific representation, or vice-versa.
579 \&Enumeration Filters
580 .IX "XDR library" "enumeration filters"
582 The XDR library provides a primitive for generic enumerations.
583 The primitive assumes that a C
585 has the same representation inside the machine as a C integer.
586 The boolean type is an important instance of the
588 The external representation of a boolean is always
601 bool_t xdr_enum(xdrs, ep)
605 bool_t xdr_bool(xdrs, bp)
609 The second parameters
613 are addresses of the associated type that provides data to, or
614 receives data from, the stream
618 .IX "XDR library" "no data"
620 Occasionally, an XDR routine must be supplied to the RPC system,
621 even when no data is passed or required.
622 The library provides such a routine:
625 bool_t xdr_void(); /* \fIalways returns TRUE\fP */
628 \&Constructed Data Type Filters
629 .IX "XDR library" "constructed data type filters"
631 Constructed or compound data type primitives
632 require more parameters and perform more complicated functions
633 then the primitives discussed above.
634 This section includes primitives for
635 strings, arrays, unions, and pointers to structures.
637 Constructed data type primitives may use memory management.
638 In many cases, memory is allocated when deserializing data with
640 Therefore, the XDR package must provide means to deallocate memory.
641 This is done by an XDR operation,
643 To review, the three XDR directional operations are
650 .IX "XDR library" "strings"
652 In C, a string is defined as a sequence of bytes
653 terminated by a null byte,
654 which is not considered when calculating string length.
655 However, when a string is passed or manipulated,
656 a pointer to it is employed.
657 Therefore, the XDR library defines a string to be a
659 and not a sequence of characters.
660 The external representation of a string is drastically different
661 from its internal representation.
662 Externally, strings are represented as
663 sequences of ASCII characters,
664 while internally, they are represented with character pointers.
665 Conversion between the two representations
666 is accomplished with the routine
668 .IX xdr_string() "" \fIxdr_string()\fP
671 bool_t xdr_string(xdrs, sp, maxlength)
678 is the XDR stream handle.
681 is a pointer to a string (type
685 specifies the maximum number of bytes allowed during encoding or decoding.
686 its value is usually specified by a protocol. For example, a protocol
687 specification may say that a file name may be no longer than 255 characters.
691 if the number of characters exceeds
699 small. If it is too big you can blow the heap, since
707 .IX xdr_string() "" \fIxdr_string()\fP
708 is similar to the behavior of other routines
709 discussed in this section. The direction
711 is easiest to understand. The parameter
713 points to a string of a certain length;
714 if the string does not exceed
716 the bytes are serialized.
718 The effect of deserializing a string is subtle.
719 First the length of the incoming string is determined;
724 is dereferenced; if the value is
726 then a string of the appropriate length is allocated and
728 is set to this string.
729 If the original value of
731 is non-null, then the XDR package assumes
732 that a target area has been allocated,
733 which can hold strings no longer than
735 In either case, the string is decoded into the target area.
736 The routine then appends a null character to the string.
740 operation, the string is obtained by dereferencing
755 .IX "XDR library" "byte arrays"
757 Often variable-length arrays of bytes are preferable to strings.
758 Byte arrays differ from strings in the following three ways:
759 1) the length of the array (the byte count) is explicitly
760 located in an unsigned integer,
761 2) the byte sequence is not terminated by a null character, and
762 3) the external representation of the bytes is the same as their
763 internal representation.
766 .IX xdr_bytes() "" \fIxdr_bytes()\fP
767 converts between the internal and external
768 representations of byte arrays:
771 bool_t xdr_bytes(xdrs, bpp, lp, maxlength)
777 The usage of the first, second and fourth parameters
778 are identical to the first, second and third parameters of
781 The length of the byte area is obtained by dereferencing
785 is set to the byte length when deserializing.
788 .IX "XDR library" "arrays"
790 The XDR library package provides a primitive
791 for handling arrays of arbitrary elements.
794 routine treats a subset of generic arrays,
795 in which the size of array elements is known to be 1,
796 and the external description of each element is built-in.
797 The generic array primitive,
799 .IX xdr_array() "" \fIxdr_array()\fP
800 requires parameters identical to those of
803 the size of array elements,
804 and an XDR routine to handle each of the elements.
805 This routine is called to encode or decode
806 each element of the array.
810 xdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element)
816 bool_t (*xdr_element)();
820 is the address of the pointer to the array.
825 when the array is being deserialized,
826 XDR allocates an array of the appropriate size and sets
829 The element count of the array is obtained from
831 when the array is serialized;
833 is set to the array length when the array is deserialized.
836 is the maximum number of elements that the array is allowed to have;
838 is the byte size of each element of the array
841 can be used to obtain this value).
844 .IX xdr_element() "" \fIxdr_element()\fP
845 routine is called to serialize, deserialize, or free
846 each element of the array.
849 Before defining more constructed data types, it is appropriate to
850 present three examples.
854 A user on a networked machine can be identified by
855 (a) the machine name, such as
859 man page; (b) the user's UID: see the
861 man page; and (c) the group numbers to which the user belongs:
864 man page. A structure with this information and its associated
865 XDR routine could be coded like this:
870 char *nu_machinename;
875 #define NLEN 255 /* \fImachine names < 256 chars\fP */
876 #define NGRPS 20 /* \fIuser can't be in > 20 groups\fP */
879 xdr_netuser(xdrs, nup)
883 return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
884 xdr_int(xdrs, &nup->nu_uid) &&
885 xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen,
886 NGRPS, sizeof (int), xdr_int));
892 A party of network users could be implemented
896 The declaration and its associated XDR routines
903 struct netuser *p_nusers;
905 #define PLEN 500 /* \fImax number of users in a party\fP */
912 return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
913 sizeof (struct netuser), xdr_netuser));
919 The well-known parameters to
924 can be combined into a structure.
925 An array of these structures can make up a history of commands.
926 The declarations and XDR routines might look like:
934 #define ALEN 1000 /* \fIargs cannot be > 1000 chars\fP */
935 #define NARGC 100 /* \fIcommands cannot have > 100 args\fP */
941 #define NCMDS 75 /* \fIhistory is no more than 75 commands\fP */
944 xdr_wrap_string(xdrs, sp)
948 return(xdr_string(xdrs, sp, ALEN));
959 return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
960 sizeof (char *), xdr_wrap_string));
967 xdr_history(xdrs, hp)
971 return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
972 sizeof (struct cmd), xdr_cmd));
975 The most confusing part of this example is that the routine
977 is needed to package the
979 routine, because the implementation of
981 only passes two parameters to the array element description routine;
983 supplies the third parameter to
986 By now the recursive nature of the XDR library should be obvious.
987 Let's continue with more constructed data types.
990 .IX "XDR library" "opaque data"
992 In some protocols, handles are passed from a server to client.
993 The client passes the handle back to the server at some later time.
994 Handles are never inspected by clients;
995 they are obtained and submitted.
996 That is to say, handles are opaque.
999 .IX xdr_opaque() "" \fIxdr_opaque()\fP
1000 primitive is used for describing fixed sized, opaque bytes.
1003 bool_t xdr_opaque(xdrs, p, len)
1010 is the location of the bytes;
1012 is the number of bytes in the opaque object.
1013 By definition, the actual data
1014 contained in the opaque object are not machine portable.
1016 \&Fixed Sized Arrays
1017 .IX "XDR library" "fixed sized arrays"
1019 The XDR library provides a primitive,
1021 for fixed-length arrays.
1025 #define NLEN 255 /* \fImachine names must be < 256 chars\fP */
1026 #define NGRPS 20 /* \fIuser belongs to exactly 20 groups\fP */
1029 char *nu_machinename;
1035 xdr_netuser(xdrs, nup)
1037 struct netuser *nup;
1041 if (!xdr_string(xdrs, &nup->nu_machinename, NLEN))
1043 if (!xdr_int(xdrs, &nup->nu_uid))
1045 if (!xdr_vector(xdrs, nup->nu_gids, NGRPS, sizeof(int),
1053 \&Discriminated Unions
1054 .IX "XDR library" "discriminated unions"
1056 The XDR library supports discriminated unions.
1057 A discriminated union is a C union and an
1059 value that selects an \*Qarm\*U of the union.
1062 struct xdr_discrim {
1067 bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm)
1071 struct xdr_discrim *arms;
1072 bool_t (*defaultarm)(); /* \fImay equal NULL\fP */
1074 First the routine translates the discriminant of the union located at
1076 The discriminant is always an
1078 Next the union located at
1083 is a pointer to an array of
1086 Each structure contains an ordered pair of
1088 If the union's discriminant is equal to the associated
1092 is called to translate the union.
1095 structure array is denoted by a routine of value
1097 (0). If the discriminant is not found in the
1101 procedure is called if it is non-null;
1102 otherwise the routine returns
1106 Suppose the type of a union may be integer,
1107 character pointer (a string), or a
1110 Also, assume the union and its current type
1111 are declared in a structure.
1116 enum utype { INTEGER=1, STRING=2, GNUMBERS=3 };
1119 enum utype utype; /* \fIthe union's discriminant\fP */
1127 The following constructs and XDR procedure (de)serialize
1128 the discriminated union:
1132 struct xdr_discrim u_tag_arms[4] = {
1133 { INTEGER, xdr_int },
1134 { GNUMBERS, xdr_gnumbers }
1135 { STRING, xdr_wrap_string },
1136 { __dontcare__, NULL }
1137 /* \fIalways terminate arms with a NULL xdr_proc\fP */
1141 xdr_u_tag(xdrs, utp)
1145 return(xdr_union(xdrs, &utp->utype, &utp->uval,
1151 was presented above in
1152 .I "The XDR Library"
1154 .I xdr_wrap_string()
1155 was presented in example C.
1160 (the last parameter) is
1162 in this example. Therefore the value of the union's discriminant
1163 may legally take on only values listed in the
1165 array. This example also demonstrates that
1166 the elements of the arm's array do not need to be sorted.
1168 It is worth pointing out that the values of the discriminant
1169 may be sparse, though in this example they are not.
1171 practice to assign explicitly integer values to each element of the
1172 discriminant's type.
1173 This practice both documents the external
1174 representation of the discriminant and guarantees that different
1175 C compilers emit identical discriminant values.
1179 using the other primitives in this section.
1182 .IX "XDR library" "pointers"
1184 In C it is often convenient to put pointers
1185 to another structure within a structure.
1188 .IX xdr_reference() "" \fIxdr_reference()\fP
1189 primitive makes it easy to serialize, deserialize, and free
1190 these referenced structures.
1193 bool_t xdr_reference(xdrs, pp, size, proc)
1203 the pointer to the structure;
1206 is the size in bytes of the structure (use the C function
1208 to obtain this value); and
1210 is the XDR routine that describes the structure.
1211 When decoding data, storage is allocated if
1216 There is no need for a primitive
1218 to describe structures within structures,
1219 because pointers are always sufficient.
1229 are NOT interchangeable external representations of data.
1232 Suppose there is a structure containing a person's name
1235 structure containing the person's gross assets and liabilities.
1241 struct gnumbers *gnp;
1244 The corresponding XDR routine for this structure is:
1252 if (xdr_string(xdrs, &pp->name, NLEN) &&
1253 xdr_reference(xdrs, &pp->gnp,
1254 sizeof(struct gnumbers), xdr_gnumbers))
1259 .IX "pointer semantics and XDR"
1260 .I "Pointer Semantics and XDR"
1262 In many applications, C programmers attach double meaning to
1263 the values of a pointer. Typically the value
1265 (or zero) means data is not needed,
1266 yet some application-specific interpretation applies.
1267 In essence, the C programmer is encoding
1268 a discriminated union efficiently
1269 by overloading the interpretation of the value of a pointer.
1270 For instance, in example E a
1275 the person's assets and liabilities are unknown.
1276 That is, the pointer value encodes two things:
1277 whether or not the data is known;
1278 and if it is known, where it is located in memory.
1279 Linked lists are an extreme example of the use
1280 of application-specific pointer interpretation.
1284 .IX xdr_reference() "" \fIxdr_reference()\fP
1285 cannot and does not attach any special
1286 meaning to a null-value pointer during serialization.
1287 That is, passing an address of a pointer whose value is
1291 when serialing data will most likely cause a memory fault and, on the UNIX
1292 system, a core dump.
1297 pointers. For more information about its use, see
1303 After reading the section on
1305 return here and extend example E so that
1306 it can correctly deal with
1316 primitives, implement a generic pointer handling primitive
1317 that implicitly deals with
1319 pointers. That is, implement
1322 \&Non-filter Primitives
1323 .IX "XDR" "non-filter primitives"
1325 XDR streams can be manipulated with
1326 the primitives discussed in this section.
1329 u_int xdr_getpos(xdrs)
1332 bool_t xdr_setpos(xdrs, pos)
1341 .IX xdr_getpos() "" \fIxdr_getpos()\fP
1342 returns an unsigned integer
1343 that describes the current position in the data stream.
1344 Warning: In some XDR streams, the returned value of
1347 the routine returns a \-1 in this case
1348 (though \-1 should be a legitimate value).
1352 .IX xdr_setpos() "" \fIxdr_setpos()\fP
1353 sets a stream position to
1355 Warning: In some XDR streams, setting a position is impossible;
1360 This routine will also fail if the requested position is out-of-bounds.
1361 The definition of bounds varies from stream to stream.
1365 .IX xdr_destroy() "" \fIxdr_destroy()\fP
1366 primitive destroys the XDR stream.
1368 after calling this routine is undefined.
1370 \&XDR Operation Directions
1371 .IX XDR "operation directions"
1372 .IX "direction of XDR operations"
1374 At times you may wish to optimize XDR routines by taking
1375 advantage of the direction of the operation \(em
1382 always contains the direction of the XDR operation.
1383 Programmers are not encouraged to take advantage of this information.
1384 Therefore, no example is presented here. However, an example in the
1386 topic below, demonstrates the usefulness of the
1391 .IX "XDR" "stream access"
1393 An XDR stream is obtained by calling the appropriate creation routine.
1394 These creation routines take arguments that are tailored to the
1395 specific properties of the stream.
1397 Streams currently exist for (de)serialization of data to or from
1400 streams, TCP/IP connections and UNIX files, and memory.
1402 \&Standard I/O Streams
1403 .IX "XDR" "standard I/O streams"
1405 XDR streams can be interfaced to standard I/O using the
1406 .I xdrstdio_create()
1407 .IX xdrstdio_create() "" \fIxdrstdio_create()\fP
1412 #include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
1415 xdrstdio_create(xdrs, fp, x_op)
1421 .I xdrstdio_create()
1422 initializes an XDR stream pointed to by
1424 The XDR stream interfaces to the standard I/O library.
1427 is an open file, and
1429 is an XDR direction.
1432 .IX "XDR" "memory streams"
1434 Memory streams allow the streaming of data into or out of
1435 a specified area of memory:
1438 #include <rpc/rpc.h>
1441 xdrmem_create(xdrs, addr, len, x_op)
1449 .IX xdrmem_create() "" \fIxdrmem_create()\fP
1450 initializes an XDR stream in local memory.
1451 The memory is pointed to by parameter
1455 is the length in bytes of the memory.
1460 are identical to the corresponding parameters of
1461 .I xdrstdio_create ().
1462 Currently, the UDP/IP implementation of RPC uses
1463 .I xdrmem_create ().
1464 Complete call or result messages are built in memory before calling the
1468 \&Record (TCP/IP) Streams
1469 .IX "XDR" "record (TCP/IP) streams"
1471 A record stream is an XDR stream built on top of
1472 a record marking standard that is built on top of the
1473 UNIX file or 4.2 BSD connection interface.
1476 #include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
1479 sendsize, recvsize, iohandle, readproc, writeproc)
1481 u_int sendsize, recvsize;
1483 int (*readproc)(), (*writeproc)();
1487 provides an XDR stream interface that allows for a bidirectional,
1488 arbitrarily long sequence of records.
1489 The contents of the records are meant to be data in XDR form.
1490 The stream's primary use is for interfacing RPC to TCP connections.
1491 However, it can be used to stream data into or out of normal
1496 is similar to the corresponding parameter described above.
1497 The stream does its own data buffering similar to that of standard I/O.
1502 determine the size in bytes of the output and input buffers, respectively;
1503 if their values are zero (0), then predetermined defaults are used.
1504 When a buffer needs to be filled or flushed, the routine
1508 is called, respectively.
1509 The usage and behavior of these
1510 routines are similar to the UNIX system calls
1515 the first parameter to each of these routines is the opaque parameter
1517 The other two parameters
1522 (byte count) are identical to the system routines.
1529 then it has the following form:
1534 * returns the actual number of bytes transferred.
1539 xxx(iohandle, buf, len)
1544 The XDR stream provides means for delimiting records in the byte stream.
1545 The implementation details of delimiting records in a stream are
1547 .I "Advanced Topics"
1549 The primitives that are specific to record streams are as follows:
1553 xdrrec_endofrecord(xdrs, flushnow)
1558 xdrrec_skiprecord(xdrs)
1566 .I xdrrec_endofrecord()
1567 .IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fP
1568 causes the current outgoing data to be marked as a record.
1575 will be called; otherwise,
1577 will be called when the output buffer has been filled.
1580 .I xdrrec_skiprecord()
1581 .IX xdrrec_skiprecord() "" \fIxdrrec_skiprecord()\fP
1582 causes an input stream's position to be moved past
1583 the current record boundary and onto the
1584 beginning of the next record in the stream.
1586 If there is no more data in the stream's input buffer,
1589 .IX xdrrec_eof() "" \fIxdrrec_eof()\fP
1592 That is not to say that there is no more data
1593 in the underlying file descriptor.
1595 \&XDR Stream Implementation
1596 .IX "XDR" "stream implementation"
1597 .IX "stream implementation in XDR"
1599 This section provides the abstract data types needed
1600 to implement new instances of XDR streams.
1605 The following structure defines the interface to an XDR stream:
1609 enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
1612 enum xdr_op x_op; /* \fIoperation; fast added param\fP */
1614 bool_t (*x_getlong)(); /* \fIget long from stream\fP */
1615 bool_t (*x_putlong)(); /* \fIput long to stream\fP */
1616 bool_t (*x_getbytes)(); /* \fIget bytes from stream\fP */
1617 bool_t (*x_putbytes)(); /* \fIput bytes to stream\fP */
1618 u_int (*x_getpostn)(); /* \fIreturn stream offset\fP */
1619 bool_t (*x_setpostn)(); /* \fIreposition offset\fP */
1620 caddr_t (*x_inline)(); /* \fIptr to buffered data\fP */
1621 VOID (*x_destroy)(); /* \fIfree private area\fP */
1623 caddr_t x_public; /* \fIusers' data\fP */
1624 caddr_t x_private; /* \fIpointer to private data\fP */
1625 caddr_t x_base; /* \fIprivate for position info\fP */
1626 int x_handy; /* \fIextra private word\fP */
1631 field is the current operation being performed on the stream.
1632 This field is important to the XDR primitives,
1633 but should not affect a stream's implementation.
1634 That is, a stream's implementation should not depend
1641 are private to the particular
1642 stream's implementation.
1645 is for the XDR client and should never be used by
1646 the XDR stream implementations or the XDR primitives.
1651 are macros for accessing operations. The operation
1653 takes two parameters:
1654 an XDR *, and an unsigned integer, which is a byte count.
1655 The routine returns a pointer to a piece of
1656 the stream's internal buffer.
1657 The caller can then use the buffer segment for any purpose.
1658 From the stream's point of view, the bytes in the
1659 buffer segment have been consumed or put.
1660 The routine may return
1662 if it cannot return a buffer segment of the requested size.
1665 routine is for cycle squeezers.
1666 Use of the resulting buffer is not data-portable.
1667 Users are encouraged not to use this feature.)
1673 blindly get and put sequences of bytes
1674 from or to the underlying stream;
1677 if they are successful, and
1679 otherwise. The routines have identical parameters (replace
1684 xxxbytes(xdrs, buf, bytecount)
1694 long numbers from and to the data stream.
1695 It is the responsibility of these routines
1696 to translate the numbers between the machine representation
1697 and the (standard) external representation.
1702 can be helpful in accomplishing this.
1703 The higher-level XDR implementation assumes that
1704 signed and unsigned long integers contain the same number of bits,
1705 and that nonnegative integers
1706 have the same bit representations as unsigned integers.
1709 if they succeed, and
1711 otherwise. They have identical parameters:
1719 Implementors of new XDR streams must make an XDR structure
1720 (with new operation routines) available to clients,
1721 using some kind of create routine.
1724 .IX XDR "advanced topics"
1726 This section describes techniques for passing data structures that
1727 are not covered in the preceding sections. Such structures include
1728 linked lists (of arbitrary lengths). Unlike the simpler examples
1729 covered in the earlier sections, the following examples are written
1730 using both the XDR C library routines and the XDR data description
1733 .I "External Data Representation Standard: Protocol Specification"
1735 language in complete detail.
1738 .IX XDR "linked lists"
1740 The last example in the
1742 topic earlier in this chapter
1743 presented a C data structure and its associated XDR
1744 routines for an individual's gross assets and liabilities.
1745 The example is duplicated below:
1755 xdr_gnumbers(xdrs, gp)
1757 struct gnumbers *gp;
1759 if (xdr_long(xdrs, &(gp->g_assets)))
1760 return(xdr_long(xdrs, &(gp->g_liabilities)));
1765 Now assume that we wish to implement a linked list of such information.
1766 A data structure could be constructed as follows:
1770 struct gnumbers_node {
1771 struct gnumbers gn_numbers;
1772 struct gnumbers_node *gn_next;
1775 typedef struct gnumbers_node *gnumbers_list;
1778 The head of the linked list can be thought of as the data object;
1779 that is, the head is not merely a convenient shorthand for a
1780 structure. Similarly the
1782 field is used to indicate whether or not the object has terminated.
1783 Unfortunately, if the object continues, the
1785 field is also the address of where it continues. The link addresses
1786 carry no useful information when the object is serialized.
1788 The XDR data description of this linked list is described by the
1789 recursive declaration of
1799 struct gnumbers_node {
1800 gnumbers gn_numbers;
1801 gnumbers_node *gn_next;
1805 In this description, the boolean indicates whether there is more data
1806 following it. If the boolean is
1808 then it is the last data field of the structure. If it is
1810 then it is followed by a gnumbers structure and (recursively) by a
1812 Note that the C declaration has no boolean explicitly declared in it
1815 field implicitly carries the information), while the XDR data
1816 description has no pointer explicitly declared in it.
1818 Hints for writing the XDR routines for a
1820 follow easily from the XDR description above. Note how the primitive
1822 is used to implement the XDR union above.
1827 xdr_gnumbers_node(xdrs, gn)
1831 return(xdr_gnumbers(xdrs, &gn->gn_numbers) &&
1832 xdr_gnumbers_list(xdrs, &gp->gn_next));
1836 xdr_gnumbers_list(xdrs, gnp)
1840 return(xdr_pointer(xdrs, gnp,
1841 sizeof(struct gnumbers_node),
1842 xdr_gnumbers_node));
1846 The unfortunate side effect of XDR'ing a list with these routines
1847 is that the C stack grows linearly with respect to the number of
1848 node in the list. This is due to the recursion. The following
1849 routine collapses the above two mutually recursive into a single,
1855 xdr_gnumbers_list(xdrs, gnp)
1860 gnumbers_list *nextp;
1863 more_data = (*gnp != NULL);
1864 if (!xdr_bool(xdrs, &more_data)) {
1870 if (xdrs->x_op == XDR_FREE) {
1871 nextp = &(*gnp)->gn_next;
1873 if (!xdr_reference(xdrs, gnp,
1874 sizeof(struct gnumbers_node), xdr_gnumbers)) {
1878 gnp = (xdrs->x_op == XDR_FREE) ?
1879 nextp : &(*gnp)->gn_next;
1886 The first task is to find out whether there is more data or not,
1887 so that this boolean information can be serialized. Notice that
1888 this statement is unnecessary in the
1890 case, since the value of more_data is not known until we
1891 deserialize it in the next statement.
1893 The next statement XDR's the more_data field of the XDR union.
1894 Then if there is truly no more data, we set this last pointer to
1896 to indicate the end of the list, and return
1898 because we are done. Note that setting the pointer to
1900 is only important in the
1902 case, since it is already
1910 Next, if the direction is
1914 is set to indicate the location of the next pointer in the list.
1915 We do this now because we need to dereference gnp to find the
1916 location of the next item in the list, and after the next
1917 statement the storage pointed to by
1919 will be freed up and no be longer valid. We can't do this for all
1920 directions though, because in the
1922 direction the value of
1924 won't be set until the next statement.
1926 Next, we XDR the data in the node using the primitive
1927 .I xdr_reference ().
1931 which we used before, but it does not
1932 send over the boolean indicating whether there is more data.
1933 We use it instead of
1935 because we have already XDR'd this information ourselves. Notice
1936 that the xdr routine passed is not the same type as an element
1937 in the list. The routine passed is
1939 for XDR'ing gnumbers, but each element in the list is actually of
1943 .I xdr_gnumbers_node()
1944 because it is recursive, and instead use
1946 which XDR's all of the non-recursive part. Note that this trick
1947 will work only if the
1949 field is the first item in each element, so that their addresses
1950 are identical when passed to
1951 .I xdr_reference ().
1955 to point to the next item in the list. If the direction is
1957 we set it to the previously saved value, otherwise we can
1960 to get the proper value. Though harder to understand than the
1961 recursive version, this non-recursive routine is far less likely
1962 to blow the C stack. It will also run more efficiently since
1963 a lot of procedure call overhead has been removed. Most lists
1964 are small though (in the hundreds of items or less) and the
1965 recursive version should be sufficient for them.