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 $
12 .if \\n%=1 .tl ''- % -''
15 .\" prevent excess underlining in nroff
17 .OH 'External Data Representation: Sun Technical Notes''Page %'
18 .EH 'Page %''External Data Representation: Sun Technical Notes'
21 \&External Data Representation: Sun Technical Notes
22 .IX XDR "Sun technical notes"
24 This chapter contains technical notes on Sun's implementation of the
25 External Data Representation (XDR) standard, a set of library routines
26 that allow a C programmer to describe arbitrary data structures in a
27 machinex-independent fashion.
28 For a formal specification of the XDR
30 .I "External Data Representation Standard: Protocol Specification".
31 XDR is the backbone of Sun's Remote Procedure Call package, in the
32 sense that data for remote procedure calls is transmitted using the
33 standard. XDR library routines should be used to transmit data
34 that is accessed (read or written) by more than one type of machine.\**
36 .IX XDR "system routines"
37 For a compete specification of the system External Data Representation
43 This chapter contains a short tutorial overview of the XDR library
44 routines, a guide to accessing currently available XDR streams, and
45 information on defining new streams and data types. XDR was designed
46 to work across different languages, operating systems, and machine
47 architectures. Most users (particularly RPC users) will only need
48 the information in the
50 .I "Floating Point Filters",
52 .I "Enumeration Filters"
54 Programmers wishing to implement RPC and XDR on new machines
55 will be interested in the rest of the chapter, as well as the
56 .I "External Data Representaiton Standard: Protocol Specification",
57 which will be their primary reference.
62 can be used to write XDR routines even in cases where no RPC calls are
66 C programs that want to use XDR routines
69 which contains all the necessary interfaces to the XDR system.
72 contains all the XDR routines,
75 example% \fBcc\0\fIprogram\fP.c\fI
82 Consider the following two programs,
89 main() /* \fIwriter.c\fP */
93 for (i = 0; i < 8; i++) {
94 if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) {
95 fprintf(stderr, "failed!\en");
109 main() /* \fIreader.c\fP */
113 for (j = 0; j < 8; j++) {
114 if (fread((char *)&i, sizeof (i), 1, stdin) != 1) {
115 fprintf(stderr, "failed!\en");
124 The two programs appear to be portable, because (a) they pass
126 checking, and (b) they exhibit the same behavior when executed
127 on two different hardware architectures, a Sun and a VAX.
129 Piping the output of the
133 program gives identical results on a Sun or a VAX.
136 sun% \fBwriter | reader\fP
141 vax% \fBwriter | reader\fP
145 With the advent of local area networks and 4.2BSD came the concept
146 of \*Qnetwork pipes\*U \(em a process produces data on one machine,
147 and a second process consumes data on another machine.
148 A network pipe can be constructed with
152 Here are the results if the first produces data on a Sun,
153 and the second consumes data on a VAX.
156 sun% \fBwriter | rsh vax reader\fP
157 0 16777216 33554432 50331648 67108864 83886080 100663296
161 Identical results can be obtained by executing
165 on the Sun. These results occur because the byte ordering
166 of long integers differs between the VAX and the Sun,
167 even though word size is the same.
168 Note that $16777216$ is $2 sup 24$ \(em
169 when four bytes are reversed, the 1 winds up in the 24th bit.
171 Whenever data is shared by two or more machine types, there is
172 a need for portable data. Programs can be made data-portable by
177 calls with calls to an XDR library routine
179 a filter that knows the standard representation
180 of a long integer in its external form.
181 Here are the revised versions of
187 #include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
189 main() /* \fIwriter.c\fP */
194 xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
195 for (i = 0; i < 8; i++) {
196 if (!xdr_long(&xdrs, &i)) {
197 fprintf(stderr, "failed!\en");
210 #include <rpc/rpc.h> /* \fIxdr is a sub-library of rpc\fP */
212 main() /* \fIreader.c\fP */
217 xdrstdio_create(&xdrs, stdin, XDR_DECODE);
218 for (j = 0; j < 8; j++) {
219 if (!xdr_long(&xdrs, &i)) {
220 fprintf(stderr, "failed!\en");
229 The new programs were executed on a Sun,
230 on a VAX, and from a Sun to a VAX;
231 the results are shown below.
234 sun% \fBwriter | reader\fP
238 vax% \fBwriter | reader\fP
242 sun% \fBwriter | rsh vax reader\fP
249 .IX XDR "portable data"
250 Integers are just the tip of the portable-data iceberg. Arbitrary
251 data structures present portability problems, particularly with
252 respect to alignment and pointers. Alignment on word boundaries
253 may cause the size of a structure to vary from machine to machine.
254 And pointers, which are very convenient to use, have no meaning
255 outside the machine where they are defined.
258 \&A Canonical Standard
259 .IX XDR "canonical standard"
261 XDR's approach to standardizing data representations is
263 That is, XDR defines a single byte order (Big Endian), a single
264 floating-point representation (IEEE), and so on. Any program running on
265 any machine can use XDR to create portable data by translating its
266 local representation to the XDR standard representations; similarly, any
267 program running on any machine can read portable data by translating the
268 XDR standard representaions to its local equivalents. The single standard
269 completely decouples programs that create or send portable data from those
270 that use or receive portable data. The advent of a new machine or a new
271 language has no effect upon the community of existing portable data creators
272 and users. A new machine joins this community by being \*Qtaught\*U how to
273 convert the standard representations and its local representations; the
274 local representations of other machines are irrelevant. Conversely, to
275 existing programs running on other machines, the local representations of
276 the new machine are also irrelevant; such programs can immediately read
277 portable data produced by the new machine because such data conforms to the
278 canonical standards that they already understand.
280 There are strong precedents for XDR's canonical approach. For example,
281 TCP/IP, UDP/IP, XNS, Ethernet, and, indeed, all protocols below layer five
282 of the ISO model, are canonical protocols. The advantage of any canonical
283 approach is simplicity; in the case of XDR, a single set of conversion
284 routines is written once and is never touched again. The canonical approach
285 has a disadvantage, but it is unimportant in real-world data transfer
286 applications. Suppose two Little-Endian machines are transferring integers
287 according to the XDR standard. The sending machine converts the integers
288 from Little-Endian byte order to XDR (Big-Endian) byte order; the receiving
289 machine performs the reverse conversion. Because both machines observe the
290 same byte order, their conversions are unnecessary. The point, however, is
291 not necessity, but cost as compared to the alternative.
293 The time spent converting to and from a canonical representation is
294 insignificant, especially in networking applications. Most of the time
295 required to prepare a data structure for transfer is not spent in conversion
296 but in traversing the elements of the data structure. To transmit a tree,
297 for example, each leaf must be visited and each element in a leaf record must
298 be copied to a buffer and aligned there; storage for the leaf may have to be
299 deallocated as well. Similarly, to receive a tree, storage must be
300 allocated for each leaf, data must be moved from the buffer to the leaf and
301 properly aligned, and pointers must be constructed to link the leaves
302 together. Every machine pays the cost of traversing and copying data
303 structures whether or not conversion is required. In networking
304 applications, communications overhead\(emthe time required to move the data
305 down through the sender's protocol layers, across the network and up through
306 the receiver's protocol layers\(emdwarfs conversion overhead.
311 The XDR library not only solves data portability problems, it also
312 allows you to write and read arbitrary C constructs in a consistent,
313 specified, well-documented manner. Thus, it can make sense to use the
314 library even when the data is not shared among machines on a network.
316 The XDR library has filter routines for
317 strings (null-terminated arrays of bytes),
318 structures, unions, and arrays, to name a few.
319 Using more primitive routines,
320 you can write your own specific XDR routines
321 to describe arbitrary data structures,
322 including elements of arrays, arms of unions,
323 or objects pointed at from other structures.
324 The structures themselves may contain arrays of arbitrary elements,
325 or pointers to other structures.
327 Let's examine the two programs more closely.
328 There is a family of XDR stream creation routines
329 in which each member treats the stream of bits differently.
330 In our example, data is manipulated using standard I/O routines,
332 .I xdrstdio_create ().
333 .IX xdrstdio_create() "" "\fIxdrstdio_create()\fP"
334 The parameters to XDR stream creation routines
335 vary according to their function.
338 takes a pointer to an XDR structure that it initializes,
341 that the input or output is performed on, and the operation.
344 for serializing in the
348 for deserializing in the
352 Note: RPC users never need to create XDR streams;
353 the RPC system itself creates these streams,
354 which are then passed to the users.
358 .IX xdr_long() "" "\fIxdr_long()\fP"
359 primitive is characteristic of most XDR library
360 primitives and all client XDR routines.
361 First, the routine returns
366 Second, for each data type,
368 there is an associated XDR routine of the form:
379 is long, and the corresponding XDR routine is
382 The client could also define an arbitrary structure
384 in which case the client would also supply the routine
386 describing each field by calling XDR routines
387 of the appropriate type.
388 In all cases the first parameter,
390 can be treated as an opaque handle,
391 and passed to the primitive routines.
393 XDR routines are direction independent;
394 that is, the same routines are called to serialize or deserialize data.
395 This feature is critical to software engineering of portable data.
396 The idea is to call the same routine for either operation \(em
397 this almost guarantees that serialized data can also be deserialized.
398 One routine is used by both producer and consumer of networked data.
399 This is implemented by always passing the address
400 of an object rather than the object itself \(em
401 only in the case of deserialization is the object modified.
402 This feature is not shown in our trivial example,
403 but its value becomes obvious when nontrivial data structures
404 are passed among machines.
405 If needed, the user can obtain the
406 direction of the XDR operation.
408 .I "XDR Operation Directions"
409 section below for details.
411 Let's look at a slightly more complicated example.
412 Assume that a person's gross assets and liabilities
413 are to be exchanged among processes.
414 Also assume that these values are important enough
415 to warrant their own data type:
424 The corresponding XDR routine describing this structure would be:
428 bool_t /* \fITRUE is success, FALSE is failure\fP */
429 xdr_gnumbers(xdrs, gp)
433 if (xdr_long(xdrs, &gp->g_assets) &&
434 xdr_long(xdrs, &gp->g_liabilities))
439 Note that the parameter
441 is never inspected or modified;
442 it is only passed on to the subcomponent routines.
443 It is imperative to inspect the return value of each XDR routine call,
444 and to give up immediately and return
446 if the subroutine fails.
448 This example also shows that the type
450 is declared as an integer whose only values are
454 (0). This document uses the following definitions:
463 Keeping these conventions in mind,
465 can be rewritten as follows:
469 xdr_gnumbers(xdrs, gp)
473 return(xdr_long(xdrs, &gp->g_assets) &&
474 xdr_long(xdrs, &gp->g_liabilities));
477 This document uses both coding styles.
479 \&XDR Library Primitives
480 .IX "library primitives for XDR"
481 .IX XDR "library primitives"
483 This section gives a synopsis of each XDR primitive.
484 It starts with basic data types and moves on to constructed data types.
485 Finally, XDR utilities are discussed.
486 The interface to these primitives
487 and utilities is defined in the include file
489 automatically included by
493 .IX "XDR library" "number filters"
495 The XDR library provides primitives to translate between numbers
496 and their corresponding external representations.
497 Primitives cover the set of numbers in:
500 [signed, unsigned] * [short, int, long]
503 Specifically, the eight primitives are:
506 bool_t xdr_char(xdrs, cp)
510 bool_t xdr_u_char(xdrs, ucp)
514 bool_t xdr_int(xdrs, ip)
518 bool_t xdr_u_int(xdrs, up)
522 bool_t xdr_long(xdrs, lip)
526 bool_t xdr_u_long(xdrs, lup)
530 bool_t xdr_short(xdrs, sip)
534 bool_t xdr_u_short(xdrs, sup)
540 is an XDR stream handle.
541 The second parameter is the address of the number
542 that provides data to the stream or receives data from it.
545 if they complete successfully, and
549 \&Floating Point Filters
550 .IX "XDR library" "floating point filters"
552 The XDR library also provides primitive routines
553 for C's floating point types:
556 bool_t xdr_float(xdrs, fp)
560 bool_t xdr_double(xdrs, dp)
566 is an XDR stream handle.
567 The second parameter is the address
568 of the floating point number that provides data to the stream
569 or receives data from it.
572 if they complete successfully, and
576 Note: Since the numbers are represented in IEEE floating point,
577 routines may fail when decoding a valid IEEE representation
578 into a machine-specific representation, or vice-versa.
580 \&Enumeration Filters
581 .IX "XDR library" "enumeration filters"
583 The XDR library provides a primitive for generic enumerations.
584 The primitive assumes that a C
586 has the same representation inside the machine as a C integer.
587 The boolean type is an important instance of the
589 The external representation of a boolean is always
602 bool_t xdr_enum(xdrs, ep)
606 bool_t xdr_bool(xdrs, bp)
610 The second parameters
614 are addresses of the associated type that provides data to, or
615 receives data from, the stream
619 .IX "XDR library" "no data"
621 Occasionally, an XDR routine must be supplied to the RPC system,
622 even when no data is passed or required.
623 The library provides such a routine:
626 bool_t xdr_void(); /* \fIalways returns TRUE\fP */
629 \&Constructed Data Type Filters
630 .IX "XDR library" "constructed data type filters"
632 Constructed or compound data type primitives
633 require more parameters and perform more complicated functions
634 then the primitives discussed above.
635 This section includes primitives for
636 strings, arrays, unions, and pointers to structures.
638 Constructed data type primitives may use memory management.
639 In many cases, memory is allocated when deserializing data with
641 Therefore, the XDR package must provide means to deallocate memory.
642 This is done by an XDR operation,
644 To review, the three XDR directional operations are
651 .IX "XDR library" "strings"
653 In C, a string is defined as a sequence of bytes
654 terminated by a null byte,
655 which is not considered when calculating string length.
656 However, when a string is passed or manipulated,
657 a pointer to it is employed.
658 Therefore, the XDR library defines a string to be a
660 and not a sequence of characters.
661 The external representation of a string is drastically different
662 from its internal representation.
663 Externally, strings are represented as
664 sequences of ASCII characters,
665 while internally, they are represented with character pointers.
666 Conversion between the two representations
667 is accomplished with the routine
669 .IX xdr_string() "" \fIxdr_string()\fP
672 bool_t xdr_string(xdrs, sp, maxlength)
679 is the XDR stream handle.
682 is a pointer to a string (type
686 specifies the maximum number of bytes allowed during encoding or decoding.
687 its value is usually specified by a protocol. For example, a protocol
688 specification may say that a file name may be no longer than 255 characters.
692 if the number of characters exceeds
700 small. If it is too big you can blow the heap, since
708 .IX xdr_string() "" \fIxdr_string()\fP
709 is similar to the behavior of other routines
710 discussed in this section. The direction
712 is easiest to understand. The parameter
714 points to a string of a certain length;
715 if the string does not exceed
717 the bytes are serialized.
719 The effect of deserializing a string is subtle.
720 First the length of the incoming string is determined;
725 is dereferenced; if the the value is
727 then a string of the appropriate length is allocated and
729 is set to this string.
730 If the original value of
732 is non-null, then the XDR package assumes
733 that a target area has been allocated,
734 which can hold strings no longer than
736 In either case, the string is decoded into the target area.
737 The routine then appends a null character to the string.
741 operation, the string is obtained by dereferencing
756 .IX "XDR library" "byte arrays"
758 Often variable-length arrays of bytes are preferable to strings.
759 Byte arrays differ from strings in the following three ways:
760 1) the length of the array (the byte count) is explicitly
761 located in an unsigned integer,
762 2) the byte sequence is not terminated by a null character, and
763 3) the external representation of the bytes is the same as their
764 internal representation.
767 .IX xdr_bytes() "" \fIxdr_bytes()\fP
768 converts between the internal and external
769 representations of byte arrays:
772 bool_t xdr_bytes(xdrs, bpp, lp, maxlength)
778 The usage of the first, second and fourth parameters
779 are identical to the first, second and third parameters of
782 The length of the byte area is obtained by dereferencing
786 is set to the byte length when deserializing.
789 .IX "XDR library" "arrays"
791 The XDR library package provides a primitive
792 for handling arrays of arbitrary elements.
795 routine treats a subset of generic arrays,
796 in which the size of array elements is known to be 1,
797 and the external description of each element is built-in.
798 The generic array primitive,
800 .IX xdr_array() "" \fIxdr_array()\fP
801 requires parameters identical to those of
804 the size of array elements,
805 and an XDR routine to handle each of the elements.
806 This routine is called to encode or decode
807 each element of the array.
811 xdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element)
817 bool_t (*xdr_element)();
821 is the address of the pointer to the array.
826 when the array is being deserialized,
827 XDR allocates an array of the appropriate size and sets
830 The element count of the array is obtained from
832 when the array is serialized;
834 is set to the array length when the array is deserialized.
837 is the maximum number of elements that the array is allowed to have;
839 is the byte size of each element of the array
842 can be used to obtain this value).
845 .IX xdr_element() "" \fIxdr_element()\fP
846 routine is called to serialize, deserialize, or free
847 each element of the array.
850 Before defining more constructed data types, it is appropriate to
851 present three examples.
855 A user on a networked machine can be identified by
856 (a) the machine name, such as
860 man page; (b) the user's UID: see the
862 man page; and (c) the group numbers to which the user belongs:
865 man page. A structure with this information and its associated
866 XDR routine could be coded like this:
871 char *nu_machinename;
876 #define NLEN 255 /* \fImachine names < 256 chars\fP */
877 #define NGRPS 20 /* \fIuser can't be in > 20 groups\fP */
880 xdr_netuser(xdrs, nup)
884 return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
885 xdr_int(xdrs, &nup->nu_uid) &&
886 xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen,
887 NGRPS, sizeof (int), xdr_int));
893 A party of network users could be implemented
897 The declaration and its associated XDR routines
904 struct netuser *p_nusers;
906 #define PLEN 500 /* \fImax number of users in a party\fP */
913 return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
914 sizeof (struct netuser), xdr_netuser));
920 The well-known parameters to
925 can be combined into a structure.
926 An array of these structures can make up a history of commands.
927 The declarations and XDR routines might look like:
935 #define ALEN 1000 /* \fIargs cannot be > 1000 chars\fP */
936 #define NARGC 100 /* \fIcommands cannot have > 100 args\fP */
942 #define NCMDS 75 /* \fIhistory is no more than 75 commands\fP */
945 xdr_wrap_string(xdrs, sp)
949 return(xdr_string(xdrs, sp, ALEN));
960 return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
961 sizeof (char *), xdr_wrap_string));
968 xdr_history(xdrs, hp)
972 return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
973 sizeof (struct cmd), xdr_cmd));
976 The most confusing part of this example is that the routine
978 is needed to package the
980 routine, because the implementation of
982 only passes two parameters to the array element description routine;
984 supplies the third parameter to
987 By now the recursive nature of the XDR library should be obvious.
988 Let's continue with more constructed data types.
991 .IX "XDR library" "opaque data"
993 In some protocols, handles are passed from a server to client.
994 The client passes the handle back to the server at some later time.
995 Handles are never inspected by clients;
996 they are obtained and submitted.
997 That is to say, handles are opaque.
1000 .IX xdr_opaque() "" \fIxdr_opaque()\fP
1001 primitive is used for describing fixed sized, opaque bytes.
1004 bool_t xdr_opaque(xdrs, p, len)
1011 is the location of the bytes;
1013 is the number of bytes in the opaque object.
1014 By definition, the actual data
1015 contained in the opaque object are not machine portable.
1017 \&Fixed Sized Arrays
1018 .IX "XDR library" "fixed sized arrays"
1020 The XDR library provides a primitive,
1022 for fixed-length arrays.
1026 #define NLEN 255 /* \fImachine names must be < 256 chars\fP */
1027 #define NGRPS 20 /* \fIuser belongs to exactly 20 groups\fP */
1030 char *nu_machinename;
1036 xdr_netuser(xdrs, nup)
1038 struct netuser *nup;
1042 if (!xdr_string(xdrs, &nup->nu_machinename, NLEN))
1044 if (!xdr_int(xdrs, &nup->nu_uid))
1046 if (!xdr_vector(xdrs, nup->nu_gids, NGRPS, sizeof(int),
1054 \&Discriminated Unions
1055 .IX "XDR library" "discriminated unions"
1057 The XDR library supports discriminated unions.
1058 A discriminated union is a C union and an
1060 value that selects an \*Qarm\*U of the union.
1063 struct xdr_discrim {
1068 bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm)
1072 struct xdr_discrim *arms;
1073 bool_t (*defaultarm)(); /* \fImay equal NULL\fP */
1075 First the routine translates the discriminant of the union located at
1077 The discriminant is always an
1079 Next the union located at
1084 is a pointer to an array of
1087 Each structure contains an ordered pair of
1089 If the union's discriminant is equal to the associated
1093 is called to translate the union.
1096 structure array is denoted by a routine of value
1098 (0). If the discriminant is not found in the
1102 procedure is called if it is non-null;
1103 otherwise the routine returns
1107 Suppose the type of a union may be integer,
1108 character pointer (a string), or a
1111 Also, assume the union and its current type
1112 are declared in a structure.
1117 enum utype { INTEGER=1, STRING=2, GNUMBERS=3 };
1120 enum utype utype; /* \fIthe union's discriminant\fP */
1128 The following constructs and XDR procedure (de)serialize
1129 the discriminated union:
1133 struct xdr_discrim u_tag_arms[4] = {
1134 { INTEGER, xdr_int },
1135 { GNUMBERS, xdr_gnumbers }
1136 { STRING, xdr_wrap_string },
1137 { __dontcare__, NULL }
1138 /* \fIalways terminate arms with a NULL xdr_proc\fP */
1142 xdr_u_tag(xdrs, utp)
1146 return(xdr_union(xdrs, &utp->utype, &utp->uval,
1152 was presented above in
1153 .I "The XDR Library"
1155 .I xdr_wrap_string()
1156 was presented in example C.
1161 (the last parameter) is
1163 in this example. Therefore the value of the union's discriminant
1164 may legally take on only values listed in the
1166 array. This example also demonstrates that
1167 the elements of the arm's array do not need to be sorted.
1169 It is worth pointing out that the values of the discriminant
1170 may be sparse, though in this example they are not.
1172 practice to assign explicitly integer values to each element of the
1173 discriminant's type.
1174 This practice both documents the external
1175 representation of the discriminant and guarantees that different
1176 C compilers emit identical discriminant values.
1180 using the other primitives in this section.
1183 .IX "XDR library" "pointers"
1185 In C it is often convenient to put pointers
1186 to another structure within a structure.
1189 .IX xdr_reference() "" \fIxdr_reference()\fP
1190 primitive makes it easy to serialize, deserialize, and free
1191 these referenced structures.
1194 bool_t xdr_reference(xdrs, pp, size, proc)
1204 the pointer to the structure;
1207 is the size in bytes of the structure (use the C function
1209 to obtain this value); and
1211 is the XDR routine that describes the structure.
1212 When decoding data, storage is allocated if
1217 There is no need for a primitive
1219 to describe structures within structures,
1220 because pointers are always sufficient.
1230 are NOT interchangeable external representations of data.
1233 Suppose there is a structure containing a person's name
1236 structure containing the person's gross assets and liabilities.
1242 struct gnumbers *gnp;
1245 The corresponding XDR routine for this structure is:
1253 if (xdr_string(xdrs, &pp->name, NLEN) &&
1254 xdr_reference(xdrs, &pp->gnp,
1255 sizeof(struct gnumbers), xdr_gnumbers))
1260 .IX "pointer semantics and XDR"
1261 .I "Pointer Semantics and XDR"
1263 In many applications, C programmers attach double meaning to
1264 the values of a pointer. Typically the value
1266 (or zero) means data is not needed,
1267 yet some application-specific interpretation applies.
1268 In essence, the C programmer is encoding
1269 a discriminated union efficiently
1270 by overloading the interpretation of the value of a pointer.
1271 For instance, in example E a
1276 the person's assets and liabilities are unknown.
1277 That is, the pointer value encodes two things:
1278 whether or not the data is known;
1279 and if it is known, where it is located in memory.
1280 Linked lists are an extreme example of the use
1281 of application-specific pointer interpretation.
1285 .IX xdr_reference() "" \fIxdr_reference()\fP
1286 cannot and does not attach any special
1287 meaning to a null-value pointer during serialization.
1288 That is, passing an address of a pointer whose value is
1292 when serialing data will most likely cause a memory fault and, on the UNIX
1293 system, a core dump.
1298 pointers. For more information about its use, see
1304 After reading the section on
1306 return here and extend example E so that
1307 it can correctly deal with
1317 primitives, implement a generic pointer handling primitive
1318 that implicitly deals with
1320 pointers. That is, implement
1323 \&Non-filter Primitives
1324 .IX "XDR" "non-filter primitives"
1326 XDR streams can be manipulated with
1327 the primitives discussed in this section.
1330 u_int xdr_getpos(xdrs)
1333 bool_t xdr_setpos(xdrs, pos)
1342 .IX xdr_getpos() "" \fIxdr_getpos()\fP
1343 returns an unsigned integer
1344 that describes the current position in the data stream.
1345 Warning: In some XDR streams, the returned value of
1348 the routine returns a \-1 in this case
1349 (though \-1 should be a legitimate value).
1353 .IX xdr_setpos() "" \fIxdr_setpos()\fP
1354 sets a stream position to
1356 Warning: In some XDR streams, setting a position is impossible;
1361 This routine will also fail if the requested position is out-of-bounds.
1362 The definition of bounds varies from stream to stream.
1366 .IX xdr_destroy() "" \fIxdr_destroy()\fP
1367 primitive destroys the XDR stream.
1369 after calling this routine is undefined.
1371 \&XDR Operation Directions
1372 .IX XDR "operation directions"
1373 .IX "direction of XDR operations"
1375 At times you may wish to optimize XDR routines by taking
1376 advantage of the direction of the operation \(em
1383 always contains the direction of the XDR operation.
1384 Programmers are not encouraged to take advantage of this information.
1385 Therefore, no example is presented here. However, an example in the
1387 topic below, demonstrates the usefulness of the
1392 .IX "XDR" "stream access"
1394 An XDR stream is obtained by calling the appropriate creation routine.
1395 These creation routines take arguments that are tailored to the
1396 specific properties of the stream.
1398 Streams currently exist for (de)serialization of data to or from
1401 streams, TCP/IP connections and UNIX files, and memory.
1403 \&Standard I/O Streams
1404 .IX "XDR" "standard I/O streams"
1406 XDR streams can be interfaced to standard I/O using the
1407 .I xdrstdio_create()
1408 .IX xdrstdio_create() "" \fIxdrstdio_create()\fP
1413 #include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
1416 xdrstdio_create(xdrs, fp, x_op)
1422 .I xdrstdio_create()
1423 initializes an XDR stream pointed to by
1425 The XDR stream interfaces to the standard I/O library.
1428 is an open file, and
1430 is an XDR direction.
1433 .IX "XDR" "memory streams"
1435 Memory streams allow the streaming of data into or out of
1436 a specified area of memory:
1439 #include <rpc/rpc.h>
1442 xdrmem_create(xdrs, addr, len, x_op)
1450 .IX xdrmem_create() "" \fIxdrmem_create()\fP
1451 initializes an XDR stream in local memory.
1452 The memory is pointed to by parameter
1456 is the length in bytes of the memory.
1461 are identical to the corresponding parameters of
1462 .I xdrstdio_create ().
1463 Currently, the UDP/IP implementation of RPC uses
1464 .I xdrmem_create ().
1465 Complete call or result messages are built in memory before calling the
1469 \&Record (TCP/IP) Streams
1470 .IX "XDR" "record (TCP/IP) streams"
1472 A record stream is an XDR stream built on top of
1473 a record marking standard that is built on top of the
1474 UNIX file or 4.2 BSD connection interface.
1477 #include <rpc/rpc.h> /* \fIxdr streams part of rpc\fP */
1480 sendsize, recvsize, iohandle, readproc, writeproc)
1482 u_int sendsize, recvsize;
1484 int (*readproc)(), (*writeproc)();
1488 provides an XDR stream interface that allows for a bidirectional,
1489 arbitrarily long sequence of records.
1490 The contents of the records are meant to be data in XDR form.
1491 The stream's primary use is for interfacing RPC to TCP connections.
1492 However, it can be used to stream data into or out of normal
1497 is similar to the corresponding parameter described above.
1498 The stream does its own data buffering similar to that of standard I/O.
1503 determine the size in bytes of the output and input buffers, respectively;
1504 if their values are zero (0), then predetermined defaults are used.
1505 When a buffer needs to be filled or flushed, the routine
1509 is called, respectively.
1510 The usage and behavior of these
1511 routines are similar to the UNIX system calls
1516 the first parameter to each of these routines is the opaque parameter
1518 The other two parameters
1523 (byte count) are identical to the system routines.
1530 then it has the following form:
1535 * returns the actual number of bytes transferred.
1540 xxx(iohandle, buf, len)
1545 The XDR stream provides means for delimiting records in the byte stream.
1546 The implementation details of delimiting records in a stream are
1548 .I "Advanced Topics"
1550 The primitives that are specific to record streams are as follows:
1554 xdrrec_endofrecord(xdrs, flushnow)
1559 xdrrec_skiprecord(xdrs)
1567 .I xdrrec_endofrecord()
1568 .IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fP
1569 causes the current outgoing data to be marked as a record.
1576 will be called; otherwise,
1578 will be called when the output buffer has been filled.
1581 .I xdrrec_skiprecord()
1582 .IX xdrrec_skiprecord() "" \fIxdrrec_skiprecord()\fP
1583 causes an input stream's position to be moved past
1584 the current record boundary and onto the
1585 beginning of the next record in the stream.
1587 If there is no more data in the stream's input buffer,
1590 .IX xdrrec_eof() "" \fIxdrrec_eof()\fP
1593 That is not to say that there is no more data
1594 in the underlying file descriptor.
1596 \&XDR Stream Implementation
1597 .IX "XDR" "stream implementation"
1598 .IX "stream implementation in XDR"
1600 This section provides the abstract data types needed
1601 to implement new instances of XDR streams.
1606 The following structure defines the interface to an XDR stream:
1610 enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
1613 enum xdr_op x_op; /* \fIoperation; fast added param\fP */
1615 bool_t (*x_getlong)(); /* \fIget long from stream\fP */
1616 bool_t (*x_putlong)(); /* \fIput long to stream\fP */
1617 bool_t (*x_getbytes)(); /* \fIget bytes from stream\fP */
1618 bool_t (*x_putbytes)(); /* \fIput bytes to stream\fP */
1619 u_int (*x_getpostn)(); /* \fIreturn stream offset\fP */
1620 bool_t (*x_setpostn)(); /* \fIreposition offset\fP */
1621 caddr_t (*x_inline)(); /* \fIptr to buffered data\fP */
1622 VOID (*x_destroy)(); /* \fIfree private area\fP */
1624 caddr_t x_public; /* \fIusers' data\fP */
1625 caddr_t x_private; /* \fIpointer to private data\fP */
1626 caddr_t x_base; /* \fIprivate for position info\fP */
1627 int x_handy; /* \fIextra private word\fP */
1632 field is the current operation being performed on the stream.
1633 This field is important to the XDR primitives,
1634 but should not affect a stream's implementation.
1635 That is, a stream's implementation should not depend
1642 are private to the particular
1643 stream's implementation.
1646 is for the XDR client and should never be used by
1647 the XDR stream implementations or the XDR primitives.
1652 are macros for accessing operations. The operation
1654 takes two parameters:
1655 an XDR *, and an unsigned integer, which is a byte count.
1656 The routine returns a pointer to a piece of
1657 the stream's internal buffer.
1658 The caller can then use the buffer segment for any purpose.
1659 From the stream's point of view, the bytes in the
1660 buffer segment have been consumed or put.
1661 The routine may return
1663 if it cannot return a buffer segment of the requested size.
1666 routine is for cycle squeezers.
1667 Use of the resulting buffer is not data-portable.
1668 Users are encouraged not to use this feature.)
1674 blindly get and put sequences of bytes
1675 from or to the underlying stream;
1678 if they are successful, and
1680 otherwise. The routines have identical parameters (replace
1685 xxxbytes(xdrs, buf, bytecount)
1695 long numbers from and to the data stream.
1696 It is the responsibility of these routines
1697 to translate the numbers between the machine representation
1698 and the (standard) external representation.
1703 can be helpful in accomplishing this.
1704 The higher-level XDR implementation assumes that
1705 signed and unsigned long integers contain the same number of bits,
1706 and that nonnegative integers
1707 have the same bit representations as unsigned integers.
1710 if they succeed, and
1712 otherwise. They have identical parameters:
1720 Implementors of new XDR streams must make an XDR structure
1721 (with new operation routines) available to clients,
1722 using some kind of create routine.
1725 .IX XDR "advanced topics"
1727 This section describes techniques for passing data structures that
1728 are not covered in the preceding sections. Such structures include
1729 linked lists (of arbitrary lengths). Unlike the simpler examples
1730 covered in the earlier sections, the following examples are written
1731 using both the XDR C library routines and the XDR data description
1734 .I "External Data Representation Standard: Protocol Specification"
1736 language in complete detail.
1739 .IX XDR "linked lists"
1741 The last example in the
1743 topic earlier in this chapter
1744 presented a C data structure and its associated XDR
1745 routines for a individual's gross assets and liabilities.
1746 The example is duplicated below:
1756 xdr_gnumbers(xdrs, gp)
1758 struct gnumbers *gp;
1760 if (xdr_long(xdrs, &(gp->g_assets)))
1761 return(xdr_long(xdrs, &(gp->g_liabilities)));
1766 Now assume that we wish to implement a linked list of such information.
1767 A data structure could be constructed as follows:
1771 struct gnumbers_node {
1772 struct gnumbers gn_numbers;
1773 struct gnumbers_node *gn_next;
1776 typedef struct gnumbers_node *gnumbers_list;
1779 The head of the linked list can be thought of as the data object;
1780 that is, the head is not merely a convenient shorthand for a
1781 structure. Similarly the
1783 field is used to indicate whether or not the object has terminated.
1784 Unfortunately, if the object continues, the
1786 field is also the address of where it continues. The link addresses
1787 carry no useful information when the object is serialized.
1789 The XDR data description of this linked list is described by the
1790 recursive declaration of
1800 struct gnumbers_node {
1801 gnumbers gn_numbers;
1802 gnumbers_node *gn_next;
1806 In this description, the boolean indicates whether there is more data
1807 following it. If the boolean is
1809 then it is the last data field of the structure. If it is
1811 then it is followed by a gnumbers structure and (recursively) by a
1813 Note that the C declaration has no boolean explicitly declared in it
1816 field implicitly carries the information), while the XDR data
1817 description has no pointer explicitly declared in it.
1819 Hints for writing the XDR routines for a
1821 follow easily from the XDR description above. Note how the primitive
1823 is used to implement the XDR union above.
1828 xdr_gnumbers_node(xdrs, gn)
1832 return(xdr_gnumbers(xdrs, &gn->gn_numbers) &&
1833 xdr_gnumbers_list(xdrs, &gp->gn_next));
1837 xdr_gnumbers_list(xdrs, gnp)
1841 return(xdr_pointer(xdrs, gnp,
1842 sizeof(struct gnumbers_node),
1843 xdr_gnumbers_node));
1847 The unfortunate side effect of XDR'ing a list with these routines
1848 is that the C stack grows linearly with respect to the number of
1849 node in the list. This is due to the recursion. The following
1850 routine collapses the above two mutually recursive into a single,
1856 xdr_gnumbers_list(xdrs, gnp)
1861 gnumbers_list *nextp;
1864 more_data = (*gnp != NULL);
1865 if (!xdr_bool(xdrs, &more_data)) {
1871 if (xdrs->x_op == XDR_FREE) {
1872 nextp = &(*gnp)->gn_next;
1874 if (!xdr_reference(xdrs, gnp,
1875 sizeof(struct gnumbers_node), xdr_gnumbers)) {
1879 gnp = (xdrs->x_op == XDR_FREE) ?
1880 nextp : &(*gnp)->gn_next;
1887 The first task is to find out whether there is more data or not,
1888 so that this boolean information can be serialized. Notice that
1889 this statement is unnecessary in the
1891 case, since the value of more_data is not known until we
1892 deserialize it in the next statement.
1894 The next statement XDR's the more_data field of the XDR union.
1895 Then if there is truly no more data, we set this last pointer to
1897 to indicate the end of the list, and return
1899 because we are done. Note that setting the pointer to
1901 is only important in the
1903 case, since it is already
1911 Next, if the direction is
1915 is set to indicate the location of the next pointer in the list.
1916 We do this now because we need to dereference gnp to find the
1917 location of the next item in the list, and after the next
1918 statement the storage pointed to by
1920 will be freed up and no be longer valid. We can't do this for all
1921 directions though, because in the
1923 direction the value of
1925 won't be set until the next statement.
1927 Next, we XDR the data in the node using the primitive
1928 .I xdr_reference ().
1932 which we used before, but it does not
1933 send over the boolean indicating whether there is more data.
1934 We use it instead of
1936 because we have already XDR'd this information ourselves. Notice
1937 that the xdr routine passed is not the same type as an element
1938 in the list. The routine passed is
1940 for XDR'ing gnumbers, but each element in the list is actually of
1944 .I xdr_gnumbers_node()
1945 because it is recursive, and instead use
1947 which XDR's all of the non-recursive part. Note that this trick
1948 will work only if the
1950 field is the first item in each element, so that their addresses
1951 are identical when passed to
1952 .I xdr_reference ().
1956 to point to the next item in the list. If the direction is
1958 we set it to the previously saved value, otherwise we can
1961 to get the proper value. Though harder to understand than the
1962 recursive version, this non-recursive routine is far less likely
1963 to blow the C stack. It will also run more efficiently since
1964 a lot of procedure call overhead has been removed. Most lists
1965 are small though (in the hundreds of items or less) and the
1966 recursive version should be sufficient for them.