Deleted Added
full compact
xdr.nts.ms (106143) xdr.nts.ms (108533)
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

--- 4 unchanged lines hidden (view full) ---

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

--- 4 unchanged lines hidden (view full) ---

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.

--- 52 unchanged lines hidden (view full) ---

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.

--- 52 unchanged lines hidden (view full) ---

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

--- 68 unchanged lines hidden (view full) ---

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

--- 68 unchanged lines hidden (view full) ---

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

--- 4 unchanged lines hidden (view full) ---

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

--- 4 unchanged lines hidden (view full) ---

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,

--- 7 unchanged lines hidden (view full) ---

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,

--- 7 unchanged lines hidden (view full) ---

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

--- 17 unchanged lines hidden (view full) ---

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

--- 17 unchanged lines hidden (view full) ---

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{

--- 63 unchanged lines hidden (view full) ---

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{

--- 63 unchanged lines hidden (view full) ---

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

--- 5 unchanged lines hidden (view full) ---

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

--- 5 unchanged lines hidden (view full) ---

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.

--- 47 unchanged lines hidden (view full) ---

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.

--- 47 unchanged lines hidden (view full) ---

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;

--- 4 unchanged lines hidden (view full) ---

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;

--- 4 unchanged lines hidden (view full) ---

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

--- 74 unchanged lines hidden (view full) ---

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

--- 74 unchanged lines hidden (view full) ---

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"

--- 19 unchanged lines hidden (view full) ---

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"

--- 19 unchanged lines hidden (view full) ---

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

--- 12 unchanged lines hidden (view full) ---

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

--- 12 unchanged lines hidden (view full) ---

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 };

--- 25 unchanged lines hidden (view full) ---

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 };

--- 25 unchanged lines hidden (view full) ---

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};

--- 9 unchanged lines hidden (view full) ---

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};

--- 9 unchanged lines hidden (view full) ---

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.

--- 5 unchanged lines hidden (view full) ---

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.

--- 5 unchanged lines hidden (view full) ---

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"

--- 25 unchanged lines hidden (view full) ---

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"

--- 25 unchanged lines hidden (view full) ---

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.

--- 10 unchanged lines hidden (view full) ---

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.

--- 10 unchanged lines hidden (view full) ---

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.

--- 4 unchanged lines hidden (view full) ---

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.

--- 4 unchanged lines hidden (view full) ---

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.

--- 23 unchanged lines hidden (view full) ---

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.

--- 23 unchanged lines hidden (view full) ---

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"

--- 56 unchanged lines hidden (view full) ---

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"

--- 56 unchanged lines hidden (view full) ---

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;

--- 15 unchanged lines hidden (view full) ---

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;

--- 15 unchanged lines hidden (view full) ---

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};

--- 4 unchanged lines hidden (view full) ---

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};

--- 4 unchanged lines hidden (view full) ---

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,

--- 15 unchanged lines hidden (view full) ---

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,

--- 15 unchanged lines hidden (view full) ---

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