Annotation of 43BSDReno/lib/librpc/doc/xdr.spec, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.