Annotation of 43BSD/contrib/sunrpc/doc/xdr.spec, revision 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.