]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - share/doc/psd/24.xdr/xdr.nts.ms
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / share / doc / psd / 24.xdr / xdr.nts.ms
1 .\"
2 .\" Must use --  eqn -- with this one
3 .\"
4 .\" @(#)xdr.nts.ms      2.2 88/08/05 4.0 RPCSRC
5 .\" $FreeBSD$
6 .\"
7 .EQ
8 delim $$
9 .EN
10 .de BT
11 .if \\n%=1 .tl ''- % -''
12 ..
13 .ND
14 .\" prevent excess underlining in nroff
15 .if n .fp 2 R
16 .OH 'External Data Representation: Sun Technical Notes''Page %'
17 .EH 'Page %''External Data Representation: Sun Technical Notes'
18 .if \n%=1 .bp
19 .SH
20 \&External Data Representation: Sun Technical Notes
21 .IX XDR "Sun technical notes"
22 .LP
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
28 standard, see the
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.\**
34 .FS
35 .IX XDR "system routines"
36 For a compete specification of the system External Data Representation
37 routines, see the
38 .I xdr(3N)
39 manual page.
40 .FE
41 .LP
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
48 .I "Number Filters",
49 .I "Floating Point Filters",
50 and
51 .I "Enumeration Filters"
52 sections.
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.
57 .SH
58 Note:
59 .I
60 .I rpcgen
61 can be used to write XDR routines even in cases where no RPC calls are
62 being made.
63 .LP
64 On Sun systems,
65 C programs that want to use XDR routines
66 must include the file
67 .I <rpc/rpc.h> ,
68 which contains all the necessary interfaces to the XDR system.
69 Since the C library
70 .I libc.a
71 contains all the XDR routines,
72 compile as normal.
73 .DS
74 example% \fBcc\0\fIprogram\fP.c\fI
75 .DE
76 .ne 3i
77 .NH 0
78 \&Justification
79 .IX XDR justification
80 .LP
81 Consider the following two programs,
82 .I writer :
83 .ie t .DS
84 .el .DS L
85 .ft CW
86 #include <stdio.h>
87 .sp .5
88 main()                  /* \fIwriter.c\fP */
89 {
90         long i;
91 .sp .5
92         for (i = 0; i < 8; i++) {
93                 if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) {
94                         fprintf(stderr, "failed!\en");
95                         exit(1);
96                 }
97         }
98         exit(0);
99 }
100 .DE
101 and
102 .I reader :
103 .ie t .DS
104 .el .DS L
105 .ft CW
106 #include <stdio.h>
107 .sp .5
108 main()                  /* \fIreader.c\fP */
109 {
110         long i, j;
111 .sp .5
112         for (j = 0; j < 8; j++) {
113                 if (fread((char *)&i, sizeof (i), 1, stdin) != 1) {
114                         fprintf(stderr, "failed!\en");
115                         exit(1);
116                 }
117                 printf("%ld ", i);
118         }
119         printf("\en");
120         exit(0);
121 }
122 .DE
123 The two programs appear to be portable, because (a) they pass
124 .I lint
125 checking, and (b) they exhibit the same behavior when executed
126 on two different hardware architectures, a Sun and a VAX.
127 .LP
128 Piping the output of the
129 .I writer
130 program to the
131 .I reader
132 program gives identical results on a Sun or a VAX.
133 .DS
134 .ft CW
135 sun% \fBwriter | reader\fP
136 0 1 2 3 4 5 6 7
137 sun%
138
139
140 vax% \fBwriter | reader\fP
141 0 1 2 3 4 5 6 7
142 vax%
143 .DE
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
148 .I writer
149 and
150 .I reader .
151 Here are the results if the first produces data on a Sun,
152 and the second consumes data on a VAX.
153 .DS
154 .ft CW
155 sun% \fBwriter | rsh vax reader\fP
156 0 16777216 33554432 50331648 67108864 83886080 100663296
157 117440512
158 sun%
159 .DE
160 Identical results can be obtained by executing
161 .I writer
162 on the VAX and
163 .I reader
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.
169 .LP
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
172 replacing the
173 .I read()
174 and
175 .I write()
176 calls with calls to an XDR library routine
177 .I xdr_long() ,
178 a filter that knows the standard representation
179 of a long integer in its external form.
180 Here are the revised versions of
181 .I writer :
182 .ie t .DS
183 .el .DS L
184 .ft CW
185 #include <stdio.h>
186 #include <rpc/rpc.h>    /* \fIxdr is a sub-library of rpc\fP */
187 .sp .5
188 main()          /* \fIwriter.c\fP */
189 {
190         XDR xdrs;
191         long i;
192 .sp .5
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");
197                         exit(1);
198                 }
199         }
200         exit(0);
201 }
202 .DE
203 and
204 .I reader :
205 .ie t .DS
206 .el .DS L
207 .ft CW
208 #include <stdio.h>
209 #include <rpc/rpc.h>    /* \fIxdr is a sub-library of rpc\fP */
210 .sp .5
211 main()          /* \fIreader.c\fP */
212 {
213         XDR xdrs;
214         long i, j;
215 .sp .5
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");
220                         exit(1);
221                 }
222                 printf("%ld ", i);
223         }
224         printf("\en");
225         exit(0);
226 }
227 .DE
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.
231 .DS
232 .ft CW
233 sun% \fBwriter | reader\fP
234 0 1 2 3 4 5 6 7
235 sun%
236
237 vax% \fBwriter | reader\fP
238 0 1 2 3 4 5 6 7
239 vax%
240
241 sun% \fBwriter | rsh vax reader\fP
242 0 1 2 3 4 5 6 7
243 sun%
244 .DE
245 .SH
246 Note:
247 .I
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.
255 .LP
256 .NH 1
257 \&A Canonical Standard
258 .IX XDR "canonical standard"
259 .LP
260 XDR's approach to standardizing data representations is
261 .I canonical .
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.
278 .LP
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.
291 .LP
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.
306 .NH 1
307 \&The XDR Library
308 .IX "XDR" "library"
309 .LP
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.
314 .LP
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.
325 .LP
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,
330 so we use
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.
335 In our example,
336 .I xdrstdio_create()
337 takes a pointer to an XDR structure that it initializes,
338 a pointer to a
339 .I FILE
340 that the input or output is performed on, and the operation.
341 The operation may be
342 .I XDR_ENCODE
343 for serializing in the
344 .I writer
345 program, or
346 .I XDR_DECODE
347 for deserializing in the
348 .I reader
349 program.
350 .LP
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.
354 .LP
355 The
356 .I xdr_long()
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
361 .I FALSE
362 (0) if it fails, and
363 .I TRUE
364 (1) if it succeeds.
365 Second, for each data type,
366 .I xxx ,
367 there is an associated XDR routine of the form:
368 .DS
369 .ft CW
370 xdr_xxx(xdrs, xp)
371         XDR *xdrs;
372         xxx *xp;
373 {
374 }
375 .DE
376 In our case,
377 .I xxx
378 is long, and the corresponding XDR routine is
379 a primitive,
380 .I xdr_long() .
381 The client could also define an arbitrary structure
382 .I xxx
383 in which case the client would also supply the routine
384 .I xdr_xxx (),
385 describing each field by calling XDR routines
386 of the appropriate type.
387 In all cases the first parameter,
388 .I xdrs
389 can be treated as an opaque handle,
390 and passed to the primitive routines.
391 .LP
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.
406 See the
407 .I "XDR Operation Directions"
408 section below for details.
409 .LP
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:
415 .ie t .DS
416 .el .DS L
417 .ft CW
418 struct gnumbers {
419         long g_assets;
420         long g_liabilities;
421 };
422 .DE
423 The corresponding XDR routine describing this structure would be:
424 .ie t .DS
425 .el .DS L
426 .ft CW
427 bool_t                  /* \fITRUE is success, FALSE is failure\fP */
428 xdr_gnumbers(xdrs, gp)
429         XDR *xdrs;
430         struct gnumbers *gp;
431 {
432         if (xdr_long(xdrs, &gp->g_assets) &&
433             xdr_long(xdrs, &gp->g_liabilities))
434                 return(TRUE);
435         return(FALSE);
436 }
437 .DE
438 Note that the parameter
439 .I xdrs
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
444 .I FALSE
445 if the subroutine fails.
446 .LP
447 This example also shows that the type
448 .I bool_t
449 is declared as an integer whose only values are
450 .I TRUE
451 (1) and
452 .I FALSE
453 (0).  This document uses the following definitions:
454 .ie t .DS
455 .el .DS L
456 .ft CW
457 #define bool_t  int
458 #define TRUE    1
459 #define FALSE   0
460 .DE
461 .LP
462 Keeping these conventions in mind,
463 .I xdr_gnumbers()
464 can be rewritten as follows:
465 .ie t .DS
466 .el .DS L
467 .ft CW
468 xdr_gnumbers(xdrs, gp)
469         XDR *xdrs;
470         struct gnumbers *gp;
471 {
472         return(xdr_long(xdrs, &gp->g_assets) &&
473                 xdr_long(xdrs, &gp->g_liabilities));
474 }
475 .DE
476 This document uses both coding styles.
477 .NH 1
478 \&XDR Library Primitives
479 .IX "library primitives for XDR"
480 .IX XDR "library primitives"
481 .LP
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
487 .I <rpc/xdr.h> ,
488 automatically included by
489 .I <rpc/rpc.h> .
490 .NH 2
491 \&Number Filters
492 .IX "XDR library" "number filters"
493 .LP
494 The XDR library provides primitives to translate between numbers
495 and their corresponding external representations.
496 Primitives cover the set of numbers in:
497 .DS
498 .ft CW
499 [signed, unsigned] * [short, int, long]
500 .DE
501 .ne 2i
502 Specifically, the eight primitives are:
503 .DS
504 .ft CW
505 bool_t xdr_char(xdrs, cp)
506         XDR *xdrs;
507         char *cp;
508 .sp .5
509 bool_t xdr_u_char(xdrs, ucp)
510         XDR *xdrs;
511         unsigned char *ucp;
512 .sp .5
513 bool_t xdr_int(xdrs, ip)
514         XDR *xdrs;
515         int *ip;
516 .sp .5
517 bool_t xdr_u_int(xdrs, up)
518         XDR *xdrs;
519         unsigned *up;
520 .sp .5
521 bool_t xdr_long(xdrs, lip)
522         XDR *xdrs;
523         long *lip;
524 .sp .5
525 bool_t xdr_u_long(xdrs, lup)
526         XDR *xdrs;
527         u_long *lup;
528 .sp .5
529 bool_t xdr_short(xdrs, sip)
530         XDR *xdrs;
531         short *sip;
532 .sp .5
533 bool_t xdr_u_short(xdrs, sup)
534         XDR *xdrs;
535         u_short *sup;
536 .DE
537 The first parameter,
538 .I xdrs ,
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.
542 All routines return
543 .I TRUE
544 if they complete successfully, and
545 .I FALSE
546 otherwise.
547 .NH 2
548 \&Floating Point Filters
549 .IX "XDR library" "floating point filters"
550 .LP
551 The XDR library also provides primitive routines
552 for C's floating point types:
553 .DS
554 .ft CW
555 bool_t xdr_float(xdrs, fp)
556         XDR *xdrs;
557         float *fp;
558 .sp .5
559 bool_t xdr_double(xdrs, dp)
560         XDR *xdrs;
561         double *dp;
562 .DE
563 The first parameter,
564 .I xdrs
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.
569 Both routines return
570 .I TRUE
571 if they complete successfully, and
572 .I FALSE
573 otherwise.
574 .LP
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.
578 .NH 2
579 \&Enumeration Filters
580 .IX "XDR library" "enumeration filters"
581 .LP
582 The XDR library provides a primitive for generic enumerations.
583 The primitive assumes that a C
584 .I enum
585 has the same representation inside the machine as a C integer.
586 The boolean type is an important instance of the
587 .I enum .
588 The external representation of a boolean is always
589 .I TRUE
590 (1) or
591 .I FALSE
592 (0).
593 .DS
594 .ft CW
595 #define bool_t  int
596 #define FALSE   0
597 #define TRUE    1
598 .sp .5
599 #define enum_t int
600 .sp .5
601 bool_t xdr_enum(xdrs, ep)
602         XDR *xdrs;
603         enum_t *ep;
604 .sp .5
605 bool_t xdr_bool(xdrs, bp)
606         XDR *xdrs;
607         bool_t *bp;
608 .DE
609 The second parameters
610 .I ep
611 and
612 .I bp
613 are addresses of the associated type that provides data to, or
614 receives data from, the stream
615 .I xdrs .
616 .NH 2
617 \&No Data
618 .IX "XDR library" "no data"
619 .LP
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:
623 .DS
624 .ft CW
625 bool_t xdr_void();  /* \fIalways returns TRUE\fP */
626 .DE
627 .NH 2
628 \&Constructed Data Type Filters
629 .IX "XDR library" "constructed data type filters"
630 .LP
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.
636 .LP
637 Constructed data type primitives may use memory management.
638 In many cases, memory is allocated when deserializing data with
639 .I XDR_DECODE
640 Therefore, the XDR package must provide means to deallocate memory.
641 This is done by an XDR operation,
642 .I XDR_FREE
643 To review, the three XDR directional operations are
644 .I XDR_ENCODE ,
645 .I XDR_DECODE
646 and
647 .I XDR_FREE .
648 .NH 3
649 \&Strings
650 .IX "XDR library" "strings"
651 .LP
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
658 .I "char *"
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
667 .I xdr_string ():
668 .IX xdr_string() "" \fIxdr_string()\fP
669 .DS
670 .ft CW
671 bool_t xdr_string(xdrs, sp, maxlength)
672         XDR *xdrs;
673         char **sp;
674         u_int maxlength;
675 .DE
676 The first parameter
677 .I xdrs
678 is the XDR stream handle.
679 The second parameter
680 .I sp
681 is a pointer to a string (type
682 .I "char **" .
683 The third parameter
684 .I maxlength
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.
688 .LP
689 The routine returns
690 .I FALSE
691 if the number of characters exceeds
692 .I maxlength ,
693 and
694 .I TRUE
695 if it doesn't.
696 .SH
697 Keep
698 .I maxlength
699 small.  If it is too big you can blow the heap, since
700 .I xdr_string()
701 will call
702 .I malloc()
703 for space.
704 .LP
705 The behavior of
706 .I xdr_string()
707 .IX xdr_string() "" \fIxdr_string()\fP
708 is similar to the behavior of other routines
709 discussed in this section.  The direction
710 .I XDR_ENCODE
711 is easiest to understand.  The parameter
712 .I sp
713 points to a string of a certain length;
714 if the string does not exceed
715 .I maxlength ,
716 the bytes are serialized.
717 .LP
718 The effect of deserializing a string is subtle.
719 First the length of the incoming string is determined;
720 it must not exceed
721 .I maxlength .
722 Next
723 .I sp
724 is dereferenced; if the value is
725 .I NULL ,
726 then a string of the appropriate length is allocated and
727 .I *sp
728 is set to this string.
729 If the original value of
730 .I *sp
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
734 .I maxlength .
735 In either case, the string is decoded into the target area.
736 The routine then appends a null character to the string.
737 .LP
738 In the
739 .I XDR_FREE
740 operation, the string is obtained by dereferencing
741 .I sp .
742 If the string is not
743 .I NULL ,
744 it is freed and
745 .I *sp
746 is set to
747 .I NULL .
748 In this operation,
749 .I xdr_string()
750 ignores the
751 .I maxlength
752 parameter.
753 .NH 3
754 \&Byte Arrays
755 .IX "XDR library" "byte arrays"
756 .LP
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.
764 The primitive
765 .I xdr_bytes()
766 .IX xdr_bytes() "" \fIxdr_bytes()\fP
767 converts between the internal and external
768 representations of byte arrays:
769 .DS
770 .ft CW
771 bool_t xdr_bytes(xdrs, bpp, lp, maxlength)
772     XDR *xdrs;
773     char **bpp;
774     u_int *lp;
775     u_int maxlength;
776 .DE
777 The usage of the first, second and fourth parameters
778 are identical to the first, second and third parameters of
779 .I xdr_string (),
780 respectively.
781 The length of the byte area is obtained by dereferencing
782 .I lp
783 when serializing;
784 .I *lp
785 is set to the byte length when deserializing.
786 .NH 3
787 \&Arrays
788 .IX "XDR library" "arrays"
789 .LP
790 The XDR library package provides a primitive
791 for handling arrays of arbitrary elements.
792 The
793 .I xdr_bytes()
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,
798 .I xdr_array() ,
799 .IX xdr_array() "" \fIxdr_array()\fP
800 requires parameters identical to those of
801 .I xdr_bytes()
802 plus two more:
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.
807 .DS
808 .ft CW
809 bool_t
810 xdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element)
811     XDR *xdrs;
812     char **ap;
813     u_int *lp;
814     u_int maxlength;
815     u_int elementsiz;
816     bool_t (*xdr_element)();
817 .DE
818 The parameter
819 .I ap
820 is the address of the pointer to the array.
821 If
822 .I *ap
823 is
824 .I NULL
825 when the array is being deserialized,
826 XDR allocates an array of the appropriate size and sets
827 .I *ap
828 to that array.
829 The element count of the array is obtained from
830 .I *lp
831 when the array is serialized;
832 .I *lp
833 is set to the array length when the array is deserialized.
834 The parameter
835 .I maxlength
836 is the maximum number of elements that the array is allowed to have;
837 .I elementsiz
838 is the byte size of each element of the array
839 (the C function
840 .I sizeof()
841 can be used to obtain this value).
842 The
843 .I xdr_element()
844 .IX xdr_element() "" \fIxdr_element()\fP
845 routine is called to serialize, deserialize, or free
846 each element of the array.
847 .br
848 .LP
849 Before defining more constructed data types, it is appropriate to
850 present three examples.
851 .LP
852 .I "Example A:"
853 .br
854 A user on a networked machine can be identified by
855 (a) the machine name, such as
856 .I krypton :
857 see the
858 .I gethostname
859 man page; (b) the user's UID: see the
860 .I geteuid
861 man page; and (c) the group numbers to which the user belongs:
862 see the
863 .I getgroups
864 man page.  A structure with this information and its associated
865 XDR routine could be coded like this:
866 .ie t .DS
867 .el .DS L
868 .ft CW
869 struct netuser {
870     char    *nu_machinename;
871     int     nu_uid;
872     u_int   nu_glen;
873     int     *nu_gids;
874 };
875 #define NLEN 255    /* \fImachine names < 256 chars\fP */
876 #define NGRPS 20    /* \fIuser can't be in > 20 groups\fP */
877 .sp .5
878 bool_t
879 xdr_netuser(xdrs, nup)
880     XDR *xdrs;
881     struct netuser *nup;
882 {
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));
887 }
888 .DE
889 .LP
890 .I "Example B:"
891 .br
892 A party of network users could be implemented
893 as an array of
894 .I netuser
895 structure.
896 The declaration and its associated XDR routines
897 are as follows:
898 .ie t .DS
899 .el .DS L
900 .ft CW
901 struct party {
902     u_int p_len;
903     struct netuser *p_nusers;
904 };
905 #define PLEN 500    /* \fImax number of users in a party\fP */
906 .sp .5
907 bool_t
908 xdr_party(xdrs, pp)
909     XDR *xdrs;
910     struct party *pp;
911 {
912     return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
913         sizeof (struct netuser), xdr_netuser));
914 }
915 .DE
916 .LP
917 .I "Example C:"
918 .br
919 The well-known parameters to
920 .I main ,
921 .I argc
922 and
923 .I argv
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:
927 .ie t .DS
928 .el .DS L
929 .ft CW
930 struct cmd {
931     u_int c_argc;
932     char **c_argv;
933 };
934 #define ALEN 1000   /* \fIargs cannot be > 1000 chars\fP */
935 #define NARGC 100   /* \fIcommands cannot have > 100 args\fP */
936
937 struct history {
938     u_int h_len;
939     struct cmd *h_cmds;
940 };
941 #define NCMDS 75    /* \fIhistory is no more than 75 commands\fP */
942
943 bool_t
944 xdr_wrap_string(xdrs, sp)
945     XDR *xdrs;
946     char **sp;
947 {
948     return(xdr_string(xdrs, sp, ALEN));
949 }
950 .DE
951 .ie t .DS
952 .el .DS L
953 .ft CW
954 bool_t
955 xdr_cmd(xdrs, cp)
956     XDR *xdrs;
957     struct cmd *cp;
958 {
959     return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
960         sizeof (char *), xdr_wrap_string));
961 }
962 .DE
963 .ie t .DS
964 .el .DS L
965 .ft CW
966 bool_t
967 xdr_history(xdrs, hp)
968     XDR *xdrs;
969     struct history *hp;
970 {
971     return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
972         sizeof (struct cmd), xdr_cmd));
973 }
974 .DE
975 The most confusing part of this example is that the routine
976 .I xdr_wrap_string()
977 is needed to package the
978 .I xdr_string()
979 routine, because the implementation of
980 .I xdr_array()
981 only passes two parameters to the array element description routine;
982 .I xdr_wrap_string()
983 supplies the third parameter to
984 .I xdr_string ().
985 .LP
986 By now the recursive nature of the XDR library should be obvious.
987 Let's continue with more constructed data types.
988 .NH 3
989 \&Opaque Data
990 .IX "XDR library" "opaque data"
991 .LP
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.
997 The
998 .I xdr_opaque()
999 .IX xdr_opaque() "" \fIxdr_opaque()\fP
1000 primitive is used for describing fixed sized, opaque bytes.
1001 .DS
1002 .ft CW
1003 bool_t xdr_opaque(xdrs, p, len)
1004     XDR *xdrs;
1005     char *p;
1006     u_int len;
1007 .DE
1008 The parameter
1009 .I p
1010 is the location of the bytes;
1011 .I len
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.
1015 .NH 3
1016 \&Fixed Sized Arrays
1017 .IX "XDR library" "fixed sized arrays"
1018 .LP
1019 The XDR library provides a primitive,
1020 .I xdr_vector (),
1021 for fixed-length arrays.
1022 .ie t .DS
1023 .el .DS L
1024 .ft CW
1025 #define NLEN 255    /* \fImachine names must be < 256 chars\fP */
1026 #define NGRPS 20    /* \fIuser belongs to exactly 20 groups\fP */
1027 .sp .5
1028 struct netuser {
1029     char *nu_machinename;
1030     int nu_uid;
1031     int nu_gids[NGRPS];
1032 };
1033 .sp .5
1034 bool_t
1035 xdr_netuser(xdrs, nup)
1036     XDR *xdrs;
1037     struct netuser *nup;
1038 {
1039     int i;
1040 .sp .5
1041     if (!xdr_string(xdrs, &nup->nu_machinename, NLEN))
1042         return(FALSE);
1043     if (!xdr_int(xdrs, &nup->nu_uid))
1044         return(FALSE);
1045     if (!xdr_vector(xdrs, nup->nu_gids, NGRPS, sizeof(int),
1046         xdr_int)) {
1047             return(FALSE);
1048     }
1049     return(TRUE);
1050 }
1051 .DE
1052 .NH 3
1053 \&Discriminated Unions
1054 .IX "XDR library" "discriminated unions"
1055 .LP
1056 The XDR library supports discriminated unions.
1057 A discriminated union is a C union and an
1058 .I enum_t
1059 value that selects an \*Qarm\*U of the union.
1060 .DS
1061 .ft CW
1062 struct xdr_discrim {
1063     enum_t value;
1064     bool_t (*proc)();
1065 };
1066 .sp .5
1067 bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm)
1068     XDR *xdrs;
1069     enum_t *dscmp;
1070     char *unp;
1071     struct xdr_discrim *arms;
1072     bool_t (*defaultarm)();  /* \fImay equal NULL\fP */
1073 .DE
1074 First the routine translates the discriminant of the union located at
1075 .I *dscmp .
1076 The discriminant is always an
1077 .I enum_t .
1078 Next the union located at
1079 .I *unp
1080 is translated.
1081 The parameter
1082 .I arms
1083 is a pointer to an array of
1084 .I xdr_discrim
1085 structures.
1086 Each structure contains an ordered pair of
1087 .I [value,proc] .
1088 If the union's discriminant is equal to the associated
1089 .I value ,
1090 then the
1091 .I proc
1092 is called to translate the union.
1093 The end of the
1094 .I xdr_discrim
1095 structure array is denoted by a routine of value
1096 .I NULL
1097 (0).  If the discriminant is not found in the
1098 .I arms
1099 array, then the
1100 .I defaultarm
1101 procedure is called if it is non-null;
1102 otherwise the routine returns
1103 .I FALSE .
1104 .LP
1105 .I "Example D:"
1106 Suppose the type of a union may be integer,
1107 character pointer (a string), or a
1108 .I gnumbers
1109 structure.
1110 Also, assume the union and its current type
1111 are declared in a structure.
1112 The declaration is:
1113 .ie t .DS
1114 .el .DS L
1115 .ft CW
1116 enum utype { INTEGER=1, STRING=2, GNUMBERS=3 };
1117 .sp .5
1118 struct u_tag {
1119     enum utype utype;   /* \fIthe union's discriminant\fP */
1120     union {
1121         int ival;
1122         char *pval;
1123         struct gnumbers gn;
1124     } uval;
1125 };
1126 .DE
1127 The following constructs and XDR procedure (de)serialize
1128 the discriminated union:
1129 .ie t .DS
1130 .el .DS L
1131 .ft CW
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 */
1138 }
1139 .sp .5
1140 bool_t
1141 xdr_u_tag(xdrs, utp)
1142     XDR *xdrs;
1143     struct u_tag *utp;
1144 {
1145     return(xdr_union(xdrs, &utp->utype, &utp->uval,
1146         u_tag_arms, NULL));
1147 }
1148 .DE
1149 The routine
1150 .I xdr_gnumbers()
1151 was presented above in
1152 .I "The XDR Library"
1153 section.
1154 .I xdr_wrap_string()
1155 was presented in example C.
1156 The default
1157 .I arm
1158 parameter to
1159 .I xdr_union()
1160 (the last parameter) is
1161 .I NULL
1162 in this example.  Therefore the value of the union's discriminant
1163 may legally take on only values listed in the
1164 .I u_tag_arms
1165 array.  This example also demonstrates that
1166 the elements of the arm's array do not need to be sorted.
1167 .LP
1168 It is worth pointing out that the values of the discriminant
1169 may be sparse, though in this example they are not.
1170 It is always good
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.
1176 .LP
1177 Exercise: Implement
1178 .I xdr_union()
1179 using the other primitives in this section.
1180 .NH 3
1181 \&Pointers
1182 .IX "XDR library" "pointers"
1183 .LP
1184 In C it is often convenient to put pointers
1185 to another structure within a structure.
1186 The
1187 .I xdr_reference()
1188 .IX xdr_reference() "" \fIxdr_reference()\fP
1189 primitive makes it easy to serialize, deserialize, and free
1190 these referenced structures.
1191 .DS
1192 .ft CW
1193 bool_t xdr_reference(xdrs, pp, size, proc)
1194     XDR *xdrs;
1195     char **pp;
1196     u_int ssize;
1197     bool_t (*proc)();
1198 .DE
1199 .LP
1200 Parameter
1201 .I pp
1202 is the address of
1203 the pointer to the structure;
1204 parameter
1205 .I ssize
1206 is the size in bytes of the structure (use the C function
1207 .I sizeof()
1208 to obtain this value); and
1209 .I proc
1210 is the XDR routine that describes the structure.
1211 When decoding data, storage is allocated if
1212 .I *pp
1213 is
1214 .I NULL .
1215 .LP
1216 There is no need for a primitive
1217 .I xdr_struct()
1218 to describe structures within structures,
1219 because pointers are always sufficient.
1220 .LP
1221 Exercise: Implement
1222 .I xdr_reference()
1223 using
1224 .I xdr_array ().
1225 Warning:
1226 .I xdr_reference()
1227 and
1228 .I xdr_array()
1229 are NOT interchangeable external representations of data.
1230 .LP
1231 .I "Example E:"
1232 Suppose there is a structure containing a person's name
1233 and a pointer to a
1234 .I gnumbers
1235 structure containing the person's gross assets and liabilities.
1236 The construct is:
1237 .DS
1238 .ft CW
1239 struct pgn {
1240     char *name;
1241     struct gnumbers *gnp;
1242 };
1243 .DE
1244 The corresponding XDR routine for this structure is:
1245 .DS
1246 .ft CW
1247 bool_t
1248 xdr_pgn(xdrs, pp)
1249     XDR *xdrs;
1250     struct pgn *pp;
1251 {
1252     if (xdr_string(xdrs, &pp->name, NLEN) &&
1253       xdr_reference(xdrs, &pp->gnp,
1254       sizeof(struct gnumbers), xdr_gnumbers))
1255         return(TRUE);
1256     return(FALSE);
1257 }
1258 .DE
1259 .IX "pointer semantics and XDR"
1260 .I "Pointer Semantics and XDR"
1261 .LP
1262 In many applications, C programmers attach double meaning to
1263 the values of a pointer.  Typically the value
1264 .I NULL
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
1271 .I NULL
1272 pointer value for
1273 .I gnp
1274 could indicate that
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.
1281 .LP
1282 The primitive
1283 .I xdr_reference()
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
1288 .I NULL
1289 to
1290 .I xdr_reference()
1291 when serialing data will most likely cause a memory fault and, on the UNIX
1292 system, a core dump.
1293 .LP
1294 .I xdr_pointer()
1295 correctly handles
1296 .I NULL
1297 pointers.  For more information about its use, see
1298 the
1299 .I "Linked Lists"
1300 topics below.
1301 .LP
1302 .I Exercise:
1303 After reading the section on
1304 .I "Linked Lists" ,
1305 return here and extend example E so that
1306 it can correctly deal with
1307 .I NULL
1308 pointer values.
1309 .LP
1310 .I Exercise:
1311 Using the
1312 .I xdr_union (),
1313 .I xdr_reference()
1314 and
1315 .I xdr_void()
1316 primitives, implement a generic pointer handling primitive
1317 that implicitly deals with
1318 .I NULL
1319 pointers.  That is, implement
1320 .I xdr_pointer ().
1321 .NH 2
1322 \&Non-filter Primitives
1323 .IX "XDR" "non-filter primitives"
1324 .LP
1325 XDR streams can be manipulated with
1326 the primitives discussed in this section.
1327 .DS
1328 .ft CW
1329 u_int xdr_getpos(xdrs)
1330     XDR *xdrs;
1331 .sp .5
1332 bool_t xdr_setpos(xdrs, pos)
1333     XDR *xdrs;
1334     u_int pos;
1335 .sp .5
1336 xdr_destroy(xdrs)
1337     XDR *xdrs;
1338 .DE
1339 The routine
1340 .I xdr_getpos()
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
1345 .I xdr_getpos()
1346 is meaningless;
1347 the routine returns a \-1 in this case
1348 (though \-1 should be a legitimate value).
1349 .LP
1350 The routine
1351 .I xdr_setpos()
1352 .IX xdr_setpos() "" \fIxdr_setpos()\fP
1353 sets a stream position to
1354 .I pos .
1355 Warning: In some XDR streams, setting a position is impossible;
1356 in such cases,
1357 .I xdr_setpos()
1358 will return
1359 .I FALSE .
1360 This routine will also fail if the requested position is out-of-bounds.
1361 The definition of bounds varies from stream to stream.
1362 .LP
1363 The
1364 .I xdr_destroy()
1365 .IX xdr_destroy() "" \fIxdr_destroy()\fP
1366 primitive destroys the XDR stream.
1367 Usage of the stream
1368 after calling this routine is undefined.
1369 .NH 2
1370 \&XDR Operation Directions
1371 .IX XDR "operation directions"
1372 .IX "direction of XDR operations"
1373 .LP
1374 At times you may wish to optimize XDR routines by taking
1375 advantage of the direction of the operation \(em
1376 .I XDR_ENCODE
1377 .I XDR_DECODE
1378 or
1379 .I XDR_FREE
1380 The value
1381 .I xdrs->x_op
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
1385 .I "Linked Lists"
1386 topic below, demonstrates the usefulness of the
1387 .I xdrs->x_op
1388 field.
1389 .NH 2
1390 \&XDR Stream Access
1391 .IX "XDR" "stream access"
1392 .LP
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.
1396 .LP
1397 Streams currently exist for (de)serialization of data to or from
1398 standard I/O
1399 .I FILE
1400 streams, TCP/IP connections and UNIX files, and memory.
1401 .NH 3
1402 \&Standard I/O Streams
1403 .IX "XDR" "standard I/O streams"
1404 .LP
1405 XDR streams can be interfaced to standard I/O using the
1406 .I xdrstdio_create()
1407 .IX xdrstdio_create() "" \fIxdrstdio_create()\fP
1408 routine as follows:
1409 .DS
1410 .ft CW
1411 #include <stdio.h>
1412 #include <rpc/rpc.h>    /* \fIxdr streams part of rpc\fP */
1413 .sp .5
1414 void
1415 xdrstdio_create(xdrs, fp, x_op)
1416     XDR *xdrs;
1417     FILE *fp;
1418     enum xdr_op x_op;
1419 .DE
1420 The routine
1421 .I xdrstdio_create()
1422 initializes an XDR stream pointed to by
1423 .I xdrs .
1424 The XDR stream interfaces to the standard I/O library.
1425 Parameter
1426 .I fp
1427 is an open file, and
1428 .I x_op
1429 is an XDR direction.
1430 .NH 3
1431 \&Memory Streams
1432 .IX "XDR" "memory streams"
1433 .LP
1434 Memory streams allow the streaming of data into or out of
1435 a specified area of memory:
1436 .DS
1437 .ft CW
1438 #include <rpc/rpc.h>
1439 .sp .5
1440 void
1441 xdrmem_create(xdrs, addr, len, x_op)
1442     XDR *xdrs;
1443     char *addr;
1444     u_int len;
1445     enum xdr_op x_op;
1446 .DE
1447 The routine
1448 .I xdrmem_create()
1449 .IX xdrmem_create() "" \fIxdrmem_create()\fP
1450 initializes an XDR stream in local memory.
1451 The memory is pointed to by parameter
1452 .I addr ;
1453 parameter
1454 .I len
1455 is the length in bytes of the memory.
1456 The parameters
1457 .I xdrs
1458 and
1459 .I x_op
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
1465 .I sendto()
1466 system routine.
1467 .NH 3
1468 \&Record (TCP/IP) Streams
1469 .IX "XDR" "record (TCP/IP) streams"
1470 .LP
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.
1474 .DS
1475 .ft CW
1476 #include <rpc/rpc.h>    /* \fIxdr streams part of rpc\fP */
1477 .sp .5
1478 xdrrec_create(xdrs,
1479   sendsize, recvsize, iohandle, readproc, writeproc)
1480     XDR *xdrs;
1481     u_int sendsize, recvsize;
1482     char *iohandle;
1483     int (*readproc)(), (*writeproc)();
1484 .DE
1485 The routine
1486 .I xdrrec_create()
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
1492 UNIX files.
1493 .LP
1494 The parameter
1495 .I xdrs
1496 is similar to the corresponding parameter described above.
1497 The stream does its own data buffering similar to that of standard I/O.
1498 The parameters
1499 .I sendsize
1500 and
1501 .I recvsize
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
1505 .I readproc()
1506 or
1507 .I writeproc()
1508 is called, respectively.
1509 The usage and behavior of these
1510 routines are similar to the UNIX system calls
1511 .I read()
1512 and
1513 .I write ().
1514 However,
1515 the first parameter to each of these routines is the opaque parameter
1516 .I iohandle .
1517 The other two parameters
1518 .I buf ""
1519 and
1520 .I nbytes )
1521 and the results
1522 (byte count) are identical to the system routines.
1523 If
1524 .I xxx
1525 is
1526 .I readproc()
1527 or
1528 .I writeproc (),
1529 then it has the following form:
1530 .DS
1531 .ft CW
1532 .ft I
1533 /*
1534  * returns the actual number of bytes transferred.
1535  * -1 is an error
1536  */
1537 .ft CW
1538 int
1539 xxx(iohandle, buf, len)
1540     char *iohandle;
1541     char *buf;
1542     int nbytes;
1543 .DE
1544 The XDR stream provides means for delimiting records in the byte stream.
1545 The implementation details of delimiting records in a stream are
1546 discussed in the
1547 .I "Advanced Topics"
1548 topic below.
1549 The primitives that are specific to record streams are as follows:
1550 .DS
1551 .ft CW
1552 bool_t
1553 xdrrec_endofrecord(xdrs, flushnow)
1554     XDR *xdrs;
1555     bool_t flushnow;
1556 .sp .5
1557 bool_t
1558 xdrrec_skiprecord(xdrs)
1559     XDR *xdrs;
1560 .sp .5
1561 bool_t
1562 xdrrec_eof(xdrs)
1563     XDR *xdrs;
1564 .DE
1565 The routine
1566 .I xdrrec_endofrecord()
1567 .IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fP
1568 causes the current outgoing data to be marked as a record.
1569 If the parameter
1570 .I flushnow
1571 is
1572 .I TRUE ,
1573 then the stream's
1574 .I writeproc
1575 will be called; otherwise,
1576 .I writeproc
1577 will be called when the output buffer has been filled.
1578 .LP
1579 The routine
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.
1585 .LP
1586 If there is no more data in the stream's input buffer,
1587 then the routine
1588 .I xdrrec_eof()
1589 .IX xdrrec_eof() "" \fIxdrrec_eof()\fP
1590 returns
1591 .I TRUE .
1592 That is not to say that there is no more data
1593 in the underlying file descriptor.
1594 .NH 2
1595 \&XDR Stream Implementation
1596 .IX "XDR" "stream implementation"
1597 .IX "stream implementation in XDR"
1598 .LP
1599 This section provides the abstract data types needed
1600 to implement new instances of XDR streams.
1601 .NH 3
1602 \&The XDR Object
1603 .IX "XDR" "object"
1604 .LP
1605 The following structure defines the interface to an XDR stream:
1606 .ie t .DS
1607 .el .DS L
1608 .ft CW
1609 enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
1610 .sp .5
1611 typedef struct {
1612     enum xdr_op x_op;            /* \fIoperation; fast added param\fP */
1613     struct xdr_ops {
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 */
1622     } *x_ops;
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 */
1627 } XDR;
1628 .DE
1629 The
1630 .I x_op
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
1635 on this value.
1636 The fields
1637 .I x_private ,
1638 .I x_base ,
1639 and
1640 .I x_handy
1641 are private to the particular
1642 stream's implementation.
1643 The field
1644 .I x_public
1645 is for the XDR client and should never be used by
1646 the XDR stream implementations or the XDR primitives.
1647 .I x_getpostn() ,
1648 .I x_setpostn()
1649 and
1650 .I x_destroy()
1651 are macros for accessing operations.  The operation
1652 .I x_inline()
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
1661 .I NULL
1662 if it cannot return a buffer segment of the requested size.
1663 (The
1664 .I x_inline()
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.)
1668 .LP
1669 The operations
1670 .I x_getbytes()
1671 and
1672 .I x_putbytes()
1673 blindly get and put sequences of bytes
1674 from or to the underlying stream;
1675 they return
1676 .I TRUE
1677 if they are successful, and
1678 .I FALSE
1679 otherwise.  The routines have identical parameters (replace
1680 .I xxx ):
1681 .DS
1682 .ft CW
1683 bool_t
1684 xxxbytes(xdrs, buf, bytecount)
1685         XDR *xdrs;
1686         char *buf;
1687         u_int bytecount;
1688 .DE
1689 The operations
1690 .I x_getlong()
1691 and
1692 .I x_putlong()
1693 receive and put
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.
1698 The UNIX primitives
1699 .I htonl()
1700 and
1701 .I ntohl()
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.
1707 The routines return
1708 .I TRUE
1709 if they succeed, and
1710 .I FALSE
1711 otherwise.  They have identical parameters:
1712 .DS
1713 .ft CW
1714 bool_t
1715 xxxlong(xdrs, lp)
1716         XDR *xdrs;
1717         long *lp;
1718 .DE
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.
1722 .NH 1
1723 \&Advanced Topics
1724 .IX XDR "advanced topics"
1725 .LP
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
1731 language.
1732 The
1733 .I "External Data Representation Standard: Protocol Specification"
1734 describes this
1735 language in complete detail.
1736 .NH 2
1737 \&Linked Lists
1738 .IX XDR "linked lists"
1739 .LP
1740 The last example in the
1741 .I Pointers
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:
1746 .ie t .DS
1747 .el .DS L
1748 .ft CW
1749 struct gnumbers {
1750         long g_assets;
1751         long g_liabilities;
1752 };
1753 .sp .5
1754 bool_t
1755 xdr_gnumbers(xdrs, gp)
1756         XDR *xdrs;
1757         struct gnumbers *gp;
1758 {
1759         if (xdr_long(xdrs, &(gp->g_assets)))
1760                 return(xdr_long(xdrs, &(gp->g_liabilities)));
1761         return(FALSE);
1762 }
1763 .DE
1764 .LP
1765 Now assume that we wish to implement a linked list of such information.
1766 A data structure could be constructed as follows:
1767 .ie t .DS
1768 .el .DS L
1769 .ft CW
1770 struct gnumbers_node {
1771         struct gnumbers gn_numbers;
1772         struct gnumbers_node *gn_next;
1773 };
1774 .sp .5
1775 typedef struct gnumbers_node *gnumbers_list;
1776 .DE
1777 .LP
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
1781 .I gn_next
1782 field is used to indicate whether or not the object has terminated.
1783 Unfortunately, if the object continues, the
1784 .I gn_next
1785 field is also the address of where it continues. The link addresses
1786 carry no useful information when the object is serialized.
1787 .LP
1788 The XDR data description of this linked list is described by the
1789 recursive declaration of
1790 .I gnumbers_list :
1791 .ie t .DS
1792 .el .DS L
1793 .ft CW
1794 struct gnumbers {
1795         int g_assets;
1796         int g_liabilities;
1797 };
1798 .sp .5
1799 struct gnumbers_node {
1800         gnumbers gn_numbers;
1801         gnumbers_node *gn_next;
1802 };
1803 .DE
1804 .LP
1805 In this description, the boolean indicates whether there is more data
1806 following it. If the boolean is
1807 .I FALSE ,
1808 then it is the last data field of the structure. If it is
1809 .I TRUE ,
1810 then it is followed by a gnumbers structure and (recursively) by a
1811 .I gnumbers_list .
1812 Note that the C declaration has no boolean explicitly declared in it
1813 (though the
1814 .I gn_next
1815 field implicitly carries the information), while the XDR data
1816 description has no pointer explicitly declared in it.
1817 .LP
1818 Hints for writing the XDR routines for a
1819 .I gnumbers_list
1820 follow easily from the XDR description above. Note how the primitive
1821 .I xdr_pointer()
1822 is used to implement the XDR union above.
1823 .ie t .DS
1824 .el .DS L
1825 .ft CW
1826 bool_t
1827 xdr_gnumbers_node(xdrs, gn)
1828         XDR *xdrs;
1829         gnumbers_node *gn;
1830 {
1831         return(xdr_gnumbers(xdrs, &gn->gn_numbers) &&
1832                 xdr_gnumbers_list(xdrs, &gp->gn_next));
1833 }
1834 .sp .5
1835 bool_t
1836 xdr_gnumbers_list(xdrs, gnp)
1837         XDR *xdrs;
1838         gnumbers_list *gnp;
1839 {
1840         return(xdr_pointer(xdrs, gnp,
1841                 sizeof(struct gnumbers_node),
1842                 xdr_gnumbers_node));
1843 }
1844 .DE
1845 .LP
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,
1850 non-recursive one.
1851 .ie t .DS
1852 .el .DS L
1853 .ft CW
1854 bool_t
1855 xdr_gnumbers_list(xdrs, gnp)
1856         XDR *xdrs;
1857         gnumbers_list *gnp;
1858 {
1859         bool_t more_data;
1860         gnumbers_list *nextp;
1861 .sp .5
1862         for (;;) {
1863                 more_data = (*gnp != NULL);
1864                 if (!xdr_bool(xdrs, &more_data)) {
1865                         return(FALSE);
1866                 }
1867                 if (! more_data) {
1868                         break;
1869                 }
1870                 if (xdrs->x_op == XDR_FREE) {
1871                         nextp = &(*gnp)->gn_next;
1872                 }
1873                 if (!xdr_reference(xdrs, gnp,
1874                         sizeof(struct gnumbers_node), xdr_gnumbers)) {
1875
1876                 return(FALSE);
1877                 }
1878                 gnp = (xdrs->x_op == XDR_FREE) ?
1879                         nextp : &(*gnp)->gn_next;
1880         }
1881         *gnp = NULL;
1882         return(TRUE);
1883 }
1884 .DE
1885 .LP
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
1889 .I XDR_DECODE
1890 case, since the value of more_data is not known until we
1891 deserialize it in the next statement.
1892 .LP
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
1895 .I NULL
1896 to indicate the end of the list, and return
1897 .I TRUE
1898 because we are done. Note that setting the pointer to
1899 .I NULL
1900 is only important in the
1901 .I XDR_DECODE
1902 case, since it is already
1903 .I NULL
1904 in the
1905 .I XDR_ENCODE
1906 and
1907 XDR_FREE
1908 cases.
1909 .LP
1910 Next, if the direction is
1911 .I XDR_FREE ,
1912 the value of
1913 .I nextp
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
1918 .I gnp
1919 will be freed up and no be longer valid.  We can't do this for all
1920 directions though, because in the
1921 .I XDR_DECODE
1922 direction the value of
1923 .I gnp
1924 won't be set until the next statement.
1925 .LP
1926 Next, we XDR the data in the node using the primitive
1927 .I xdr_reference ().
1928 .I xdr_reference()
1929 is like
1930 .I xdr_pointer()
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
1934 .I xdr_pointer()
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
1938 .I xdr_gnumbers (),
1939 for XDR'ing gnumbers, but each element in the list is actually of
1940 type
1941 .I gnumbers_node .
1942 We don't pass
1943 .I xdr_gnumbers_node()
1944 because it is recursive, and instead use
1945 .I xdr_gnumbers()
1946 which XDR's all of the non-recursive part.  Note that this trick
1947 will work only if the
1948 .I gn_numbers
1949 field is the first item in each element, so that their addresses
1950 are identical when passed to
1951 .I xdr_reference ().
1952 .LP
1953 Finally, we update
1954 .I gnp
1955 to point to the next item in the list. If the direction is
1956 .I XDR_FREE ,
1957 we set it to the previously saved value, otherwise we can
1958 dereference
1959 .I gnp
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.
1966 .EQ
1967 delim off
1968 .EN