grrr...fix reverse chronological order
[dragonfly.git] / lib / libcr / rpc / PSD.doc / 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: src/lib/libc/rpc/PSD.doc/xdr.nts.ms,v 1.1.14.1 2000/11/24 09:36:30 ru Exp $
6 .\" $DragonFly: src/lib/libcr/rpc/PSD.doc/Attic/xdr.nts.ms,v 1.2 2003/06/17 04:26:45 dillon Exp $
7 .\"
8 .so stubs
9 .EQ
10 delim $$
11 .EN
12 .de BT
13 .if \\n%=1 .tl ''- % -''
14 ..
15 .ND
16 .\" prevent excess underlining in nroff
17 .if n .fp 2 R
18 .OH 'External Data Representation: Sun Technical Notes''Page %'
19 .EH 'Page %''External Data Representation: Sun Technical Notes'
20 .if \n%=1 .bp
21 .SH
22 \&External Data Representation: Sun Technical Notes
23 .IX XDR "Sun technical notes"
24 .LP
25 This chapter contains technical notes on Sun's implementation of the
26 External Data Representation (XDR) standard, a set of library routines
27 that allow a C programmer to describe arbitrary data structures in a
28 machinex-independent fashion.  
29 For a formal specification of the XDR
30 standard, see the
31 .I "External Data Representation Standard: Protocol Specification".
32 XDR is the backbone of Sun's Remote Procedure Call package, in the 
33 sense that data for remote procedure calls is transmitted using the 
34 standard.  XDR library routines should be used to transmit data
35 that is accessed (read or written) by more than one type of machine.\**
36 .FS
37 .IX XDR "system routines"
38 For a compete specification of the system External Data Representation
39 routines, see the 
40 .I xdr(3N) 
41 manual page.
42 .FE
43 .LP
44 This chapter contains a short tutorial overview of the XDR library 
45 routines, a guide to accessing currently available XDR streams, and
46 information on defining new streams and data types.  XDR was designed
47 to work across different languages, operating systems, and machine 
48 architectures.  Most users (particularly RPC users) will only need
49 the information in the
50 .I "Number Filters",
51 .I "Floating Point Filters",
52 and
53 .I "Enumeration Filters"
54 sections.  
55 Programmers wishing to implement RPC and XDR on new machines
56 will be interested in the rest of the chapter, as well as the
57 .I "External Data Representaiton Standard: Protocol Specification",
58 which will be their primary reference.
59 .SH
60 Note:
61 .I
62 .I rpcgen 
63 can be used to write XDR routines even in cases where no RPC calls are
64 being made.
65 .LP
66 On Sun systems,
67 C programs that want to use XDR routines
68 must include the file
69 .I <rpc/rpc.h> ,
70 which contains all the necessary interfaces to the XDR system.
71 Since the C library
72 .I libc.a
73 contains all the XDR routines,
74 compile as normal.
75 .DS
76 example% \fBcc\0\fIprogram\fP.c\fI
77 .DE
78 .ne 3i
79 .NH 0
80 \&Justification
81 .IX XDR justification
82 .LP
83 Consider the following two programs,
84 .I writer :
85 .ie t .DS
86 .el .DS L
87 .ft CW
88 #include <stdio.h>
89 .sp .5
90 main()                  /* \fIwriter.c\fP */
91 {
92         long i;
93 .sp .5
94         for (i = 0; i < 8; i++) {
95                 if (fwrite((char *)&i, sizeof(i), 1, stdout) != 1) {
96                         fprintf(stderr, "failed!\en");
97                         exit(1);
98                 }
99         }
100         exit(0);
101 }
102 .DE
103 and
104 .I reader :
105 .ie t .DS
106 .el .DS L
107 .ft CW
108 #include <stdio.h>
109 .sp .5
110 main()                  /* \fIreader.c\fP */
111 {
112         long i, j;
113 .sp .5
114         for (j = 0; j < 8; j++) {
115                 if (fread((char *)&i, sizeof (i), 1, stdin) != 1) {
116                         fprintf(stderr, "failed!\en");
117                         exit(1);
118                 }
119                 printf("%ld ", i);
120         }
121         printf("\en");
122         exit(0);
123 }
124 .DE
125 The two programs appear to be portable, because (a) they pass
126 .I lint
127 checking, and (b) they exhibit the same behavior when executed
128 on two different hardware architectures, a Sun and a VAX.
129 .LP
130 Piping the output of the
131 .I writer 
132 program to the
133 .I reader 
134 program gives identical results on a Sun or a VAX.
135 .DS
136 .ft CW
137 sun% \fBwriter | reader\fP
138 0 1 2 3 4 5 6 7
139 sun%
140
141
142 vax% \fBwriter | reader\fP
143 0 1 2 3 4 5 6 7
144 vax%
145 .DE
146 With the advent of local area networks and 4.2BSD came the concept 
147 of \*Qnetwork pipes\*U \(em a process produces data on one machine,
148 and a second process consumes data on another machine.
149 A network pipe can be constructed with
150 .I writer 
151 and
152 .I reader .
153 Here are the results if the first produces data on a Sun,
154 and the second consumes data on a VAX.
155 .DS
156 .ft CW
157 sun% \fBwriter | rsh vax reader\fP
158 0 16777216 33554432 50331648 67108864 83886080 100663296
159 117440512
160 sun%
161 .DE
162 Identical results can be obtained by executing
163 .I writer 
164 on the VAX and
165 .I reader 
166 on the Sun.  These results occur because the byte ordering
167 of long integers differs between the VAX and the Sun,
168 even though word size is the same.
169 Note that $16777216$ is $2 sup 24$ \(em
170 when four bytes are reversed, the 1 winds up in the 24th bit.
171 .LP
172 Whenever data is shared by two or more machine types, there is
173 a need for portable data.  Programs can be made data-portable by
174 replacing the
175 .I read() 
176 and
177 .I write() 
178 calls with calls to an XDR library routine
179 .I xdr_long() ,
180 a filter that knows the standard representation
181 of a long integer in its external form.
182 Here are the revised versions of
183 .I writer :
184 .ie t .DS
185 .el .DS L
186 .ft CW
187 #include <stdio.h>
188 #include <rpc/rpc.h>    /* \fIxdr is a sub-library of rpc\fP */
189 .sp .5
190 main()          /* \fIwriter.c\fP */
191 {
192         XDR xdrs;
193         long i;
194 .sp .5
195         xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
196         for (i = 0; i < 8; i++) {
197                 if (!xdr_long(&xdrs, &i)) {
198                         fprintf(stderr, "failed!\en");
199                         exit(1);
200                 }
201         }
202         exit(0);
203 }
204 .DE
205 and
206 .I reader :
207 .ie t .DS
208 .el .DS L
209 .ft CW
210 #include <stdio.h>
211 #include <rpc/rpc.h>    /* \fIxdr is a sub-library of rpc\fP */
212 .sp .5
213 main()          /* \fIreader.c\fP */
214 {
215         XDR xdrs;
216         long i, j;
217 .sp .5
218         xdrstdio_create(&xdrs, stdin, XDR_DECODE);
219         for (j = 0; j < 8; j++) {
220                 if (!xdr_long(&xdrs, &i)) {
221                         fprintf(stderr, "failed!\en");
222                         exit(1);
223                 }
224                 printf("%ld ", i);
225         }
226         printf("\en");
227         exit(0);
228 }
229 .DE
230 The new programs were executed on a Sun,
231 on a VAX, and from a Sun to a VAX;
232 the results are shown below.
233 .DS
234 .ft CW
235 sun% \fBwriter | reader\fP
236 0 1 2 3 4 5 6 7
237 sun%
238
239 vax% \fBwriter | reader\fP
240 0 1 2 3 4 5 6 7
241 vax%
242
243 sun% \fBwriter | rsh vax reader\fP
244 0 1 2 3 4 5 6 7
245 sun%
246 .DE
247 .SH
248 Note:
249 .I
250 .IX XDR "portable data"
251 Integers are just the tip of the portable-data iceberg.  Arbitrary
252 data structures present portability problems, particularly with
253 respect to alignment and pointers.  Alignment on word boundaries
254 may cause the size of a structure to vary from machine to machine.
255 And pointers, which are very convenient to use, have no meaning
256 outside the machine where they are defined.
257 .LP
258 .NH 1
259 \&A Canonical Standard
260 .IX XDR "canonical standard"
261 .LP
262 XDR's approach to standardizing data representations is 
263 .I canonical .
264 That is, XDR defines a single byte order (Big Endian), a single
265 floating-point representation (IEEE), and so on.  Any program running on
266 any machine can use XDR to create portable data by translating its
267 local representation to the XDR standard representations; similarly, any
268 program running on any machine can read portable data by translating the
269 XDR standard representaions to its local equivalents.  The single standard
270 completely decouples programs that create or send portable data from those
271 that use or receive portable data.  The advent of a new machine or a new
272 language has no effect upon the community of existing portable data creators
273 and users.  A new machine joins this community by being \*Qtaught\*U how to
274 convert the standard representations and its local representations; the
275 local representations of other machines are irrelevant.  Conversely, to
276 existing programs running on other machines, the local representations of
277 the new machine are also irrelevant; such programs can immediately read
278 portable data produced by the new machine because such data conforms to the
279 canonical standards that they already understand.
280 .LP
281 There are strong precedents for XDR's canonical approach.  For example,
282 TCP/IP, UDP/IP, XNS, Ethernet, and, indeed, all protocols below layer five
283 of the ISO model, are canonical protocols.  The advantage of any canonical 
284 approach is simplicity; in the case of XDR, a single set of conversion 
285 routines is written once and is never touched again.  The canonical approach 
286 has a disadvantage, but it is unimportant in real-world data transfer 
287 applications.  Suppose two Little-Endian machines are transferring integers
288 according to the XDR standard.  The sending machine converts the integers 
289 from Little-Endian byte order to XDR (Big-Endian) byte order; the receiving
290 machine performs the reverse conversion.  Because both machines observe the
291 same byte order, their conversions are unnecessary.  The point, however, is
292 not necessity, but cost as compared to the alternative.
293 .LP
294 The time spent converting to and from a canonical representation is
295 insignificant, especially in networking applications.  Most of the time 
296 required to prepare a data structure for transfer is not spent in conversion 
297 but in traversing the elements of the data structure.  To transmit a tree, 
298 for example, each leaf must be visited and each element in a leaf record must
299 be copied to a buffer and aligned there; storage for the leaf may have to be
300 deallocated as well.  Similarly, to receive a tree, storage must be 
301 allocated for each leaf, data must be moved from the buffer to the leaf and
302 properly aligned, and pointers must be constructed to link the leaves 
303 together.  Every machine pays the cost of traversing and copying data
304 structures whether or not conversion is required.  In networking 
305 applications, communications overhead\(emthe time required to move the data
306 down through the sender's protocol layers, across the network and up through 
307 the receiver's protocol layers\(emdwarfs conversion overhead.
308 .NH 1
309 \&The XDR Library
310 .IX "XDR" "library"
311 .LP
312 The XDR library not only solves data portability problems, it also
313 allows you to write and read arbitrary C constructs in a consistent, 
314 specified, well-documented manner.  Thus, it can make sense to use the 
315 library even when the data is not shared among machines on a network.
316 .LP
317 The XDR library has filter routines for
318 strings (null-terminated arrays of bytes),
319 structures, unions, and arrays, to name a few.
320 Using more primitive routines,
321 you can write your own specific XDR routines
322 to describe arbitrary data structures,
323 including elements of arrays, arms of unions,
324 or objects pointed at from other structures.
325 The structures themselves may contain arrays of arbitrary elements,
326 or pointers to other structures.
327 .LP
328 Let's examine the two programs more closely.
329 There is a family of XDR stream creation routines
330 in which each member treats the stream of bits differently.
331 In our example, data is manipulated using standard I/O routines,
332 so we use
333 .I xdrstdio_create ().
334 .IX xdrstdio_create() "" "\fIxdrstdio_create()\fP"
335 The parameters to XDR stream creation routines
336 vary according to their function.
337 In our example,
338 .I xdrstdio_create() 
339 takes a pointer to an XDR structure that it initializes,
340 a pointer to a
341 .I FILE 
342 that the input or output is performed on, and the operation.
343 The operation may be
344 .I XDR_ENCODE
345 for serializing in the
346 .I writer 
347 program, or
348 .I XDR_DECODE
349 for deserializing in the
350 .I reader 
351 program.
352 .LP
353 Note: RPC users never need to create XDR streams;
354 the RPC system itself creates these streams,
355 which are then passed to the users.
356 .LP
357 The
358 .I xdr_long() 
359 .IX xdr_long() "" "\fIxdr_long()\fP"
360 primitive is characteristic of most XDR library 
361 primitives and all client XDR routines.
362 First, the routine returns
363 .I FALSE 
364 (0) if it fails, and
365 .I TRUE 
366 (1) if it succeeds.
367 Second, for each data type,
368 .I xxx ,
369 there is an associated XDR routine of the form:
370 .DS
371 .ft CW
372 xdr_xxx(xdrs, xp)
373         XDR *xdrs;
374         xxx *xp;
375 {
376 }
377 .DE
378 In our case,
379 .I xxx 
380 is long, and the corresponding XDR routine is
381 a primitive,
382 .I xdr_long() .
383 The client could also define an arbitrary structure
384 .I xxx 
385 in which case the client would also supply the routine
386 .I xdr_xxx (),
387 describing each field by calling XDR routines
388 of the appropriate type.
389 In all cases the first parameter,
390 .I xdrs 
391 can be treated as an opaque handle,
392 and passed to the primitive routines.
393 .LP
394 XDR routines are direction independent;
395 that is, the same routines are called to serialize or deserialize data.
396 This feature is critical to software engineering of portable data.
397 The idea is to call the same routine for either operation \(em
398 this almost guarantees that serialized data can also be deserialized.
399 One routine is used by both producer and consumer of networked data.
400 This is implemented by always passing the address
401 of an object rather than the object itself \(em
402 only in the case of deserialization is the object modified.
403 This feature is not shown in our trivial example,
404 but its value becomes obvious when nontrivial data structures
405 are passed among machines.  
406 If needed, the user can obtain the
407 direction of the XDR operation.  
408 See the
409 .I "XDR Operation Directions"
410 section below for details.
411 .LP
412 Let's look at a slightly more complicated example.
413 Assume that a person's gross assets and liabilities
414 are to be exchanged among processes.
415 Also assume that these values are important enough
416 to warrant their own data type:
417 .ie t .DS
418 .el .DS L
419 .ft CW
420 struct gnumbers {
421         long g_assets;
422         long g_liabilities;
423 };
424 .DE
425 The corresponding XDR routine describing this structure would be:
426 .ie t .DS
427 .el .DS L
428 .ft CW
429 bool_t                  /* \fITRUE is success, FALSE is failure\fP */
430 xdr_gnumbers(xdrs, gp)
431         XDR *xdrs;
432         struct gnumbers *gp;
433 {
434         if (xdr_long(xdrs, &gp->g_assets) &&
435             xdr_long(xdrs, &gp->g_liabilities))
436                 return(TRUE);
437         return(FALSE);
438 }
439 .DE
440 Note that the parameter
441 .I xdrs 
442 is never inspected or modified;
443 it is only passed on to the subcomponent routines.
444 It is imperative to inspect the return value of each XDR routine call,
445 and to give up immediately and return
446 .I FALSE 
447 if the subroutine fails.
448 .LP
449 This example also shows that the type
450 .I bool_t
451 is declared as an integer whose only values are
452 .I TRUE 
453 (1) and
454 .I FALSE 
455 (0).  This document uses the following definitions:
456 .ie t .DS
457 .el .DS L
458 .ft CW
459 #define bool_t  int
460 #define TRUE    1
461 #define FALSE   0
462 .DE
463 .LP
464 Keeping these conventions in mind,
465 .I xdr_gnumbers() 
466 can be rewritten as follows:
467 .ie t .DS
468 .el .DS L
469 .ft CW
470 xdr_gnumbers(xdrs, gp)
471         XDR *xdrs;
472         struct gnumbers *gp;
473 {
474         return(xdr_long(xdrs, &gp->g_assets) &&
475                 xdr_long(xdrs, &gp->g_liabilities));
476 }
477 .DE
478 This document uses both coding styles.
479 .NH 1
480 \&XDR Library Primitives
481 .IX "library primitives for XDR"
482 .IX XDR "library primitives"
483 .LP
484 This section gives a synopsis of each XDR primitive.
485 It starts with basic data types and moves on to constructed data types.
486 Finally, XDR utilities are discussed.
487 The interface to these primitives
488 and utilities is defined in the include file
489 .I <rpc/xdr.h> ,
490 automatically included by
491 .I <rpc/rpc.h> .
492 .NH 2
493 \&Number Filters
494 .IX "XDR library" "number filters"
495 .LP
496 The XDR library provides primitives to translate between numbers
497 and their corresponding external representations.
498 Primitives cover the set of numbers in:
499 .DS
500 .ft CW
501 [signed, unsigned] * [short, int, long]
502 .DE
503 .ne 2i
504 Specifically, the eight primitives are:
505 .DS
506 .ft CW
507 bool_t xdr_char(xdrs, cp)
508         XDR *xdrs;
509         char *cp;
510 .sp .5
511 bool_t xdr_u_char(xdrs, ucp)
512         XDR *xdrs;
513         unsigned char *ucp;
514 .sp .5
515 bool_t xdr_int(xdrs, ip)
516         XDR *xdrs;
517         int *ip;
518 .sp .5
519 bool_t xdr_u_int(xdrs, up)
520         XDR *xdrs;
521         unsigned *up;
522 .sp .5
523 bool_t xdr_long(xdrs, lip)
524         XDR *xdrs;
525         long *lip;
526 .sp .5
527 bool_t xdr_u_long(xdrs, lup)
528         XDR *xdrs;
529         u_long *lup;
530 .sp .5
531 bool_t xdr_short(xdrs, sip)
532         XDR *xdrs;
533         short *sip;
534 .sp .5
535 bool_t xdr_u_short(xdrs, sup)
536         XDR *xdrs;
537         u_short *sup;
538 .DE
539 The first parameter,
540 .I xdrs ,
541 is an XDR stream handle.
542 The second parameter is the address of the number
543 that provides data to the stream or receives data from it.
544 All routines return
545 .I TRUE 
546 if they complete successfully, and
547 .I FALSE 
548 otherwise.
549 .NH 2
550 \&Floating Point Filters
551 .IX "XDR library" "floating point filters"
552 .LP
553 The XDR library also provides primitive routines
554 for C's floating point types:
555 .DS
556 .ft CW
557 bool_t xdr_float(xdrs, fp)
558         XDR *xdrs;
559         float *fp;
560 .sp .5
561 bool_t xdr_double(xdrs, dp)
562         XDR *xdrs;
563         double *dp;
564 .DE
565 The first parameter,
566 .I xdrs 
567 is an XDR stream handle.
568 The second parameter is the address
569 of the floating point number that provides data to the stream
570 or receives data from it.
571 Both routines return
572 .I TRUE 
573 if they complete successfully, and
574 .I FALSE 
575 otherwise.
576 .LP
577 Note: Since the numbers are represented in IEEE floating point,
578 routines may fail when decoding a valid IEEE representation
579 into a machine-specific representation, or vice-versa.
580 .NH 2
581 \&Enumeration Filters
582 .IX "XDR library" "enumeration filters"
583 .LP
584 The XDR library provides a primitive for generic enumerations.
585 The primitive assumes that a C
586 .I enum 
587 has the same representation inside the machine as a C integer.
588 The boolean type is an important instance of the
589 .I enum .
590 The external representation of a boolean is always
591 .I TRUE 
592 (1) or 
593 .I FALSE 
594 (0).
595 .DS
596 .ft CW
597 #define bool_t  int
598 #define FALSE   0
599 #define TRUE    1
600 .sp .5
601 #define enum_t int
602 .sp .5
603 bool_t xdr_enum(xdrs, ep)
604         XDR *xdrs;
605         enum_t *ep;
606 .sp .5
607 bool_t xdr_bool(xdrs, bp)
608         XDR *xdrs;
609         bool_t *bp;
610 .DE
611 The second parameters
612 .I ep
613 and
614 .I bp
615 are addresses of the associated type that provides data to, or 
616 receives data from, the stream
617 .I xdrs .
618 .NH 2
619 \&No Data
620 .IX "XDR library" "no data"
621 .LP
622 Occasionally, an XDR routine must be supplied to the RPC system,
623 even when no data is passed or required.
624 The library provides such a routine:
625 .DS
626 .ft CW
627 bool_t xdr_void();  /* \fIalways returns TRUE\fP */
628 .DE
629 .NH 2
630 \&Constructed Data Type Filters
631 .IX "XDR library" "constructed data type filters"
632 .LP
633 Constructed or compound data type primitives
634 require more parameters and perform more complicated functions
635 then the primitives discussed above.
636 This section includes primitives for
637 strings, arrays, unions, and pointers to structures.
638 .LP
639 Constructed data type primitives may use memory management.
640 In many cases, memory is allocated when deserializing data with
641 .I XDR_DECODE
642 Therefore, the XDR package must provide means to deallocate memory.
643 This is done by an XDR operation,
644 .I XDR_FREE
645 To review, the three XDR directional operations are
646 .I XDR_ENCODE ,
647 .I XDR_DECODE
648 and
649 .I XDR_FREE .
650 .NH 3
651 \&Strings
652 .IX "XDR library" "strings"
653 .LP
654 In C, a string is defined as a sequence of bytes
655 terminated by a null byte,
656 which is not considered when calculating string length.
657 However, when a string is passed or manipulated,
658 a pointer to it is employed.
659 Therefore, the XDR library defines a string to be a
660 .I "char *"
661 and not a sequence of characters.
662 The external representation of a string is drastically different
663 from its internal representation.
664 Externally, strings are represented as
665 sequences of ASCII characters,
666 while internally, they are represented with character pointers.
667 Conversion between the two representations
668 is accomplished with the routine
669 .I xdr_string ():
670 .IX xdr_string() "" \fIxdr_string()\fP
671 .DS
672 .ft CW
673 bool_t xdr_string(xdrs, sp, maxlength)
674         XDR *xdrs;
675         char **sp;
676         u_int maxlength;
677 .DE
678 The first parameter
679 .I xdrs 
680 is the XDR stream handle.
681 The second parameter
682 .I sp 
683 is a pointer to a string (type
684 .I "char **" .
685 The third parameter
686 .I maxlength 
687 specifies the maximum number of bytes allowed during encoding or decoding.
688 its value is usually specified by a protocol.  For example, a protocol
689 specification may say that a file name may be no longer than 255 characters.
690 .LP
691 The routine returns
692 .I FALSE 
693 if the number of characters exceeds
694 .I maxlength ,
695 and
696 .I TRUE 
697 if it doesn't.
698 .SH
699 Keep
700 .I maxlength 
701 small.  If it is too big you can blow the heap, since
702 .I xdr_string() 
703 will call
704 .I malloc() 
705 for space.
706 .LP
707 The behavior of
708 .I xdr_string() 
709 .IX xdr_string() "" \fIxdr_string()\fP
710 is similar to the behavior of other routines
711 discussed in this section.  The direction
712 .I XDR_ENCODE 
713 is easiest to understand.  The parameter
714 .I sp 
715 points to a string of a certain length;
716 if the string does not exceed
717 .I maxlength ,
718 the bytes are serialized.
719 .LP
720 The effect of deserializing a string is subtle.
721 First the length of the incoming string is determined;
722 it must not exceed
723 .I maxlength .
724 Next
725 .I sp 
726 is dereferenced; if the the value is
727 .I NULL ,
728 then a string of the appropriate length is allocated and
729 .I *sp 
730 is set to this string.
731 If the original value of
732 .I *sp 
733 is non-null, then the XDR package assumes
734 that a target area has been allocated,
735 which can hold strings no longer than
736 .I maxlength .
737 In either case, the string is decoded into the target area.
738 The routine then appends a null character to the string.
739 .LP
740 In the
741 .I XDR_FREE 
742 operation, the string is obtained by dereferencing
743 .I sp .
744 If the string is not
745 .I NULL ,
746 it is freed and
747 .I *sp 
748 is set to
749 .I NULL .
750 In this operation,
751 .I xdr_string() 
752 ignores the
753 .I maxlength 
754 parameter.
755 .NH 3
756 \&Byte Arrays
757 .IX "XDR library" "byte arrays"
758 .LP
759 Often variable-length arrays of bytes are preferable to strings.
760 Byte arrays differ from strings in the following three ways: 
761 1) the length of the array (the byte count) is explicitly
762 located in an unsigned integer,
763 2) the byte sequence is not terminated by a null character, and
764 3) the external representation of the bytes is the same as their
765 internal representation.
766 The primitive
767 .I xdr_bytes() 
768 .IX xdr_bytes() "" \fIxdr_bytes()\fP
769 converts between the internal and external
770 representations of byte arrays:
771 .DS
772 .ft CW
773 bool_t xdr_bytes(xdrs, bpp, lp, maxlength)
774     XDR *xdrs;
775     char **bpp;
776     u_int *lp;
777     u_int maxlength;
778 .DE
779 The usage of the first, second and fourth parameters
780 are identical to the first, second and third parameters of
781 .I xdr_string (),
782 respectively.
783 The length of the byte area is obtained by dereferencing
784 .I lp 
785 when serializing;
786 .I *lp 
787 is set to the byte length when deserializing.
788 .NH 3
789 \&Arrays
790 .IX "XDR library" "arrays"
791 .LP
792 The XDR library package provides a primitive
793 for handling arrays of arbitrary elements.
794 The
795 .I xdr_bytes() 
796 routine treats a subset of generic arrays,
797 in which the size of array elements is known to be 1,
798 and the external description of each element is built-in.
799 The generic array primitive,
800 .I xdr_array() ,
801 .IX xdr_array() "" \fIxdr_array()\fP
802 requires parameters identical to those of
803 .I xdr_bytes() 
804 plus two more:
805 the size of array elements,
806 and an XDR routine to handle each of the elements.
807 This routine is called to encode or decode
808 each element of the array.
809 .DS
810 .ft CW
811 bool_t
812 xdr_array(xdrs, ap, lp, maxlength, elementsiz, xdr_element)
813     XDR *xdrs;
814     char **ap;
815     u_int *lp;
816     u_int maxlength;
817     u_int elementsiz;
818     bool_t (*xdr_element)();
819 .DE
820 The parameter
821 .I ap 
822 is the address of the pointer to the array.
823 If
824 .I *ap 
825 is
826 .I NULL 
827 when the array is being deserialized,
828 XDR allocates an array of the appropriate size and sets
829 .I *ap 
830 to that array.
831 The element count of the array is obtained from
832 .I *lp 
833 when the array is serialized;
834 .I *lp 
835 is set to the array length when the array is deserialized. 
836 The parameter
837 .I maxlength 
838 is the maximum number of elements that the array is allowed to have;
839 .I elementsiz
840 is the byte size of each element of the array
841 (the C function
842 .I sizeof()
843 can be used to obtain this value).
844 The
845 .I xdr_element() 
846 .IX xdr_element() "" \fIxdr_element()\fP
847 routine is called to serialize, deserialize, or free
848 each element of the array.
849 .br
850 .LP
851 Before defining more constructed data types, it is appropriate to 
852 present three examples.
853 .LP
854 .I "Example A:"
855 .br
856 A user on a networked machine can be identified by 
857 (a) the machine name, such as
858 .I krypton :
859 see the
860 .I gethostname 
861 man page; (b) the user's UID: see the
862 .I geteuid 
863 man page; and (c) the group numbers to which the user belongs: 
864 see the
865 .I getgroups 
866 man page.  A structure with this information and its associated 
867 XDR routine could be coded like this:
868 .ie t .DS
869 .el .DS L
870 .ft CW
871 struct netuser {
872     char    *nu_machinename;
873     int     nu_uid;
874     u_int   nu_glen;
875     int     *nu_gids;
876 };
877 #define NLEN 255    /* \fImachine names < 256 chars\fP */
878 #define NGRPS 20    /* \fIuser can't be in > 20 groups\fP */
879 .sp .5
880 bool_t
881 xdr_netuser(xdrs, nup)
882     XDR *xdrs;
883     struct netuser *nup;
884 {
885     return(xdr_string(xdrs, &nup->nu_machinename, NLEN) &&
886         xdr_int(xdrs, &nup->nu_uid) &&
887         xdr_array(xdrs, &nup->nu_gids, &nup->nu_glen, 
888         NGRPS, sizeof (int), xdr_int));
889 }
890 .DE
891 .LP
892 .I "Example B:"
893 .br
894 A party of network users could be implemented
895 as an array of
896 .I netuser
897 structure.
898 The declaration and its associated XDR routines
899 are as follows:
900 .ie t .DS
901 .el .DS L
902 .ft CW
903 struct party {
904     u_int p_len;
905     struct netuser *p_nusers;
906 };
907 #define PLEN 500    /* \fImax number of users in a party\fP */
908 .sp .5
909 bool_t
910 xdr_party(xdrs, pp)
911     XDR *xdrs;
912     struct party *pp;
913 {
914     return(xdr_array(xdrs, &pp->p_nusers, &pp->p_len, PLEN,
915         sizeof (struct netuser), xdr_netuser));
916 }
917 .DE
918 .LP
919 .I "Example C:"
920 .br
921 The well-known parameters to
922 .I main ,
923 .I argc
924 and
925 .I argv
926 can be combined into a structure.
927 An array of these structures can make up a history of commands.
928 The declarations and XDR routines might look like:
929 .ie t .DS
930 .el .DS L
931 .ft CW
932 struct cmd {
933     u_int c_argc;
934     char **c_argv;
935 };
936 #define ALEN 1000   /* \fIargs cannot be > 1000 chars\fP */
937 #define NARGC 100   /* \fIcommands cannot have > 100 args\fP */
938
939 struct history {
940     u_int h_len;
941     struct cmd *h_cmds;
942 };
943 #define NCMDS 75    /* \fIhistory is no more than 75 commands\fP */
944
945 bool_t
946 xdr_wrap_string(xdrs, sp)
947     XDR *xdrs;
948     char **sp;
949 {
950     return(xdr_string(xdrs, sp, ALEN));
951 }
952 .DE
953 .ie t .DS
954 .el .DS L
955 .ft CW
956 bool_t
957 xdr_cmd(xdrs, cp)
958     XDR *xdrs;
959     struct cmd *cp;
960 {
961     return(xdr_array(xdrs, &cp->c_argv, &cp->c_argc, NARGC,
962         sizeof (char *), xdr_wrap_string));
963 }
964 .DE
965 .ie t .DS
966 .el .DS L
967 .ft CW
968 bool_t
969 xdr_history(xdrs, hp)
970     XDR *xdrs;
971     struct history *hp;
972 {
973     return(xdr_array(xdrs, &hp->h_cmds, &hp->h_len, NCMDS,
974         sizeof (struct cmd), xdr_cmd));
975 }
976 .DE
977 The most confusing part of this example is that the routine
978 .I xdr_wrap_string() 
979 is needed to package the
980 .I xdr_string() 
981 routine, because the implementation of
982 .I xdr_array() 
983 only passes two parameters to the array element description routine;
984 .I xdr_wrap_string() 
985 supplies the third parameter to
986 .I xdr_string ().
987 .LP
988 By now the recursive nature of the XDR library should be obvious.
989 Let's continue with more constructed data types.
990 .NH 3
991 \&Opaque Data
992 .IX "XDR library" "opaque data"
993 .LP
994 In some protocols, handles are passed from a server to client.
995 The client passes the handle back to the server at some later time.
996 Handles are never inspected by clients;
997 they are obtained and submitted.
998 That is to say, handles are opaque.
999 The
1000 .I xdr_opaque() 
1001 .IX xdr_opaque() "" \fIxdr_opaque()\fP
1002 primitive is used for describing fixed sized, opaque bytes.
1003 .DS
1004 .ft CW
1005 bool_t xdr_opaque(xdrs, p, len)
1006     XDR *xdrs;
1007     char *p;
1008     u_int len;
1009 .DE
1010 The parameter
1011 .I p 
1012 is the location of the bytes;
1013 .I len
1014 is the number of bytes in the opaque object.
1015 By definition, the actual data
1016 contained in the opaque object are not machine portable.
1017 .NH 3
1018 \&Fixed Sized Arrays
1019 .IX "XDR library" "fixed sized arrays"
1020 .LP
1021 The XDR library provides a primitive,
1022 .I xdr_vector (),
1023 for fixed-length arrays.
1024 .ie t .DS
1025 .el .DS L
1026 .ft CW
1027 #define NLEN 255    /* \fImachine names must be < 256 chars\fP */
1028 #define NGRPS 20    /* \fIuser belongs to exactly 20 groups\fP */
1029 .sp .5
1030 struct netuser {
1031     char *nu_machinename;
1032     int nu_uid;
1033     int nu_gids[NGRPS];
1034 };
1035 .sp .5
1036 bool_t
1037 xdr_netuser(xdrs, nup)
1038     XDR *xdrs;
1039     struct netuser *nup;
1040 {
1041     int i;
1042 .sp .5
1043     if (!xdr_string(xdrs, &nup->nu_machinename, NLEN))
1044         return(FALSE);
1045     if (!xdr_int(xdrs, &nup->nu_uid))
1046         return(FALSE);
1047     if (!xdr_vector(xdrs, nup->nu_gids, NGRPS, sizeof(int), 
1048         xdr_int)) {
1049             return(FALSE);
1050     }
1051     return(TRUE);
1052 }
1053 .DE
1054 .NH 3
1055 \&Discriminated Unions
1056 .IX "XDR library" "discriminated unions"
1057 .LP
1058 The XDR library supports discriminated unions.
1059 A discriminated union is a C union and an
1060 .I enum_t
1061 value that selects an \*Qarm\*U of the union.
1062 .DS
1063 .ft CW
1064 struct xdr_discrim {
1065     enum_t value;
1066     bool_t (*proc)();
1067 };
1068 .sp .5
1069 bool_t xdr_union(xdrs, dscmp, unp, arms, defaultarm)
1070     XDR *xdrs;
1071     enum_t *dscmp;
1072     char *unp;
1073     struct xdr_discrim *arms;
1074     bool_t (*defaultarm)();  /* \fImay equal NULL\fP */
1075 .DE
1076 First the routine translates the discriminant of the union located at 
1077 .I *dscmp .
1078 The discriminant is always an
1079 .I enum_t .
1080 Next the union located at
1081 .I *unp 
1082 is translated.
1083 The parameter
1084 .I arms
1085 is a pointer to an array of
1086 .I xdr_discrim
1087 structures. 
1088 Each structure contains an ordered pair of
1089 .I [value,proc] .
1090 If the union's discriminant is equal to the associated
1091 .I value ,
1092 then the
1093 .I proc
1094 is called to translate the union.
1095 The end of the
1096 .I xdr_discrim
1097 structure array is denoted by a routine of value
1098 .I NULL 
1099 (0).  If the discriminant is not found in the
1100 .I arms
1101 array, then the
1102 .I defaultarm
1103 procedure is called if it is non-null;
1104 otherwise the routine returns
1105 .I FALSE .
1106 .LP
1107 .I "Example D:"
1108 Suppose the type of a union may be integer,
1109 character pointer (a string), or a
1110 .I gnumbers 
1111 structure.
1112 Also, assume the union and its current type
1113 are declared in a structure.
1114 The declaration is:
1115 .ie t .DS
1116 .el .DS L
1117 .ft CW
1118 enum utype { INTEGER=1, STRING=2, GNUMBERS=3 };
1119 .sp .5
1120 struct u_tag {
1121     enum utype utype;   /* \fIthe union's discriminant\fP */
1122     union {
1123         int ival;
1124         char *pval;
1125         struct gnumbers gn;
1126     } uval;
1127 };
1128 .DE
1129 The following constructs and XDR procedure (de)serialize
1130 the discriminated union:
1131 .ie t .DS
1132 .el .DS L
1133 .ft CW
1134 struct xdr_discrim u_tag_arms[4] = {
1135     { INTEGER, xdr_int },
1136     { GNUMBERS, xdr_gnumbers }
1137     { STRING, xdr_wrap_string },
1138     { __dontcare__, NULL }
1139     /* \fIalways terminate arms with a NULL xdr_proc\fP */
1140 }
1141 .sp .5
1142 bool_t
1143 xdr_u_tag(xdrs, utp)
1144     XDR *xdrs;
1145     struct u_tag *utp;
1146 {
1147     return(xdr_union(xdrs, &utp->utype, &utp->uval,
1148         u_tag_arms, NULL));
1149 }
1150 .DE
1151 The routine
1152 .I xdr_gnumbers() 
1153 was presented above in 
1154 .I "The XDR Library"
1155 section.
1156 .I xdr_wrap_string() 
1157 was presented in example C.
1158 The default 
1159 .I arm 
1160 parameter to
1161 .I xdr_union() 
1162 (the last parameter) is
1163 .I NULL 
1164 in this example.  Therefore the value of the union's discriminant
1165 may legally take on only values listed in the
1166 .I u_tag_arms 
1167 array.  This example also demonstrates that
1168 the elements of the arm's array do not need to be sorted.
1169 .LP
1170 It is worth pointing out that the values of the discriminant
1171 may be sparse, though in this example they are not.
1172 It is always good
1173 practice to assign explicitly integer values to each element of the
1174 discriminant's type.
1175 This practice both documents the external
1176 representation of the discriminant and guarantees that different
1177 C compilers emit identical discriminant values.
1178 .LP
1179 Exercise: Implement
1180 .I xdr_union() 
1181 using the other primitives in this section.
1182 .NH 3
1183 \&Pointers
1184 .IX "XDR library" "pointers"
1185 .LP
1186 In C it is often convenient to put pointers
1187 to another structure within a structure.
1188 The
1189 .I xdr_reference() 
1190 .IX xdr_reference() "" \fIxdr_reference()\fP
1191 primitive makes it easy to serialize, deserialize, and free
1192 these referenced structures.
1193 .DS
1194 .ft CW
1195 bool_t xdr_reference(xdrs, pp, size, proc)
1196     XDR *xdrs;
1197     char **pp;
1198     u_int ssize;
1199     bool_t (*proc)();
1200 .DE
1201 .LP
1202 Parameter
1203 .I pp 
1204 is the address of
1205 the pointer to the structure;
1206 parameter
1207 .I ssize
1208 is the size in bytes of the structure (use the C function
1209 .I sizeof() 
1210 to obtain this value); and
1211 .I proc
1212 is the XDR routine that describes the structure.
1213 When decoding data, storage is allocated if
1214 .I *pp 
1215 is
1216 .I NULL .
1217 .LP
1218 There is no need for a primitive
1219 .I xdr_struct() 
1220 to describe structures within structures,
1221 because pointers are always sufficient.
1222 .LP
1223 Exercise: Implement
1224 .I xdr_reference() 
1225 using
1226 .I xdr_array ().
1227 Warning:
1228 .I xdr_reference() 
1229 and
1230 .I xdr_array() 
1231 are NOT interchangeable external representations of data.
1232 .LP
1233 .I "Example E:"
1234 Suppose there is a structure containing a person's name
1235 and a pointer to a
1236 .I gnumbers 
1237 structure containing the person's gross assets and liabilities.
1238 The construct is:
1239 .DS
1240 .ft CW
1241 struct pgn {
1242     char *name;
1243     struct gnumbers *gnp;
1244 };
1245 .DE
1246 The corresponding XDR routine for this structure is:
1247 .DS
1248 .ft CW
1249 bool_t
1250 xdr_pgn(xdrs, pp)
1251     XDR *xdrs;
1252     struct pgn *pp;
1253 {
1254     if (xdr_string(xdrs, &pp->name, NLEN) &&
1255       xdr_reference(xdrs, &pp->gnp,
1256       sizeof(struct gnumbers), xdr_gnumbers))
1257         return(TRUE);
1258     return(FALSE);
1259 }
1260 .DE
1261 .IX "pointer semantics and XDR"
1262 .I "Pointer Semantics and XDR" 
1263 .LP
1264 In many applications, C programmers attach double meaning to 
1265 the values of a pointer.  Typically the value
1266 .I NULL 
1267 (or zero) means data is not needed,
1268 yet some application-specific interpretation applies.
1269 In essence, the C programmer is encoding
1270 a discriminated union efficiently
1271 by overloading the interpretation of the value of a pointer.
1272 For instance, in example E a
1273 .I NULL 
1274 pointer value for
1275 .I gnp
1276 could indicate that
1277 the person's assets and liabilities are unknown.
1278 That is, the pointer value encodes two things:
1279 whether or not the data is known;
1280 and if it is known, where it is located in memory.
1281 Linked lists are an extreme example of the use
1282 of application-specific pointer interpretation.
1283 .LP
1284 The primitive
1285 .I xdr_reference() 
1286 .IX xdr_reference() "" \fIxdr_reference()\fP
1287 cannot and does not attach any special
1288 meaning to a null-value pointer during serialization.
1289 That is, passing an address of a pointer whose value is
1290 .I NULL 
1291 to
1292 .I xdr_reference() 
1293 when serialing data will most likely cause a memory fault and, on the UNIX
1294 system, a core dump.
1295 .LP
1296 .I xdr_pointer() 
1297 correctly handles 
1298 .I NULL 
1299 pointers.  For more information about its use, see 
1300 the
1301 .I "Linked Lists"
1302 topics below.
1303 .LP
1304 .I Exercise:
1305 After reading the section on
1306 .I "Linked Lists" ,
1307 return here and extend example E so that
1308 it can correctly deal with 
1309 .I NULL 
1310 pointer values.
1311 .LP
1312 .I Exercise:
1313 Using the
1314 .I xdr_union (),
1315 .I xdr_reference() 
1316 and
1317 .I xdr_void() 
1318 primitives, implement a generic pointer handling primitive
1319 that implicitly deals with
1320 .I NULL 
1321 pointers.  That is, implement
1322 .I xdr_pointer ().
1323 .NH 2
1324 \&Non-filter Primitives
1325 .IX "XDR" "non-filter primitives"
1326 .LP
1327 XDR streams can be manipulated with
1328 the primitives discussed in this section.
1329 .DS
1330 .ft CW
1331 u_int xdr_getpos(xdrs)
1332     XDR *xdrs;
1333 .sp .5
1334 bool_t xdr_setpos(xdrs, pos)
1335     XDR *xdrs;
1336     u_int pos;
1337 .sp .5
1338 xdr_destroy(xdrs)
1339     XDR *xdrs;
1340 .DE
1341 The routine
1342 .I xdr_getpos() 
1343 .IX xdr_getpos() "" \fIxdr_getpos()\fP
1344 returns an unsigned integer
1345 that describes the current position in the data stream.
1346 Warning: In some XDR streams, the returned value of
1347 .I xdr_getpos() 
1348 is meaningless;
1349 the routine returns a \-1 in this case
1350 (though \-1 should be a legitimate value).
1351 .LP
1352 The routine
1353 .I xdr_setpos() 
1354 .IX xdr_setpos() "" \fIxdr_setpos()\fP
1355 sets a stream position to
1356 .I pos .
1357 Warning: In some XDR streams, setting a position is impossible;
1358 in such cases,
1359 .I xdr_setpos() 
1360 will return
1361 .I FALSE .
1362 This routine will also fail if the requested position is out-of-bounds.
1363 The definition of bounds varies from stream to stream.
1364 .LP
1365 The
1366 .I xdr_destroy() 
1367 .IX xdr_destroy() "" \fIxdr_destroy()\fP
1368 primitive destroys the XDR stream.
1369 Usage of the stream
1370 after calling this routine is undefined.
1371 .NH 2
1372 \&XDR Operation Directions
1373 .IX XDR "operation directions"
1374 .IX "direction of XDR operations"
1375 .LP
1376 At times you may wish to optimize XDR routines by taking
1377 advantage of the direction of the operation \(em
1378 .I XDR_ENCODE
1379 .I XDR_DECODE
1380 or
1381 .I XDR_FREE
1382 The value
1383 .I xdrs->x_op
1384 always contains the direction of the XDR operation.
1385 Programmers are not encouraged to take advantage of this information.
1386 Therefore, no example is presented here.  However, an example in the
1387 .I "Linked Lists"
1388 topic below, demonstrates the usefulness of the
1389 .I xdrs->x_op
1390 field.
1391 .NH 2
1392 \&XDR Stream Access
1393 .IX "XDR" "stream access"
1394 .LP
1395 An XDR stream is obtained by calling the appropriate creation routine.
1396 These creation routines take arguments that are tailored to the
1397 specific properties of the stream.
1398 .LP
1399 Streams currently exist for (de)serialization of data to or from
1400 standard I/O
1401 .I FILE
1402 streams, TCP/IP connections and UNIX files, and memory.
1403 .NH 3
1404 \&Standard I/O Streams
1405 .IX "XDR" "standard I/O streams"
1406 .LP
1407 XDR streams can be interfaced to standard I/O using the
1408 .I xdrstdio_create() 
1409 .IX xdrstdio_create() "" \fIxdrstdio_create()\fP
1410 routine as follows:
1411 .DS
1412 .ft CW
1413 #include <stdio.h>
1414 #include <rpc/rpc.h>    /* \fIxdr streams part of rpc\fP */
1415 .sp .5
1416 void
1417 xdrstdio_create(xdrs, fp, x_op)
1418     XDR *xdrs;
1419     FILE *fp;
1420     enum xdr_op x_op;
1421 .DE
1422 The routine
1423 .I xdrstdio_create() 
1424 initializes an XDR stream pointed to by
1425 .I xdrs .
1426 The XDR stream interfaces to the standard I/O library.
1427 Parameter
1428 .I fp
1429 is an open file, and
1430 .I x_op
1431 is an XDR direction.
1432 .NH 3
1433 \&Memory Streams
1434 .IX "XDR" "memory streams"
1435 .LP
1436 Memory streams allow the streaming of data into or out of
1437 a specified area of memory:
1438 .DS
1439 .ft CW
1440 #include <rpc/rpc.h>
1441 .sp .5
1442 void
1443 xdrmem_create(xdrs, addr, len, x_op)
1444     XDR *xdrs;
1445     char *addr;
1446     u_int len;
1447     enum xdr_op x_op;
1448 .DE
1449 The routine
1450 .I xdrmem_create() 
1451 .IX xdrmem_create() "" \fIxdrmem_create()\fP
1452 initializes an XDR stream in local memory.
1453 The memory is pointed to by parameter
1454 .I addr ;
1455 parameter
1456 .I len
1457 is the length in bytes of the memory.
1458 The parameters
1459 .I xdrs
1460 and
1461 .I x_op
1462 are identical to the corresponding parameters of
1463 .I xdrstdio_create ().
1464 Currently, the UDP/IP implementation of RPC uses
1465 .I xdrmem_create ().
1466 Complete call or result messages are built in memory before calling the
1467 .I sendto() 
1468 system routine.
1469 .NH 3
1470 \&Record (TCP/IP) Streams
1471 .IX "XDR" "record (TCP/IP) streams"
1472 .LP
1473 A record stream is an XDR stream built on top of
1474 a record marking standard that is built on top of the
1475 UNIX file or 4.2 BSD connection interface.
1476 .DS
1477 .ft CW
1478 #include <rpc/rpc.h>    /* \fIxdr streams part of rpc\fP */
1479 .sp .5
1480 xdrrec_create(xdrs,
1481   sendsize, recvsize, iohandle, readproc, writeproc)
1482     XDR *xdrs;
1483     u_int sendsize, recvsize;
1484     char *iohandle;
1485     int (*readproc)(), (*writeproc)();
1486 .DE
1487 The routine
1488 .I xdrrec_create() 
1489 provides an XDR stream interface that allows for a bidirectional,
1490 arbitrarily long sequence of records.
1491 The contents of the records are meant to be data in XDR form.
1492 The stream's primary use is for interfacing RPC to TCP connections.
1493 However, it can be used to stream data into or out of normal
1494 UNIX files.
1495 .LP
1496 The parameter
1497 .I xdrs
1498 is similar to the corresponding parameter described above.
1499 The stream does its own data buffering similar to that of standard I/O.
1500 The parameters
1501 .I sendsize
1502 and
1503 .I recvsize
1504 determine the size in bytes of the output and input buffers, respectively;
1505 if their values are zero (0), then predetermined defaults are used.
1506 When a buffer needs to be filled or flushed, the routine
1507 .I readproc() 
1508 or
1509 .I writeproc() 
1510 is called, respectively.
1511 The usage and behavior of these
1512 routines are similar to the UNIX system calls
1513 .I read() 
1514 and
1515 .I write ().
1516 However,
1517 the first parameter to each of these routines is the opaque parameter
1518 .I iohandle .
1519 The other two parameters
1520 .I buf ""
1521 and
1522 .I nbytes )
1523 and the results
1524 (byte count) are identical to the system routines.
1525 If
1526 .I xxx 
1527 is
1528 .I readproc() 
1529 or
1530 .I writeproc (),
1531 then it has the following form:
1532 .DS
1533 .ft CW
1534 .ft I
1535 /*
1536  * returns the actual number of bytes transferred.
1537  * -1 is an error
1538  */
1539 .ft CW
1540 int
1541 xxx(iohandle, buf, len)
1542     char *iohandle;
1543     char *buf;
1544     int nbytes;
1545 .DE
1546 The XDR stream provides means for delimiting records in the byte stream.
1547 The implementation details of delimiting records in a stream are
1548 discussed in the
1549 .I "Advanced Topics"
1550 topic below.
1551 The primitives that are specific to record streams are as follows:
1552 .DS
1553 .ft CW
1554 bool_t
1555 xdrrec_endofrecord(xdrs, flushnow)
1556     XDR *xdrs;
1557     bool_t flushnow;
1558 .sp .5
1559 bool_t
1560 xdrrec_skiprecord(xdrs)
1561     XDR *xdrs;
1562 .sp .5
1563 bool_t
1564 xdrrec_eof(xdrs)
1565     XDR *xdrs;
1566 .DE
1567 The routine
1568 .I xdrrec_endofrecord() 
1569 .IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fP
1570 causes the current outgoing data to be marked as a record.
1571 If the parameter
1572 .I flushnow
1573 is
1574 .I TRUE ,
1575 then the stream's
1576 .I writeproc 
1577 will be called; otherwise,
1578 .I writeproc 
1579 will be called when the output buffer has been filled.
1580 .LP
1581 The routine
1582 .I xdrrec_skiprecord() 
1583 .IX xdrrec_skiprecord() "" \fIxdrrec_skiprecord()\fP
1584 causes an input stream's position to be moved past
1585 the current record boundary and onto the
1586 beginning of the next record in the stream.
1587 .LP
1588 If there is no more data in the stream's input buffer,
1589 then the routine
1590 .I xdrrec_eof() 
1591 .IX xdrrec_eof() "" \fIxdrrec_eof()\fP
1592 returns
1593 .I TRUE .
1594 That is not to say that there is no more data
1595 in the underlying file descriptor.
1596 .NH 2
1597 \&XDR Stream Implementation
1598 .IX "XDR" "stream implementation"
1599 .IX "stream implementation in XDR"
1600 .LP
1601 This section provides the abstract data types needed
1602 to implement new instances of XDR streams.
1603 .NH 3
1604 \&The XDR Object
1605 .IX "XDR" "object"
1606 .LP
1607 The following structure defines the interface to an XDR stream:
1608 .ie t .DS
1609 .el .DS L
1610 .ft CW
1611 enum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };
1612 .sp .5
1613 typedef struct {
1614     enum xdr_op x_op;            /* \fIoperation; fast added param\fP */
1615     struct xdr_ops {
1616         bool_t  (*x_getlong)();  /* \fIget long from stream\fP */
1617         bool_t  (*x_putlong)();  /* \fIput long to stream\fP */
1618         bool_t  (*x_getbytes)(); /* \fIget bytes from stream\fP */
1619         bool_t  (*x_putbytes)(); /* \fIput bytes to stream\fP */
1620         u_int   (*x_getpostn)(); /* \fIreturn stream offset\fP */
1621         bool_t  (*x_setpostn)(); /* \fIreposition offset\fP */
1622         caddr_t (*x_inline)();   /* \fIptr to buffered data\fP */
1623         VOID    (*x_destroy)();  /* \fIfree private area\fP */
1624     } *x_ops;
1625     caddr_t     x_public;        /* \fIusers' data\fP */
1626     caddr_t     x_private;       /* \fIpointer to private data\fP */
1627     caddr_t     x_base;          /* \fIprivate for position info\fP */
1628     int         x_handy;         /* \fIextra private word\fP */
1629 } XDR;
1630 .DE
1631 The
1632 .I x_op
1633 field is the current operation being performed on the stream.
1634 This field is important to the XDR primitives,
1635 but should not affect a stream's implementation.
1636 That is, a stream's implementation should not depend
1637 on this value.
1638 The fields
1639 .I x_private ,
1640 .I x_base ,
1641 and
1642 .I x_handy
1643 are private to the particular
1644 stream's implementation.
1645 The field
1646 .I x_public
1647 is for the XDR client and should never be used by
1648 the XDR stream implementations or the XDR primitives.
1649 .I x_getpostn() ,
1650 .I x_setpostn()
1651 and
1652 .I x_destroy()
1653 are macros for accessing operations.  The operation
1654 .I x_inline()
1655 takes two parameters:
1656 an XDR *, and an unsigned integer, which is a byte count.
1657 The routine returns a pointer to a piece of
1658 the stream's internal buffer.
1659 The caller can then use the buffer segment for any purpose.
1660 From the stream's point of view, the bytes in the
1661 buffer segment have been consumed or put.
1662 The routine may return
1663 .I NULL 
1664 if it cannot return a buffer segment of the requested size.
1665 (The
1666 .I x_inline() 
1667 routine is for cycle squeezers.
1668 Use of the resulting buffer is not data-portable.
1669 Users are encouraged not to use this feature.) 
1670 .LP
1671 The operations
1672 .I x_getbytes()
1673 and
1674 .I x_putbytes()
1675 blindly get and put sequences of bytes
1676 from or to the underlying stream;
1677 they return
1678 .I TRUE 
1679 if they are successful, and
1680 .I FALSE 
1681 otherwise.  The routines have identical parameters (replace
1682 .I xxx ):
1683 .DS
1684 .ft CW
1685 bool_t
1686 xxxbytes(xdrs, buf, bytecount)
1687         XDR *xdrs;
1688         char *buf;
1689         u_int bytecount;
1690 .DE
1691 The operations
1692 .I x_getlong()
1693 and
1694 .I x_putlong()
1695 receive and put
1696 long numbers from and to the data stream.
1697 It is the responsibility of these routines
1698 to translate the numbers between the machine representation
1699 and the (standard) external representation.
1700 The UNIX primitives
1701 .I htonl()
1702 and
1703 .I ntohl()
1704 can be helpful in accomplishing this.
1705 The higher-level XDR implementation assumes that
1706 signed and unsigned long integers contain the same number of bits,
1707 and that nonnegative integers
1708 have the same bit representations as unsigned integers.
1709 The routines return
1710 .I TRUE
1711 if they succeed, and
1712 .I FALSE 
1713 otherwise.  They have identical parameters:
1714 .DS
1715 .ft CW
1716 bool_t
1717 xxxlong(xdrs, lp)
1718         XDR *xdrs;
1719         long *lp;
1720 .DE
1721 Implementors of new XDR streams must make an XDR structure
1722 (with new operation routines) available to clients,
1723 using some kind of create routine.
1724 .NH 1
1725 \&Advanced Topics
1726 .IX XDR "advanced topics"
1727 .LP
1728 This section describes techniques for passing data structures that
1729 are not covered in the preceding sections.  Such structures include
1730 linked lists (of arbitrary lengths).  Unlike the simpler examples
1731 covered in the earlier sections, the following examples are written
1732 using both the XDR C library routines and the XDR data description 
1733 language.  
1734 The
1735 .I "External Data Representation Standard: Protocol Specification"
1736 describes this 
1737 language in complete detail.
1738 .NH 2
1739 \&Linked Lists
1740 .IX XDR "linked lists"
1741 .LP
1742 The last example in the
1743 .I Pointers
1744 topic earlier in this chapter 
1745 presented a C data structure and its associated XDR
1746 routines for a individual's gross assets and liabilities.  
1747 The example is duplicated below:
1748 .ie t .DS
1749 .el .DS L
1750 .ft CW
1751 struct gnumbers {
1752         long g_assets;
1753         long g_liabilities;
1754 };
1755 .sp .5
1756 bool_t
1757 xdr_gnumbers(xdrs, gp)
1758         XDR *xdrs;
1759         struct gnumbers *gp;
1760 {
1761         if (xdr_long(xdrs, &(gp->g_assets)))
1762                 return(xdr_long(xdrs, &(gp->g_liabilities)));
1763         return(FALSE);
1764 }
1765 .DE
1766 .LP
1767 Now assume that we wish to implement a linked list of such information. 
1768 A data structure could be constructed as follows:
1769 .ie t .DS
1770 .el .DS L
1771 .ft CW
1772 struct gnumbers_node {
1773         struct gnumbers gn_numbers;
1774         struct gnumbers_node *gn_next;
1775 };
1776 .sp .5
1777 typedef struct gnumbers_node *gnumbers_list;
1778 .DE
1779 .LP
1780 The head of the linked list can be thought of as the data object;
1781 that is, the head is not merely a convenient shorthand for a
1782 structure.  Similarly the 
1783 .I gn_next 
1784 field is used to indicate whether or not the object has terminated.  
1785 Unfortunately, if the object continues, the 
1786 .I gn_next 
1787 field is also the address of where it continues. The link addresses 
1788 carry no useful information when the object is serialized.
1789 .LP
1790 The XDR data description of this linked list is described by the 
1791 recursive declaration of 
1792 .I gnumbers_list :
1793 .ie t .DS
1794 .el .DS L
1795 .ft CW
1796 struct gnumbers {
1797         int g_assets;
1798         int g_liabilities;
1799 };
1800 .sp .5
1801 struct gnumbers_node {
1802         gnumbers gn_numbers;
1803         gnumbers_node *gn_next;
1804 };
1805 .DE
1806 .LP
1807 In this description, the boolean indicates whether there is more data
1808 following it. If the boolean is 
1809 .I FALSE ,
1810 then it is the last data field of the structure. If it is 
1811 .I TRUE ,
1812 then it is followed by a gnumbers structure and (recursively) by a 
1813 .I gnumbers_list .
1814 Note that the C declaration has no boolean explicitly declared in it 
1815 (though the 
1816 .I gn_next 
1817 field implicitly carries the information), while the XDR data 
1818 description has no pointer explicitly declared in it.
1819 .LP
1820 Hints for writing the XDR routines for a 
1821 .I gnumbers_list 
1822 follow easily from the XDR description above. Note how the primitive 
1823 .I xdr_pointer() 
1824 is used to implement the XDR union above.
1825 .ie t .DS
1826 .el .DS L
1827 .ft CW
1828 bool_t
1829 xdr_gnumbers_node(xdrs, gn)
1830         XDR *xdrs;
1831         gnumbers_node *gn;
1832 {
1833         return(xdr_gnumbers(xdrs, &gn->gn_numbers) &&
1834                 xdr_gnumbers_list(xdrs, &gp->gn_next));
1835 }
1836 .sp .5
1837 bool_t
1838 xdr_gnumbers_list(xdrs, gnp)
1839         XDR *xdrs;
1840         gnumbers_list *gnp;
1841 {
1842         return(xdr_pointer(xdrs, gnp, 
1843                 sizeof(struct gnumbers_node), 
1844                 xdr_gnumbers_node));
1845 }
1846 .DE
1847 .LP
1848 The unfortunate side effect of XDR'ing a list with these routines
1849 is that the C stack grows linearly with respect to the number of
1850 node in the list.  This is due to the recursion. The following
1851 routine collapses the above two mutually recursive into a single,
1852 non-recursive one.
1853 .ie t .DS
1854 .el .DS L
1855 .ft CW
1856 bool_t
1857 xdr_gnumbers_list(xdrs, gnp)
1858         XDR *xdrs;
1859         gnumbers_list *gnp;
1860 {
1861         bool_t more_data;
1862         gnumbers_list *nextp;
1863 .sp .5
1864         for (;;) {
1865                 more_data = (*gnp != NULL);
1866                 if (!xdr_bool(xdrs, &more_data)) {
1867                         return(FALSE);
1868                 }
1869                 if (! more_data) {
1870                         break;
1871                 }
1872                 if (xdrs->x_op == XDR_FREE) {
1873                         nextp = &(*gnp)->gn_next;
1874                 }
1875                 if (!xdr_reference(xdrs, gnp, 
1876                         sizeof(struct gnumbers_node), xdr_gnumbers)) {
1877
1878                 return(FALSE);
1879                 }
1880                 gnp = (xdrs->x_op == XDR_FREE) ? 
1881                         nextp : &(*gnp)->gn_next;
1882         }
1883         *gnp = NULL;
1884         return(TRUE);
1885 }
1886 .DE
1887 .LP
1888 The first task is to find out whether there is more data or not,
1889 so that this boolean information can be serialized. Notice that
1890 this statement is unnecessary in the 
1891 .I XDR_DECODE 
1892 case, since the value of more_data is not known until we 
1893 deserialize it in the next statement.
1894 .LP
1895 The next statement XDR's the more_data field of the XDR union. 
1896 Then if there is truly no more data, we set this last pointer to 
1897 .I NULL 
1898 to indicate the end of the list, and return 
1899 .I TRUE 
1900 because we are done. Note that setting the pointer to 
1901 .I NULL 
1902 is only important in the 
1903 .I XDR_DECODE 
1904 case, since it is already 
1905 .I NULL 
1906 in the 
1907 .I XDR_ENCODE 
1908 and 
1909 XDR_FREE 
1910 cases.
1911 .LP
1912 Next, if the direction is 
1913 .I XDR_FREE ,
1914 the value of 
1915 .I nextp 
1916 is set to indicate the location of the next pointer in the list. 
1917 We do this now because we need to dereference gnp to find the 
1918 location of the next item in the list, and after the next 
1919 statement the storage pointed to by
1920 .I gnp 
1921 will be freed up and no be longer valid.  We can't do this for all
1922 directions though, because in the 
1923 .I XDR_DECODE 
1924 direction the value of 
1925 .I gnp 
1926 won't be set until the next statement.
1927 .LP
1928 Next, we XDR the data in the node using the primitive 
1929 .I xdr_reference ().
1930 .I xdr_reference() 
1931 is like 
1932 .I xdr_pointer() 
1933 which we used before, but it does not
1934 send over the boolean indicating whether there is more data. 
1935 We use it instead of 
1936 .I xdr_pointer() 
1937 because we have already XDR'd this information ourselves. Notice 
1938 that the xdr routine passed is not the same type as an element 
1939 in the list. The routine passed is 
1940 .I xdr_gnumbers (),
1941 for XDR'ing gnumbers, but each element in the list is actually of 
1942 type 
1943 .I gnumbers_node .
1944 We don't pass 
1945 .I xdr_gnumbers_node() 
1946 because it is recursive, and instead use 
1947 .I xdr_gnumbers() 
1948 which XDR's all of the non-recursive part.  Note that this trick 
1949 will work only if the 
1950 .I gn_numbers 
1951 field is the first item in each element, so that their addresses 
1952 are identical when passed to 
1953 .I xdr_reference ().
1954 .LP
1955 Finally, we update 
1956 .I gnp 
1957 to point to the next item in the list. If the direction is 
1958 .I XDR_FREE ,
1959 we set it to the previously saved value, otherwise we can 
1960 dereference 
1961 .I gnp 
1962 to get the proper value.  Though harder to understand than the 
1963 recursive version, this non-recursive routine is far less likely
1964 to blow the C stack.  It will also run more efficiently since
1965 a lot of procedure call overhead has been removed. Most lists 
1966 are small though (in the hundreds of items or less) and the 
1967 recursive version should be sufficient for them.
1968 .EQ
1969 delim off
1970 .EN