OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [librpc/] [src/] [rpc/] [PSD.doc/] [xdr.nts.ms] - Blame information for rev 562

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.