JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
ONC+ Developer's Guide     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

1.  Introduction to ONC+ Technologies

2.  Introduction to TI-RPC

3.  rpcgen Programming Guide

4.  Programmer's Interface to RPC

5.  Advanced RPC Programming Techniques

6.  Porting From TS-RPC to TI-RPC

7.  Multithreaded RPC Programming

8.  Extensions to the Oracle Solaris RPC Library

A.  XDR Technical Note

What Is XDR?

Canonical Standard

XDR Library

XDR Library Primitives

Memory Requirements for XDR Routines

Number Filters

Floating-Point Filters

Enumeration Filters

No-Data Routine

Constructed Data Type Filters

Strings

Byte Arrays

Arrays

Array Example 1

Array Example 2

Array Example 3

Opaque Data

Fixed-Length Arrays

Discriminated Unions

Discriminated Union Example

Pointers

Pointer Example

Pointer Semantics

Nonfilter Primitives

Operation Directions

Stream Access

Standard I/O Streams

Memory Streams

Record TCP/IP Streams

XDR Stream Implementation

XDR Object

Advanced XDR Topics

Linked Lists

B.  RPC Protocol and Language Specification

C.  XDR Protocol Specification

D.  RPC Code Examples

E.  portmap Utility

Glossary

Index

XDR Library

The XDR library solves data portability problems, and also enables you to write and read arbitrary C constructs in a consistent, specified, well-documented manner. Thus, using the library can be helpful even when the data is not shared among machines on a network.

The XDR library has filter routines for strings (null-terminated arrays of bytes), structures, unions, and arrays, to name a few. Using more primitive routines, you can write your own specific XDR routines to describe arbitrary data structures, including elements of arrays, arms of unions, or objects pointed at from other structures. The structures themselves might contain arrays of arbitrary elements, or pointers to other structures.

Look closely at Example A-3 and Example A-4. A family of XDR stream-creation routines has each member treat the stream of bits differently. In the example, data is manipulated using standard I/O routines, so you use xdrstdio_create(). The parameters to XDR stream-creation routines vary according to their function. In the example, xdrstdio_create() takes a pointer to an XDR structure that it initializes, a pointer to a FILE that the input or output is performed on, and the operation. The operation might be XDR_ENCODE for serializing in the writer program, or XDR_DECODE for deserializing in the reader program.


Note - RPC users never need to create XDR streams. The RPC system itself creates these streams, which are then passed to the users.


The xdr_int() primitive is characteristic of most XDR library primitives and all client XDR routines. First, the routine returns FALSE (0) if it fails, and TRUE (1) if it succeeds. Second, for each data type, xxx, there is an associated XDR routine of the form:

xdr_xxx(xdrs, xp)
   XDR *xdrs;
   xxx *xp;
{
}

In this case, xxx is int, and the corresponding XDR routine is a primitive, xdr_int(). The client could also define an arbitrary structure xxx, in which case the client would also supply the routine xdr_xxx(), describing each field by calling XDR routines of the appropriate type. In all cases the first parameter, xdrs, can be treated as an opaque handle and passed to the primitive routines.

An XDR routine is direction independent. That is, the same routine is called to serialize or deserialize data. This feature is critical to software engineering of portable data. The idea is to call the same routine for either operation. This practice almost guarantees that serialized data can also be deserialized.

This one routine is used by both producer and consumer of networked data. This concept is implemented by always passing the address of an object rather than the object itself. Only in the case of deserialization is the object modified. This feature is not shown in the example, but its value becomes obvious when nontrivial data structures are passed among machines. If needed, the user can obtain the direction of the XDR operation. For details, see the sectionOperation Directions.

A slightly more complicated example follows. Assume that a person's gross assets and liabilities are to be exchanged among processes. Also assume that these values are important enough to warrant their own data type.

struct gnumbers {
   int g_assets;
   int g_liabilities;
};

The corresponding XDR routine describing this structure is as follows.

bool_t                      /* TRUE is success, FALSE is failure */
xdr_gnumbers(xdrs, gp)
   XDR *xdrs;
   struct gnumbers *gp;
{
   if (xdr_int(xdrs, &gp->g_assets) &&
         xdr_int(xdrs, &gp->g_liabilities))
      return(TRUE);
   return(FALSE);
}

Note that the parameter xdrs is never inspected or modified. It is only passed on to the subcomponent routines. The routine must inspect the return value of each XDR routine call, and to halt immediately and return FALSE if the subroutine fails.

This example also shows that the type bool_t is declared as an integer that has only the values TRUE (1) and FALSE (0). This document uses the following definitions:

#define bool_t int
#define TRUE 1
#define FALSE 0

By observing these conventions, you can rewrite xdr_gnumbers() as follows:

xdr_gnumbers(xdrs, gp)
   XDR *xdrs;
   struct gnumbers *gp;
{
   return(xdr_int(xdrs, &gp->g_assets) &&
            xdr_int(xdrs, &gp->g_liabilities));
}

This document uses both coding styles.