ONC+ Developer's Guide

Client

There is just one function on the client side of the simplified interface: rpc_call(). It has nine parameters:

int	0 or error code
rpc_call (  
       char				*host			/* Name of server host */
       rpcprog_t		prognum		/* Server program number */
       rpcvers_t		versnum		/* Server version number */
       rpcproc_t		procnum		/* Server procedure number */
       xdrproc_t		inproc		/* XDR filter to encode arg */
       char				*in			/* Pointer to argument */
       xdr_proc_t	outproc		/* Filter to decode result */
       char				*out			/* Address to store result */
       char				*nettype		/* For transport selection */
);

This function calls the procedure specified by prognum, versum, and procnum on the host. The argument to be passed to the remote procedure is pointed to by the in parameter, and inproc is the XDR filter to encode this argument. The out parameter is an address where the result from the remote procedure is to be placed. outproc is an XDR filter which will decode the result and place it at this address.

The client blocks on rpc_call() until it receives a reply from the server. If the server accepts, it returns RPC_SUCCESS with the value of zero. It will return a non-zero value if the call was unsuccessful. This value can be cast to the type clnt_stat, an enumerated type defined in the RPC include files and interpreted by the clnt_sperrno() function. This function returns a pointer to a standard RPC error message corresponding to the error code.

In the example, all "visible" transports listed in /etc/netconfig are tried. Adjusting the number of retries requires use of the lower levels of the RPC library.

Multiple arguments and results are handled by collecting them in structures.

The example in Example 4-1, changed to use the simplified interface, looks like Example 4-2.


Example 4-2 rusers Program Using Simplified Interface

#include <stdio.h>
#include <utmpx.h>
#include <rpc/rpc.h>
#include <rpcsvc/rusers.h>
 
/* a program that calls the RUSERSPROG
 * RPC program
 */
 
main(argc, argv)
	int argc;
	char **argv;
{
	unsigned int nusers;
	enum clnt_stat cs;
 
	if (argc != 2) {
		   fprintf(stderr, "usage: rusers hostname\n");
		   exit(1);
	}
	if( cs = rpc_call(argv[1], RUSERSPROG,
			 	RUSERSVERS,	RUSERSPROC_NUM, xdr_void,
					(char *)0, xdr_u_int, (char *)&nusers,
     "visible")  !=  RPC_SUCCESS )  {
		          clnt_perrno(cs);
		          exit(1);
	           }
	fprintf(stderr, "%d users on %s\n", nusers,
						argv[1] );
	exit(0);
}

Since data types may be represented differently on different machines, rpc_call() needs both the type of, and a pointer to, the RPC argument (similarly for the result). For RUSERSPROC_NUM, the return value is an unsigned int, so the first return parameter of rpc_call() is xdr_u_int (which is for an unsigned int) and the second is &nusers (which points to unsigned int storage). Because RUSERSPROC_NUM has no argument, the XDR encoding function of rpc_call() is xdr_void() and its argument is NULL.