ONC+ Developer's Guide

What is XDR

XDR is the backbone of Sun Microsystems's Remote Procedure Call package, in the sense that 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 wanting to implement RPC and XDR on new machines will be interested in this technical note and the protocol specification.

rpcgen can be used 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. Since the library libnsl.a contains all the XDR routines, compile as follows:

example% cc program.c

In many environments, several criteria must be observed to accomplish porting. It is not always easy to see the ramifications of a small programmatic change, but they can often have far reaching implications. Consider the examples of a program to read/write a line of text, shown in Example A-1 and Example A-2.


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)

#include <stdio.h>

main()       /* reader.c */
{
 	int i, j;

	for (j = 0; j < 8; j++) {
 		if (fread((char *) &i, sizeof(i), 1, stdin) != 1) {
 			fprintf(stderr, "failed!\n");
 			exit(1);
 		}
 		printf("%ld ", i);
 	}
 	printf("\n");
 	exit(0);
}

The two programs appear to be portable, because (a) they pass lint checking, and (b) they 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 SPARC or Intel.

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. A network pipe can be constructed with writer and reader. Here are the results if the first produces data on a SPARC, and the second consumes data on Intel architecture.

sun% writer | rsh intel reader
0 16777216 33554432 50331648 67108864 83886080 100663296
117440512
sun%

Identical results can be obtained by executing writer on the Intel and reader on the SPARC. These results occur because the byte ordering of data differs between the Intel and the SPARC, even though word size is the same.


Note -

16777216 is 224. When four bytes are reversed, the 1 is placed in the 24th bit.


Whenever data is shared by two or more machine types, there is a need for portable data. Programs can be made 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 Example A-3.


Example A-3 Writer Example (XDR modified)

#include <stdio.h>
#include <rpc/rpc.h>	/* xdr is a sub-library of rpc */

main()       /* writer.c */
{
 	XDR xdrs;
 	int i;

xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
 	for (i = 0; i < 8; i++) {
 		if (!xdr_int(&xdrs, &i)) {
 			fprintf(stderr, "failed!\n");
 			exit(1);
 		}
 	}
 	exit(0);
}

Example A-4 shows the revised versions of reader.


Example A-4 Reader Example (XDR modified)

#include <stdio.h>
#include <rpc/rpc.h>	/* xdr is a sub-library of rpc */

main()                /* reader.c */
{
 	XDR xdrs;
 	int i, j;

xdrstdio_create(&xdrs, stdin, XDR_DECODE);
 	for (j = 0; j < 8; j++) {
 		if (!xdr_int(&xdrs, &i)) {
 			fprintf(stderr, "failed!\n");
 			exit(1);
 		}
 		printf("%ld ", i);
 	}
 	printf("\n");
 	exit(0);
}

The new programs were executed on a SPARC, on an Intel, and from a SPARC to an Intel; the results are shown below.

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 -

Integers are just the tip of the portable-data iceberg. Arbitrary data structures present portability problems, particularly with respect to alignment and pointers. Alignment on word boundaries may cause the size of a structure to vary from machine to machine. And pointers, which are very convenient to use, have no meaning outside the machine where they are defined.