XDR Technical Note
This appendix is a technical note on the Sun Microsystems implementation of the external data representation (XDR) standard, which is a set of library routines that enable C programmers to describe arbitrary data structures in a machine-independent manner.
What Is XDR?
XDR is the backbone of the Sun Microsystems Remote Procedure Call package. Data for RPCs are transmitted using this standard. XDR library routines should be used to transmit data accessed (read or written) by more than one type of machine.
XDR works across different languages, operating systems, and machine architectures. Most users (particularly RPC users) only need the information in the sections on number filters, floating point filters, and enumeration filters. Programmers who want to implement RPC and XDR on new machines should read this technical note and the protocol specification.
You can use rpcgen to write XDR routines even in cases where no RPC calls are being made.
C programs that use XDR routines must include the file <rpc/xdr.h>, which contains all the necessary interfaces to the XDR system. Because the library libnsl.a contains all the XDR routines, you compile it by typing:
example% cc program.c |
In many environments, several criteria must be observed to accomplish porting. The ramifications of a small programmatic change are not always apparent, but they can often have far-reaching implications. Consider the program to read/write a line of text that is shown in the next two code examples.
Example A-1 Writer Example (initial)
#include <stdio.h> main() /* writer.c */ { int i; for (i = 0; i < 8; i++) { if (fwrite((char *) &i, sizeof(i), 1, stdout) != 1) { fprintf(stderr, "failed!\n"); exit(1); } } exit(0); } |
Example A-2 Reader Example (initial)
The two programs appear to be portable because they:
Pass lint checking
Exhibit the same behavior when executed locally on any hardware architecture
Piping the output of the writer program to the reader program gives identical results on a SPARC or Intel machine.
sun% writer | reader 0 1 2 3 4 5 6 7 sun% intel% writer | reader 0 1 2 3 4 5 6 7 intel% |
With the advent of local area networks and 4.2BSD came the concept of "network pipes," which is a process that produces data on one machine and a second process that consumes data on another machine. You can construct a network pipe with writer and reader. Here are the results if the writer produces data on a SPARC system, and the reader consumes data on Intel architecture.
sun% writer | rsh intel reader 0 16777216 33554432 50331648 67108864 83886080 100663296 117440512 sun% |
Executing writer on the Intel and reader on the SPARC system produces identical results. These results occur because the byte ordering of data differs between the Intel and the SPARC, even though the word size is the same.
Note - 16777216 is 224. When 4 bytes are reversed, the 1 is placed in the 24th bit.
Whenever data is shared by two or more machine types, a need exists for portable data. You can make data portable by replacing the read() and write() calls with calls to an XDR library routine, xdr_int(), a filter that knows the standard representation of an int integer in its external form. The revised versions of writer are shown in the following code example.
Example A-3 Writer Example (XDR modified)
The following code example shows the revised versions of reader.
Example A-4 Reader Example (XDR modified)
The new programs were executed on a SPARC system, on an Intel, and from a SPARC to an Intel. The results follow.
sun% writer | reader 0 1 2 3 4 5 6 7 sun% intel% writer | reader 0 1 2 3 4 5 6 7 intel% sun% writer | rsh intel reader 0 1 2 3 4 5 6 7 sun% |
Note - Arbitrary data structures can create portability issues, particularly with respect to alignment and pointers. Alignment on word boundaries cause the size of a structure to vary from machine to machine. Pointers, which are very convenient to use, have no meaning outside the machine where they are defined.