Much of the miniRPC interface is specific to the application protocol being implemented on top of miniRPC. The code to implement this interface is generated by minirpcgen
from a ".mx" or protocol definition file. This documentation will illustrate the protocol-dependent interfaces using a simple example protocol.
A protocol definition file describes the data structures and procedure calls to be supported by the protocol. The data structures are defined using XDRL, the External Data Representation Language, defined in RFC 4506. The procedure calls are defined using a syntax specific to miniRPC.
First, we examine the protocol definition for our example protocol.
enum example_color { RED = 0, ORANGE = 1, YELLOW = 2, GREEN = 3, BLUE = 4, INDIGO = 5, VIOLET = 6 }; struct example_color_choice { enum example_color acceptable<>; enum example_color preferred; };
The example protocol starts out by defining an example_color
enumeration, and then defines an example_color_choice
structure which will be used as the basis of a protocol message. example_color_choice
contains a variable-length array of "acceptable" colors, and one particular color which is selected as "preferred".
typedef int example_count;
miniRPC presently does not support the use of primitive XDR types as request or reply arguments to RPC procedures. A procedure argument must be a named type corresponding to a struct, enum, or typedef, or must be void. As here, if a protocol needs to use a primitive type as a procedure argument, it must declare and use a typedef for that type.
serverprocs {
choose_color(example_color_choice) = 1;
get_num_colors(void, example_count) = 2;
}
We now define the procedure calls to be supported by the server. Each procedure can have up to two arguments: one request argument and one reply argument, in that order. Unused arguments can be omitted from the procedure definition or declared to be void
. As with get_num_colors
, a procedure with a reply argument but no request argument must declare the request argument to be void
. Each procedure is also assigned a procedure number, which is used by the protocol to indicate which procedure is being called.
Since these procedures are declared in a serverprocs
section, they are procedure calls made from client to server; that is, the client is the sender and the server is the receiver. There can also be a clientprocs
section, which defines procedure calls initiated by the server and received by the client.
No two procedures in a protocol can have the same name. No two procedures of the same type (serverprocs
, clientprocs
, servermsgs
, or clientmsgs
) can have the same procedure number.
servermsgs { crayon_selected(example_color) = 1; }
This protocol includes an additional crayon_selected
message, which is not really a procedure call at all: it is an event notification sent from client to server, to which the server has no opportunity to reply. (Procedure calls declared in a procs
section with a void
return type, such as choose_color
above, still involve a reply, since the receiver can return a success indication or error code.) Accordingly, procedure definitions in the msgs
section take only a request argument.
As above, messages sent from client to server are defined in a servermsgs
section, and messages sent by the server are defined in a clientmsgs
section.
minirpcgen -o example example.mx
The result is a set of output files:
The C source files should be compiled into the programs implementing the client and server (either directly, or indirectly via a library). The header files should also be made available to these programs during their build process. A client application implementing this example protocol need only include example_client.h directly; likewise, a server need only include example_server.h.
Note that the argument given to minirpcgen's
-o
option is embedded not only in the names of the output files, but in the names of the generated miniRPC structures and C functions. (This does not apply to the XDR structs and enums specified in the .mx file.) If the
-o
option is not specified, the name of the .mx file (with ".mx" removed) is used.
make
jobs are run in parallel (e.g., with "make -j3"
). If you use GNU Make, you can use pattern rules to properly handle this case:
%_minirpc.c %_minirpc.h %_client.h %_server.h %_xdr.c %_xdr.h: %.mx $(MINIRPCGEN) $^
minirpcgen
, see Common Definitions, Client Stubs, and Server Stubs. For example code using this protocol, see Example Client Program and Example Server Program.minirpcgen
generates output in three passes. The *_xdr.c
and *_xdr.h
files are generated by the rpcgen
program in two separate passes; the rest of the output files are generated by minirpcgen
itself.
As a result, parse errors may be issued at several points in the compile process. minirpcgen
itself will issue errors relating to procedure definition blocks, while rpcgen
will issue errors relating to XDR data type definitions. rpcgen
does not attempt to catch all type definition errors directly, so some errors may only appear once the C compiler attempts to compile the generated code.
.mx
files are preprocessed using cpp
before they are read, so all of the usual preprocessor directives (#include
, etc.) work as expected. minirpcgen
defines special preprocessor macros during each pass over the input file:
RPC_XDR
is defined when generating *_xdr.c
RPC_HDR
is defined when generating *_xdr.h
MINIRPC
is defined when generating all other output files
For the XDR passes only, you can embed literal strings in the output files by prefixing them with "%". Using both literal strings and defines it is possible to declare common data structures in a .mx file and include it into several others with the following fragment:
#ifdef MINIRPC #include "common.mx" #else %#include "common_xdr.h" #endif
You can define additional preprocessor macros by passing "-D MACRONAME=value"
to minirpcgen
. Multiple -D
options are accepted.
Modules | |
Common Definitions | |
Client Stubs | |
Server Stubs |