RPCGEN(1) MachTen Programmer’s Manual RPCGEN(1)

NAME
rpcgen - an RPC protocol compiler

SYNOPSIS
rpcgen -h [-o outfile] [inputfile]
rpcgen -c [-o outfile] [infile]
rpcgen infile
rpcgen [-s transport]* [-o outfile] [infile]

DESCRIPTION
rpcgen is a tool that generates C code to implement an RPC
protocol. The input to rpcgen is a language with striking
similarity to C known as RPCL (Remote Procedure Call Lan-
guage). rpcgen operates in four modes. The first mode is
used to convert RPCL definitions into C definitions for
use as a header file. The second mode compiles the XDR
routines required to serialize the protocol described by
RPCL. The third mode compiles both, leaving the header
file in a file named infile with a .h extension and the
XDR routines in infile with a .c extension. The fourth
mode is used to compile an RPC server skeleton, so that
all you have to do is write local procedures that know
nothing about RPC in order to implement an RPC server.

The input may contain C-style comments and preprocessor
directives. Comments are ignored, while the directives
are simply stuffed uninterpreted in the output header
file.

You can customize some of your XDR routines by leaving
those data types undefined. For every data type that is
undefined, rpcgen will assume that there exists a routine
with the name ‘xdr_’ prepended to the name of the unde-
fined type.

OPTIONS
-c Compile XDR routines.

-h Compile C data-definitions (a header file)

-o outfile
Specify the name of the output file. If none is
specified, standard output is used (-c, -h and -s
modes only).

-s transport
Compile a server, using the the given transport.
The supported transports are udp and tcp. This
option may be invoked more than once so as to com-
pile a server that serves multiple transports.

USAGE
RPCL Syntax Summary
This summary of RPCL syntax, which is used for rpcgen
input, is intended more for aiding comprehension than as
an exact statement of the language.

Primitive Data Types
[ unsigned ] char unsigned
[ unsigned ] short float
[ unsigned ] int double
[ unsigned ] long void
bool
Except for the added boolean data-type bool, RPCL is iden-
tical to C. rpcgen converts bool declarations to int dec-
larations in the output header file (literally it is con-
verted to a bool_t, which has been #define’d to be an
int). Also, void declarations may appear only inside of
union and program definitions. For those averse to typing
the prefix unsigned, the abbreviations u_char, u_short,
u_int and u_long are available.

Declarations
RPCL allows only three kinds of declarations:

declaration:
simple-declaration
pointer-declaration
vector-declaration

simple-declaration:
type-name object-ident

pointer-declaration:
type-name *object-ident

vector-declaration:
type-name object-ident[size]

(size can be either an integer or a symbolic constant)

RPCL declarations contain both limitations and extensions
with respect to C. The limitations are that you cannot
declare multidimensional arrays or pointers-to-pointers
in-line (You can still declare them though, using type-
def). There are two extensions:

Opaque data is declared as a vector as follows:

opaque object-ident [ size ]

In the protocol, this results in an object of size
bytes. Note that this is not the same as a declara-
tion of size characters, since XDR characters are
32-bits. Opaque declarations are compiled in the
output header file into character array declara-
tions of size bytes.

Strings are special and are declared as a vector
declaration:

string object-ident [ max-size ]

If max-size is unspecified, then there is essen-
tially no limit to the maximum length of the
string. String declarations get compiled into the
following:

char *object-ident

Type Definitions
The only way to generate an XDR routine is to define a
type. For every type zetype you define, there is a corre-
sponding XDR routine named xdr_zetype.

There are six ways to define a type:

type-definition:
typedef
enumeration-def
structure-def
variable-length-array-def
discriminated-union-def
program-def

The first three are very similar to their C namesakes. C
does not have a formal type mechanism to define variable-
length arrays and XDR unions are quite different from
their C counterparts. Program definitions are not really
type definitions, but they are useful nonetheless.

You may not nest XDR definitions. For example, the fol-
lowing will cause rpcgen to choke:
struct dontdoit {
struct ididit {
int oops;
} sorry;
enum ididitagain { OOPS, WHOOPS } iapologize;
};

Typedefs
An XDR typedef looks as follows:

typedef:
typedef declaration ;
The object-ident part of declaration is the name of the
new type, whereas the type-name part is the name of the
type from which it is derived.

Enumeration Types
The syntax is:

enumeration-def:
enum enum-ident {
enum-list
};

enum-list:
enum-symbol-ident [ = assignment ]
enum-symbol-ident [ = assignment ] , enum-list

(assignment may be either an integer or a symbolic con-
stant)

If there is no explicit assignment, then the implicit
assignment is the value of the previous enumeration plus
1. If not explicitly assigned, the first enumeration
receives the value 0.

Structures
structure-def:
struct struct-ident {
declaration-list
};

declaration-list:
declaration ;
declaration ; declaration-list

Variable-Length Arrays
variable-length-array-def:
array array-ident {
unsigned length-identifer ;
vector-declaration ;
};

A variable length array definition looks much like a
structure definition. Here’s an example:
array mp_int {
unsigned len;
short val[MAX_MP_LENGTH];
};
This is compiled into:
struct mp_int {
unsigned len;
short *val;
};
typedef struct mp_int mp_int;

Disriminated Unions
discriminated-union-def:
union union-ident switch ( discriminant-declaration
) {
case-list
[ default : declaration ; ]
};

case-list:
case case-ident : declaration ;
case case-ident : declaration ; case-list

discriminant-declaration:
declaration

The union definition looks like a cross between a C-union
and a C-switch. An example:
union net_object switch (net_kind kind) {
case MACHINE:
struct sockaddr_in sin;
case USER:
int uid;
default:
string whatisit;
};
Compiles into:
struct net_object {
net_kind kind;
union {
struct sockaddr_in sin;
int uid;
char *whatisit;
} net_object;
};
typedef struct net_object net_object;
Note that the name of the union component of the output
struct is the same as the name of the type itself.

Program Definitions
program-def:
program program-ident {
version-list
} = program-number ;

version-list:
version
version version-list
version:
version version-ident {
procedure-list
} = version-number ;
procedure-list:
procedure-declaration
procedure-declaration procedure-list
procedure-declaration:
type-name procedure-ident ( type-name ) = proce-
dure-number ;

Program definitions look like nothing you’ve ever seen
before, so we turn to an example to explain them. Suppose
you wanted to create server that could get or set the
date. It’s declaration might look like this:
program DATE_PROG {
version DATE_VERS {
date DATE_GET(timezone) = 1;
void DATE_SET(date) = 2; /* Greenwich mean time */
} = 1;
} = 100;
In the header file, this compiles into the following:
#define DATE_PROG 100
#define DATE_VERS 1
#define DATE_GET 1
#define DATE_SET 2
These define’s are intended for use by the client program
to reference the remote procedures.

If you are using rpcgen to compile your server, then there
are some important things for you to know. The server
interfaces to your local procedures by expecting a C func-
tion with the same name as that in the program definition,
but in all lower-case letters and followed by the version
number. Here is the local procedure that implements
DATE_GET:
date * /* always returns a pointer to the results */
date_get_1(tz)
timezone *tz; /* always takes a a pointer to the arguments */
{
static date d; /* must be static! */

/*** figure out the date and store it in d ***/

return(&d);
}
The name of the routine is the same as the #define’d name,
but in all lower case letters and followed by the version
number. XDR will recursively free the argument after get-
ting the results from your local procedure, so you should
copy from the argument any data that you will need between
calls. However, XDR neither allocates nor frees your
results. You must take care of their storage yourself.

Make Inference Rules For Compiling XDR Headers
It is possible to set up suffix transformation rules in
make(1) for compiling XDR routines and header files. The
convention is that RPCL protocol files have the extension
.x. The make rules to do this are:
.SUFFIXES: .x
.x.c:
rpcgen -c $< -o $@

.x.h:
rpcgen -h $< -o $@

SEE ALSO
"Sun Microsystems RPC Programming Guide" and "Sun
Microsystems XDR Protocol Specification" in volume 2 of
the Sun Microsystems System Manager’s Manual

BUGS
Name clashes can occur when using program definitions,
since the apparent scoping does not really apply. Most of
these can be avoided by giving unique names for programs,
versions, procedures and types.

MachTen 11 March 1986 6