Chapter 7. XDR and RPC Language Structure
Prev |  | Next

## Chapter 7. XDR and RPC Language Structure

This chapter describes the XDR and RPC languages. Topics include:

- XDR language structure, syntax, and examples

- RPC language structure, syntax, and examples

  | Note: For an overview of the relationship between the RPC and XDR languages and the RPC interface, see Chapter 4, “Introduction to RPC Programming”. For information about `rpcgen`, see Chapter 5, “Programming with rpcgen”. For information about RPC programming, see Chapter 6, “RPC Programming Guide”. For technical details about XDR, see Chapter 8, “XDR Programming Notes”. For complete specifications of the RPC and XDR protocols, see Appendix A, “RPC Protocol Specification” and Appendix B, “XDR Protocol Specification”.

## XDR Language

This section describes the components of the XDR language.

### Notational Conventions

This specification uses an extended Backus-Naur Form notation for describing the XDR language. This notation has the following characteristics:

- These are the special characters:

  `| ( ) [ ] " *`

- Terminal symbols are strings of any characters surrounded by double quotes (`" "`).

- Nonterminal symbols are strings of non-special characters.

- Alternative items are separated by a vertical bar (`|`).

- Optional items are enclosed in brackets (`[]`).

- Items are grouped by enclosing them in parentheses (`( )`).

- An asterisk (`*`) following an item means zero or more occurrences of that item.

For example, consider this pattern:

    "a" "very" ("," "very")* ["cold" "and"]  "rainy" ("day" | "night")

An infinite number of strings match this pattern; for example:

    "a very rainy day"
    "a very, very rainy day"
    "a very cold and rainy day"
    "a very, very, very cold and rainy night"

### Lexical Notes

This section discusses some lexical features of the XDR language:

- Comments begin with /* and end with */. For example:

  `/* comment */`

- White space separates items and is otherwise ignored.

- An identifier is a letter followed by an optional sequence of letters, digits, or an underscore (`_`). The case of identifiers is not ignored.

- A constant is a sequence of one or more decimal digits, optionally preceded by a minus sign (`–`).

### Syntax Information

This section describes XDR language syntax:

    declaration:
        type-specifier identifier
        | type-specifier identifier "[" value "]"
        | type-specifier identifier "<" [ value ] ">"
        | "opaque" identifier "[" value "]"
        | "opaque" identifier "<" [ value ] ">"
        | "string" identifier "<" [ value ] ">"
        | type-specifier "*" identifier
        | "void"
    value:
        constant
        | identifier
    type-specifier:
          [ "unsigned" ] "int"
        | [ "unsigned" ] "hyper"
        | "float"
        | "double"
        | "bool"
        | enum-type-spec
        | struct-type-spec
        | union-type-spec
        | identifier
    enum-type-spec:
        "enum" enum-body
    enum-body:
        "{"
        ( identifier "=" value )
        ( "," identifier "=" value )*
        "}"
    struct-type-spec:
        "struct" struct-body
    struct-body:
        "{"
        ( declaration ";" )
        ( declaration ";" )*
        "}"
    union-type-spec:
        "union" union-body
    union-body:
        "switch" "(" declaration ")" "{"
        ( "case" value ":" declaration ";" )
        ( "case" value ":" declaration ";" )*
        [ "default" ":" declaration ";" ]
        "}"
    constant-def:
        "const" identifier "=" constant ";"
    type-def:
        "typedef" declaration ";"
        | "enum" identifier enum-body ";"
        | "struct" identifier struct-body ";"
        | "union" identifier union-body ";"
    definition:
        type-def
        | constant-def
    specification:
        definition *

### Syntax Notes

This section provides additional information about XDR language syntax:

- The following keywords cannot be used as identifiers:

      bool        double      opaque    typedef
      case        enum        string    union
      const       float       struct    unsigned
      default     hyper       switch    void

- Only unsigned constants may be used as size specifications for arrays. If an identifier is used, it must have been declared previously as an unsigned constant in a const definition.

- Constant and type identifiers within the scope of a specification are in the same name space and must be declared uniquely within this scope.

- Similarly, variable names must be unique within the scope of struct and union declarations. Nested struct and union declarations create new scopes.

- The discriminant of a union must be of a type that evaluates to an integer. That is, int, unsigned int, bool, an enumerated type, or any `typedef` type that evaluates to one of these is legal. Also, the `case` values must be one of the legal values of the discriminant. Finally, a `case` value may not be specified more than once within the scope of a union declaration.

### XDR Data Description Example

The following is a short XDR data description of a “file” that you might use to transfer files from one machine to another:

    const MAXUSERNAME = 32;    /* max length of a user name */
    const MAXFILELEN = 65535;  /* max length of a file */
    const MAXNAMELEN = 255;    /* max length of a filename */

    /* Types of files: */
    enum filekind {
        TEXT = 0,            /* ascii data */
        DATA = 1,            /* raw data */
        EXEC = 2             /* executable */
    };

    /* File information, per kind of file: */
    union filetype switch (filekind kind) {
        case TEXT:
          void;                /* no extra information */
        case DATA:
          string creator<MAXNAMELEN>;   /* data creator */
        case EXEC:
          string interpreter<MAXNAMELEN>;/*program interpreter*/
    };

    /* A complete file: */
    struct file {
        string filename<MAXNAMELEN>;    /* name of file */
        filetype type;                  /* info about file */
        string owner<MAXUSERNAME>;      /* owner of file */
        opaque data<MAXFILELEN>;        /* file data  */
    };

Suppose that a user named jean wants to store a LISP program `sillyprog`, which contains just the data “(quit).” The file would be encoded as shown in Table 7-1.

Table 7-1. DR Data Encoding Examples

Offset | Hex Bytes | ASCII | Description
--- | --- | --- | ---
0 | 00 00 00 09 | .... | Length of filename = 9
4 | 73 69 6c 6c | sill | Filename characters
8 | 79 70 72 6 | ypro | More filename characters
12 | 67 00 00 00 | g... | The last filename character plus 3 zero-bytes of fill
16 | 00 00 00 02 | .... | File kind is EXEC = 2
20 | 00 00 00 04 | .... | Length of interpreter name = 4
24 | 6c 69 73 70 | lisp | Interpreter name
28 | 00 00 00 04 | .... | Length of owner name = 4
32 | 6a 65 61 6e | jean | Owner name
36 | 00 00 00 06 | .... | Length of data = 6
40 | 28 71 75 69 | (qui | File data bytes
44 | 74 29 00 00 | t).. | More data plus 2 zero-bytes of fill

## RPC Language

RPC language is an extension of the XDR language; the sole extension is the addition of the program type.

### Definitions

An RPC language file consists of a series of definitions:

    definition-list:
        definition ";"
        definition ";" definition-list

It recognizes six types of definition:

    definition:
        enum-definition
        struct-definition
        union-definition
        typedef-definition
        const-definition
        program-definition

### Structures

An XDR structure is declared almost exactly like its C counterpart:

    struct-definition:
        "struct" struct-ident "{"
            declaration-list
        "}"

    declaration-list:
        declaration ";"
        declaration ";" declaration-list

For example, the following code is an XDR structure for a two–dimensional coordinate and the C structure into which it is compiled in the output header file:

    struct coord {          struct coord {
        int x;       -->        int x;
        int y;                  int y;
    };                      };
                            typedef struct coord coord;

The output is identical to the input, except for the added `typedef` at the end of the output. Using `typedef` allows you to use coord instead of struct coord when declaring items.

### Unions

XDR unions are discriminated unions, and they look different from C unions. They are more analogous to Pascal variant records than they are to C unions:

    union-definition:
        "union" union-ident "switch" "(" declaration ")" "{"
            case-list
        "}"
    case-list:
        "case" value ":" declaration ";"
        "default" ":" declaration ";"
        "case" value ":" declaration ";" case-list

The next example shows a type that might be returned as the result of a read data operation. If no error, return a block of data. Otherwise, return nothing.

    union read_result switch (int errno) {
    case 0:
        opaque data[1024];
    default:
        void;
    };

This code is compiled into:

    struct read_result {
        int errno;
        union {
            char data[1024];
        } read_result_u;
    };
    typedef struct read_result read_result;

Notice that the union component of the output struct has the name as the type name, except for the trailing _u.

### Enumerations

XDR enumerations have the same syntax as C enumerations:

    enum-definition:
        "enum" enum-ident "{"
            enum-value-list
        "}"

    enum-value-list:
        enum-value
        enum-value "," enum-value-list

    enum-value:
        enum-value-ident
        enum-value-ident "=" value

The XDR enum and the C enum are compiled into:

    enum colortype {          enum colortype {
        RED = 0,                  RED = 0,
        GREEN = 1,     -->        GREEN = 1,
        BLUE = 2                  BLUE = 2
    };                        };
                              typedef enum colortype colortype;

### Typedefs

An XDR `typedef` has the same syntax as a C `typedef`:

    typedef-definition:
        "typedef" declaration

The following example defines a fname_type used to declare filename strings that have a maximum length of 255 characters:

    typedef string fname_type<255>; --> typedef char *fname_type;

### Constants

XDR constants are symbolic constants. They may be used wherever an integer constant is used; for example, in array-size specifications:

    const-definition:
         "const" const-ident "=" integer

For example, the following defines a constant DOZEN equal to 12:

    const DOZEN = 12;  -->  #define DOZEN 12

### Programs

RPC programs are declared using this syntax:

    program-definition:
        "program" program-ident "{"
            version-list
        "}" "=" value

    version-list:
        version ";"
        version ";" version-list

    version:
        "version" version-ident "{"
            procedure-list
        "}" "=" value

    procedure-list:
        procedure ";"
        procedure ";" procedure-list

    procedure:
        type-ident procedure-ident "(" type-ident ")" "=" value

This example shows the time protocol, revisited:

    /*
     * time.x: Get or set the time. Time is represented as
     * number of seconds since 0:00, January 1, 1970.
     */
    program TIMEPROG {
        version TIMEVERS {
            unsigned int TIMEGET(void) = 1;
            void TIMESET(unsigned) = 2;
        } = 1;
    } = 44;

This file compiles into `#define`s in the output header file:

    #define TIMEPROG 44
    #define TIMEVERS 1
    #define TIMEGET 1
    #define TIMESET 2

### Declarations

There are four kinds of declaration in XDR:

- Simple declarations are like simple C declarations:

          simple-declaration:
              type-ident variable-ident

  For example:

          colortype color;    --> colortype color;

- Fixed-array declarations are like array declarations in C:

          fixed-array-declaration:
              type-ident variable-ident "[" value "]"

  For example:

          colortype palette[8];    --> colortype palette[8];

- Variable-array declarations have no explicit syntax in C, so XDR invents its own using angle brackets:

          variable-array-declaration:
              type-ident variable-ident "<" value ">"
              type-ident variable-ident "<" ">"

- The maximum size is specified between the angle brackets. The size may be omitted, indicating that the array may be of any size:

          int heights<12>;     /* at most 12 items */
          int widths<>;        /* any number of items */

- Since variable-length arrays have no explicit syntax in C, these declarations are actually compiled into structs. For example, the heights declaration gets compiled into the following struct:

          struct {
              u_int heights_len;       /* # of items in array */
              int *heights_val;        /* pointer to array */
          } heights;

- The number of items in the array is stored in the _len component, and the pointer to the array is stored in the _val component. The first part of each component's name is the same as the name of the declared XDR variable.

- Pointer declarations are made in XDR exactly as they are in C. You can't really send pointers over the network, but you can use XDR pointers to send recursive data types such as lists and trees. The type is actually called optional data, not pointer, in XDR language.

          pointer-declaration:
              type-ident "*" variable-ident

  For example:

          listitem *next;    -->    listitem *next;

### Special Cases

There are a few exceptions to the rules described in the preceding sections:

- Booleans

  C has no built-in boolean type. However, the RPC library does have a boolean type called bool_t that is either TRUE or FALSE. Things declared as type bool in XDR language are compiled into bool_t in the output header file. For example:

          bool married;    -->    bool_t married;

- Strings

  C has no built-in string type, but instead uses the null-terminated char * convention. In XDR language, strings are declared using the string keyword and are compiled into char *s in the output header file. The number contained in the angle brackets specifies the maximum number of characters allowed in the string (not counting the NULL character). The maximum size may be left off, indicating a string of arbitrary length. For example:

          string name<32>;      -->    char *name;
          string longname<>;    -->    char *longname;

- Opaque data

  Opaque data is used in RPC and XDR to describe untyped data; that is, just sequences of arbitrary bytes. Opaque data may be declared as either a fixed- or a variable-length array. For example:

          opaque diskblock[512];    -->    char diskblock[512];
          opaque filedata<1024>;    -->    struct {
                                              u_int filedata_len;
                                              char *filedata_val;
                                          } filedata;

- Voids

  In a void declaration, the variable is not named. The declaration is just void and nothing else. Void declarations can occur in only two places: union definitions and program definitions (as the argument or the result of a remote procedure).

Prev | Table of Contents | Next
Chapter 6. RPC Programming Guide |  | Chapter 8. XDR Programming Notes