The rpcgen protocol compiler accepts a remote program interface definition written in the Remote Procedure Call language (RPCL), which is similar to the C language. The rpcgen compiler helps programmers write RPC applications simply and directly. The rpcgen compiler debugs the network interface code, thereby allowing programmers to spend their time debugging the main features of their applications.
The rpcgen compiler produces a C language output that includes the following:
Client stubs interface with the RPC library to effectively hide the network from its callers. Server stubs similarly hide the network from server procedures invoked by remote clients. The rpcgen output files can be compiled and linked in the usual way. Using any language, programmers write server procedures and link them with the server skeleton to get an executable server program.
When application programs use the rpcgen compiler, there are many details to consider. Of particular importance is the writing of XDR routines needed to convert procedure arguments and results into the network format, and vice versa.
Applications running at a single workstation can be converted to run over the network. A converted procedure can be called from anywhere in the network. Generally, it is necessary to identify the types for all procedure inputs and outputs. A null procedure (procedure 0) is not necessary because the rpcgen compiler generates it automatically. See "Converting Local Procedures into Remote Procedures Example" for more information.
The rpcgen compiler can be used to generate the XDR routines necessary to convert local data structures into network format, and vice versa. Some types can be defined using the struct, union, and enum keywords. However, these keywords should not be used in subsequent declarations of variables of these same types. The rpcgen compiler compiles RPC unions into C structures. It is an error to declare these unions using the union keyword. See "Generating XDR Routines Example" for more information.
The C language preprocessor is run on all input files before they are compiled, making all preprocessor directives within a .x file legal. Four symbols can be defined, depending upon which output file is generated. The symbols and their uses are:
RPC_HDR | Represents header file output. |
RPC_XDR | Represents XDR routine output. |
RPC_SVC | Represents server skeleton output. |
RPC_CLNT | Represents client stub output. |
The rpcgen compiler also does some preprocessing. Any line that begins with a % (percent sign) is passed directly into the output file without an interpretation of the line. Use of the percent feature is not generally recommended, since there is no guarantee that the compiler will put the output where it is intended.
When using the clnt_create subroutine, RPC sets a default time out of 25 seconds for remote procedure calls. The time-out default can be changed using the clnt_control subroutine. The following code fragment illustrates the use of this routine:
struct timeval tv CLIENT *cl; cl=clnt_create("somehost", SOMEPROG, SOMEVERS, "tcp"); if (cl=NULL) { exit(1); } tv.tv_sec=60; /* change timeout to 1 minute */ tv.tv_usec=0; clnt_control(cl, CLSET_TIMEOUT, &tv);
When a client calls a procedure through broadcast RPC, the server normally replies only if it can provide useful information to the client. This prevents flooding the network with useless replies.
To prevent the server from replying, a remote procedure can return null as its result. The server code generated by the rpcgen compiler detects this and does not send a reply. For example, the following procedure replies only if it interprets itself to be a server:
void * reply_if_nfsserver() { char notnull; /* just here so we can use its address */ if {access("/etc/exports", F_OK) < 0) { return (NULL); /* prevent RPC from replying */ } /* *return non-null pointer so RPC will send out a reply */ return ((void *) ¬null); }
If a procedure returns type void, the server must return a nonnull pointer in order for RPC to reply.
Server procedures often want more information about a remote procedure call than just its arguments. For example, getting authentication information is important to procedures that implement some level of security. This additional information is supplied to the server procedure as a second argument. The following example program that allows only root users to print a message on the console, demonstrates the use of the second argument:
int * printmessage_1(msg, rq) char **msg; struct svc_req *rq; { static in result; /* Must be static */ FILE *f; struct authunix_parms *aup; aup=(struct authunix_parms *)rq->rq_clntcred; if (aup->aup_uid !=0) { result=0; return (&result); } /* *Same code as before. */ }