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);
}
}
|