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