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