AutoXDR - Automated XDR Interfaces


Abstract

This paper describes several enhancements to rpcgen designed to facilitate the implementation of both traditional RPC programs and also RPC programs with combinable RPC calls.

This proposal is based on RFCs 1831 and 1832 (RPC and XDR).


Motivation

NFSv4 defines a new RPC interface with 38 procedure calls defined. However, one is the NULL procedure and a second is the carrier procedure for the remaining 36. That means that, as it stands, the authors of the client and server procedures that support these 36 calls must manage the marshaling and unmarshaling of their data into and out of the structures used by the carrier procedure. This proposal augments the functionality of RPCGEN such that the NFSv4 implementers, or the implementers of any other protocol so conceived, shall not deal with such bookkeeping.

This proposal maintains binary compatibility with the proposed NFSv4 standard. Any variations are bugs.

Approach

This all could have been written without modifying the NFS4 XDR and, instead, just writing libraries specific to the NFS4 and NFS4-CB programs. However, modifying RPCGEN was rejected because it would have taken a lot of work and there is already a tool that makes it relatively simple to do the text expansions. With this tool and a small amount of added work, it has been possible to generate the code to produce these additional interfaces.

Terminology

The following terms are used throughout:

carrier procedure
This is a procedure that sends multiple queued procedure calls at once. It is implemented with two calls. An "init" call that will allocate data structures, and a "send" call to send the queued calls and receive the multiple results.

queued procedure calls
These are procedure calls that are not sent immediately. They are queued and sent when its carrier procedure's "send" function is invoked.

queued procedure callback
When the carrier procedure receives its results, each of the queued procedure calls had a callback procedure registered. If the registered procedure address is not NULL, it will be called with the complete argument list, input *and* output.

AutoXDR's Major functions

XDR Changes

The implementation requires several changes to the way the XDR data and RPC programs get defined. Principally, there are some data that must be operated on by both the XDR compiler (rpcgen) and by this new tool (AutoXDR). Rather than duplicate the information, these common data are now expressed in a way that AutoGen can understand and it will produce both the new files, and the traditional XDR file. There are also a few additional bits of information that are needed by AutoGen for the XDR templates, but not specifiable in the ONC IDL.

This is a summary of the changes. Greater detail on the requirements for the AutoGen definitions file can be found in the example definitions file.

  1. Only one program may be defined at a time. If two different programs have a lot of common data structures, then the common data can be specified in a common definition file that is included by both of the programs' AutoXDR definiton files.

    If you compile code that references both of these programs, you will need to be careful and protect the data structures with something like:

    #if defined( RPC_HDR )
    %#ifndef HAVE_XDR_DATA_
    %#define HAVE_XDR_DATA_
    
    #elif defined( RPC_XDR )
    %#ifndef HAVE_XDR_PROCS_
    %#define HAVE_XDR_PROCS_
    #endif
    
  2. The program specification must not be supplied. Instead, you must use AutoGen definition syntax to provide values for program, prog_id and one or more copies of prog_version. You will find these definitions very similar to the original definitions.

  3. The program must define the name of the status enumeration. This is done by providing a definition for status_enum, such as:
    status_enum = "nfs4_status";
    
  4. As with ONC's IDL, the procedures are defined as part of the compound version (prog_version) definitions. Each defined procedure must have a p_name defined, and may have zero, one or more arguments (p_arg) defined.

  5. Each argument must have an object type (def_type), a name (def_name) and a usage (in, out or i_o attribute) defined. If the argument is normally passed by value (a scalar), no passing type is specified. If the argument is a fixed-length array, then it must have the array attribute. Otherwise, the argument should be a structure that is passed by reference and must have the ref attribute.

  6. Queued procedures are members of carrier procedure definitions. They are defined as a p_op attribute(s) to the carrier procedure. The arguments to a queueing procedure are specified exactly the same way as the arguments to normal procedures, except they are each named op_arg.

  7. Special enumerations (especially the error status enumeration) can be specified in a way that will cause translation routines to be emitted. Here is a trivial examle from NFSv4:
    /*
     * Error status
     */
    enum = {
      en_name = status;
      en_ent[    0] = { ename = OK;
                        etype = "successful completion"; };
      en_ent[    1] = { ename = PERM;
         etype = "caller is either not privileged or not owner"; };
      en_ent[    2] = { ename = NOENT;
                        etype = "No such file or directory"; };
      en_ent[  256] = { ename = OMITTED;
                        etype = "operation omitted"; };
    };
    
    The enumeration for zero (0) is omitted.

  8. All other XDR data are passed through the AutoGen definitions by setting one or more copies of xdr_data to the text to be passed through.


Example definitions and output

Below are brief descriptions of the AutoXDR relevant files and links to longer descriptions with brief examples. The examples are based on a tiny fragment of the NFSv4 specification.

Definitions
A description of the AutoGen definitions that are used by AutoXDR. This and the example test program below are the only files that are hand edited. The remainder are generated for you.

Client code
This is the generated code that collects the arguments for the queued procedures and marshals the arguments into and out of structures for the clnt_call routine.

Client header
This is a generated file that declares the enumeration procedures and, for queued procedures, the types of the queued procedure callbacks and the procedure prototypes for the queueing procedures.

Server code
This is the generated code that handles the NULL procedure and the servicing of the queued procedures. It will process the calls until a threshold result code is exceeded. The default threshold is 0. This file is not produced if there are no carrier procedures.

Server header
This is a generated file that declares the queued service routines that the server side code will call. This file is not produced if there are no carrier procedures.

Enum translator
This is the generated code that translates enumerations into strings and back. It can be used on either the client or server side, but the interface is declared in the client header.

XDR IDL
This is the ONC IDL or XDR file.

Debug & Startup Code
There are several debug and start up files that get generated. The referenced page shows an example of the debug code only.

*-debug.c
This is a debug version substitution for the normal client code (*-client.c). It will directly call the server code so that you can debug the protocol in a single process. With this module, the XDR routines from rpcgen and the server code, you have all the glue you need to debug your RPC program inside of a single process.

*-clmain.c
This is a template file that can be used to start development of the client. It includes code that will call every procedure once and, if there are queued procedure calls, the callback procedures are generated and thecarrier procedure's init and send procedures are called at the right time. You should rename the file, if you choose to edit it. Otherwise, it will be overwritten whenever these files are regenerated.

*-svstub.c
This file contains stub procedures for the server side. They will all ignore their input arguments, print a message to stderr and return success. Similar to the *-clmain.c file, you should rename this file before editing it.


Example Test
If you compile this module and link it with the Debug Procedures, the Server code and the rpcgen-ed XDR module, you will have a fully functional program that tests out this example interface. e.g.:
  $(CC) -o rpctest rpctest.o nfsv4-debug.o nfsv4-server.o nfsv4_xdr.o


Viewable With Any Browser


AutoGen, AutoOpts, columns, getdefs, AutoFSM, AutoXDR and these web pages copyright (c) 1999, 2000, 2001 Bruce Korb, all rights reserved.

AutoXDR copyright (c) 2000 Bruce Korb, all rights reserved.