ONC+ Developer's Guide

Client

Assume the header file in Example 4-7.


Example 4-7 time_prot.h Header File

/* time_prot.h */
#include <rpc/rpc.h>
#include <rpc/types.h>
 
struct timev {
	int second;
	int minute;
	int hour;
};
typedef struct timev timev;
bool_t xdr_timev();
 
#define TIME_PROG 0x40000001
#define TIME_VERS 1
#define TIME_GET  1

Example 4-8 shows the client side of a trivial date service using top-level service routines. The transport type is specified as an invocation argument of the program.


Example 4-8 Client for Trivial Date Service

#include <stdio.h>
#include "time_prot.h"
 
#define TOTAL (30)
/*
 * Caller of trivial date service
 * usage: calltime hostname
 */
main(argc, argv)
	int argc;
	char *argv[];
{
	struct timeval time_out;
	CLIENT *client;
	enum clnt_stat stat;
	struct timev timev;
	char *nettype;
 
	if (argc != 2 && argc != 3) {
		fprintf(stderr,"usage:%s host[nettype]\n"
					,argv[0]);
		exit(1);
	}
	if (argc == 2)
		nettype = "netpath";		/* Default */	
	else
		nettype = argv[2];
	client = clnt_create(argv[1], TIME_PROG,
									TIME_VERS, nettype);
	if (client == (CLIENT *) NULL) {
		clnt_pcreateerror("Couldn't create client");
		exit(1);
	}
	time_out.tv_sec = TOTAL;
	time_out.tv_usec = 0;
	stat = clnt_call( client, TIME_GET, 
					xdr_void, (caddr_t)NULL,
					xdr_timev, (caddr_t)&timev,
					time_out);
	if (stat != RPC_SUCCESS) {
		clnt_perror(client, "Call failed");
		exit(1);
	}
	fprintf(stderr,"%s: %02d:%02d:%02d GMT\n",
				nettype timev.hour, timev.minute,
				timev.second);
	(void) clnt_destroy(client);
	exit(0);	
}

If nettype is not specified in the invocation of the program, the string netpath is substituted. When RPC libraries routines encounter this string, the value of the NETPATH environment variable governs transport selection.

If the client handle cannot be created, display the reason for the failure with clnt_pcreateerror(), or get the error status by reading the contents of the global variable rpc_createerr.

After the client handle is created, clnt_call() is used to make the remote call. Its arguments are the remote procedure number, an XDR filter for the input argument, the argument pointer, an XDR filter for the result, the result pointer, and the time-out period of the call. The program has no arguments, so xdr_void() is specified. Clean up by calling clnt_destroy().

In the above example, if the programmer wished to bound the time allowed for client handle creation to thirty seconds, the call to clnt_create() should be replaced with a call to clnt_create_timed() as shown in the following code segment:

 struct timeval timeout;
 timeout.tv_sec = 30;		/* 30 seconds */
 timeout.tv_usec = 0;

 client = clnt_create_timed(argv[1],
					TIME_PROG, TIME_VERS, nettype,
					&timeout);

Example 4-9 shows a top-level implementation of a server for the trivial date service.


Example 4-9 Server for Trivial Date Service

#include <stdio.h>
#include <rpc/rpc.h>
#include "time_prot.h"
 
static void time_prog();
 
main(argc,argv)
	int argc;
	char *argv[];
{
	int transpnum;
	char *nettype;
 
	if (argc > 2) {
 
		fprintf(stderr, "usage: %s [nettype]\n",
						argv[0]);
		exit(1);
	}
	if (argc == 2)
		nettype = argv[1];
	else
		nettype = "netpath";			/* Default */
	transpnum =
svc_create(time_prog,TIME_PROG,TIME_VERS,nettype);
	if (transpnum == 0) {
		fprintf(stderr,"%s: cannot create %s service.\n",
					argv[0], nettype);
		exit(1);
	}
	svc_run();
}
 
/*
 * The server dispatch function
 */
static void
time_prog(rqstp, transp)
	struct svc_req *rqstp;
	SVCXPRT *transp;
{
	struct timev rslt;
	time_t thetime;
 
	switch(rqstp->rq_proc) {
		case NULLPROC:
			svc_sendreply(transp, xdr_void, NULL);
			return;
		case TIME_GET:
			break;
		default:
			svcerr_noproc(transp);
			return;
		}
	thetime = time((time_t *) 0);
	rslt.second = thetime % 60;
	thetime /= 60;
	rslt.minute = thetime % 60;
	thetime /= 60;
	rslt.hour = thetime % 24;
	if (!svc_sendreply( transp, xdr_timev, &rslt)) {
		svcerr_systemerr(transp);
		}
}

svc_create() returns the number of transports on which it created server handles. time_prog() is the service function called by svc_run() when a request specifies its program and version numbers. The server returns the results to the client through svc_sendreply().

When rpcgen is used to generate the dispatch function, svc_sendreply() is called after the procedure returns, so rslt (in this example) must be declared static in the actual procedure. svc_sendreply() is called from inside the dispatch function, so rslt is not declared static.

In this example, the remote procedure takes no arguments. When arguments must be passed, the calls:

svc_getargs( SVCXPRT_handle, XDR_filter, argument_pointer);
svc_freeargs( SVCXPRT_handle, XDR_filter argument_pointer );

fetch, deserialize (XDR decode), and free the arguments.