|
|
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!)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.