Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
5.  Advanced RPC Programming Techniques Using Port Monitors Using the Listener   Previous   Contents   Next 
   
 

Multiple Server Versions

By convention, the first version number of a program, PROG, is named PROGVERS_ORIG and the most recent version is named PROGVERS. Program version numbers must be assigned consecutively. Leaving a gap in the program version sequence can cause the search algorithm not to find a matching program version number that is defined.

Only the owner of a program should change version numbers. Adding a version number to a program that you do not own can cause severe problems when the owner increments the version number. Sun registers version numbers and answers questions about them (rpc@Sun.com).

Suppose a new version of the ruser program returns an unsigned short rather than an int. If you name this version RUSERSVERS_SHORT, a server that supports both versions would do a double register. Use the same server handle for both registrations.


Example 5-15 Server Handle for Two Versions of Single Routine

if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_ORIG, 
						nuser, nconf))
{
	fprintf(stderr, "can't register RUSER service\n");
	exit(1);
}
if (!svc_reg(transp, RUSERSPROG, RUSERSVERS_SHORT, nuser,
						nconf)) {
	fprintf(stderr, "can't register RUSER service\n");
	exit(1);
}

Both versions can be performed by a single procedure, as shown in the following example.


Example 5-16 Procedure for Two Versions of Single Routine

void
nuser(rqstp, transp)
	struct svc_req *rqstp;
	SVCXPRT *transp;
{
	unsigned int nusers;
	unsigned short nusers2;
	switch(rqstp->rq_proc) {
		case NULLPROC:
			if (!svc_sendreply( transp, xdr_void, 0))
				fprintf(stderr, "can't reply to RPC call\n");
			return;
		case RUSERSPROC_NUM:
			/*
			 * Code here to compute the number of users
			 * and assign it to the variable nusers
			 */
		switch(rqstp->rq_vers) {
			case RUSERSVERS_ORIG:
				if (! svc_sendreply( transp, xdr_u_int, &nusers))
					fprintf(stderr, "can't reply to RPC call\n");
				break;
			case RUSERSVERS_SHORT:
				nusers2 = nusers;
				if (! svc_sendreply( transp, xdr_u_short, &nusers2))
					fprintf(stderr, "can't reply to RPC call\n");
				break;
		}
		default:
			svcerr_noproc(transp);
			return;
	}
	return;
}

Multiple Client Versions

Because different hosts can run different versions of RPC servers, a client should be capable of accommodating the variations. For example, one server can run the old version of RUSERSPROG(RUSERSVERS_ORIG) while another server runs the newer version (RUSERSVERS_SHORT).

If the version on a server does not match the version number in the client creation call, clnt_call() fails with an RPCPROGVERSMISMATCH error. You can get the version numbers supported by a server and then create a client handle with the appropriate version number. Use either the routine in the following example, or clnt_create_vers(). See the rpc(3NSL)man page for more details.


Example 5-17 RPC Versions on Client Side

main()
{
	enum clnt_stat status;
	u_short num_s;
	u_int num_l;
	struct rpc_err rpcerr;
	int maxvers, minvers;
	CLIENT *clnt;
 
	clnt = clnt_create("remote", RUSERSPROG, RUSERSVERS_SHORT,
			             "datagram_v");
	if (clnt == (CLIENT *) NULL) {
		clnt_pcreateerror("unable to create client handle");
		exit(1);
	}
	to.tv_sec = 10;							      /* set the time outs */
	to.tv_usec = 0;
 
	status = clnt_call(clnt, RUSERSPROC_NUM, xdr_void,
	                  (caddr_t) NULL, xdr_u_short, 
 (caddr_t)&num_s, to);
	if (status == RPC_SUCCESS) {		/* Found latest version number */
		printf("num = %d\n", num_s);
		exit(0);
	}
	if (status != RPC_PROGVERSMISMATCH) {		/* Some other error */
		clnt_perror(clnt, "rusers");
		exit(1);
	}
	/* This version not supported */
	clnt_geterr(clnt, &rpcerr);
	maxvers = rpcerr.re_vers.high;		  /* highest version supported */
	minvers = rpcerr.re_vers.low;		     /*lowest version supported */

	if (RUSERSVERS_SHORT < minvers || RUSERSVERS_SHORT > maxvers)
{
			                           /* doesn't meet minimum standards */
		clnt_perror(clnt, "version mismatch");
		exit(1);
	}
	(void) clnt_control(clnt, CLSET_VERSION, RUSERSVERS_ORIG);
	status = clnt_call(clnt, RUSERSPROC_NUM, xdr_void,
(caddr_t) NULL, xdr_u_int, (caddr_t)&num_l, to);
	if (status == RPC_SUCCESS)
			                 /* We found a version number we recognize */
		printf("num = %d\n", num_l);
	else {
		clnt_perror(clnt, "rusers");
		exit(1);
	}
}

 
 
 
  Previous   Contents   Next