Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
3.  rpcgen Programming Guide rpcgen Programming Techniques Port Monitor Support  Previous   Contents   Next 
   
 

Time-out Changes

After sending a request to the server, a client program waits for a default period (25 seconds) to receive a reply. You can change this timeout by using the clnt_control() routine. See "Standard Interfaces " for additional uses of the clnt_control() routine. See also the rpc(3NSL) man page. When considering time-out periods, be sure to allow the minimum amount of time required for "round-trip" communications over the network. The following code example illustrates the use of clnt_control().


Example 3-24 clnt_control Routine

struct timeval tv;
CLIENT *clnt;
clnt = clnt_create( "somehost", SOMEPROG,
									SOMEVERS, "visible" );

if (clnt == (CLIENT *)NULL)
	exit(1);
tv.tv_sec = 60;	/* change time-out to
							 * 60 seconds
							 */
tv.tv_usec = 0;
clnt_control(clnt, CLSET_TIMEOUT, &tv);

Client Authentication

The client create routines do not have any facilities for client authentication. Some clients might have to authenticate themselves to the server.

The following example illustrates one of the least secure authentication methods in common use. See "Authentication" for information on more secure authentication techniques.


Example 3-25 AUTH_SYS Authentication Program

CLIENT *clnt;
clnt = clnt_create( "somehost", SOMEPROG,
									SOMEVERS, "visible" );
if (clnt != (CLIENT *)NULL) {
	/* To set AUTH_SYS style authentication */
		clnt->cl_auth = authsys_createdefault();
}

Authentication information is important to servers that have to achieve some level of security. This extra information is supplied to the server as a second argument.

The following example is for a server that checks client authentication data. It is modified from printmessage_1() in "rpcgen Tutorial". The code allows only superusers to print a message to the console.


Example 3-26 printmsg_1 for Superuser

int *
printmessage_1(msg, req)
	char **msg;
	struct svc_req  *req;
{
	static int result;	/* Must be static */
	FILE *f;
	struct authsys_parms *aup;

	aup = (struct authsys_parms *)req->rq_clntcred;
	if (aup->aup_uid != 0) {
		result = 0;
		return (&result)
	}

/* Same code as before. */
}

Dispatch Tables

Sometimes programs should have access to the dispatch tables used by the RPC package. For example, the server dispatch routine might check authorization and then invoke the service routine. Or, a client library might handle the details of storage management and XDR data conversion.

When invoked with the -T option, rpcgen generates RPC dispatch tables for each program defined in the protocol description file, proto.x, in the file proto_tbl.i. The suffix.i stands for "index." You can invoke rpcgen with the -t option to build only the header file. You cannot invoke rpcgen in C-style mode (-N) with either the -T or -t flag.

Each entry in the dispatch table is a struct rpcgen_table, defined in the header file proto.h as follows:

struct rpcgen_table {
   char *(*proc)();
   xdrproc_t xdr_arg;
   unsigned len_arg;
   xdrproc_t xdr_res;
   xdrproc_t len_res
};

where:

proc is a pointer to the service routine

xdr_arg is a pointer to the input (argument) xdr routine

len_arg is the length in bytes of the input argument

xdr_res is a pointer to the output (result) xdr routine

len_res is the length in bytes of the output result

The table, named dirprog_1_table for the dir.x example, is indexed by procedure number. The variable dirprog_1_nproc contains the number of entries in the table.

The find_proc() routine shows an example of how to locate a procedure in the dispatch tables.


Example 3-27 Using a Dispatch Table

struct rpcgen_table *
find_proc(proc)
   rpcproc_t proc;
{
   if (proc >= dirprog_1_nproc)
       /* error */
   else
      return (&dirprog_1_table[proc]);
}

Each entry in the dispatch table contains a pointer to the corresponding service routine. However, that service routine is usually not defined in the client code. To avoid generating unresolved external references, and to require only one source file for the dispatch table, the rpcgen service routine initializer is RPCGEN_ACTION(proc_ver).

Using this technique, the same dispatch table can be included in both the client and the server. Use the following define statement when compiling the client.

#define RPCGEN_ACTION(routine) 0

Use the following define when writing the server.

#define RPCGEN_ACTION(routine)routine

64-Bit Considerations for rpcgen

In Example 3-27 proc is declared as type rpcproc_t. Formerly, RPC programs, versions, procedures, and ports were declared to be of type u_long. On a 32-bit machine, a u_long is a 4-byte quantity (as is an int); on a 64-bit system, a u_long is an 8-byte quantity. The data types rpcprog_t, rpcvers_t, rpc_proc_t, and rpcport_t, introduced in the Solaris 7 environment, should be used whenever possible in declaring RPC programs, versions, procedures, and ports in place of both u_long and long. These newer types provide backwards compatibility with 32-bit systems. They are guaranteed to be 4-byte quantities no matter which system rpcgen is run on. While rpcgen programs using u_long versions of programs, versions, and procedures can still run, they have different consequences on 32- and 64-bit machines. For that reason, replace them with the appropriate newer data types. In fact, avoid using long and u_long whenever possible.

Beginning with the Solaris 7 environment, source files created with rpcgen containing XDR routines use different inline macros depending on whether the code is to run on a 32-bit or 64-bit machine. Specifically, the source files will use the IXDR_GET_INT32() and IXDR_PUT_INT32() macros instead of IXDR_GETLONG() and IXDR_PUTLONG(). For example, if the rpcgen source file foo.x contains the following code, the resulting foo_xdr.c file ensures that the correct inline macro is used.
struct foo {
        char      c;
        int       i1;
        int       i2;
        int       i3;
        long      l;
        short     s;
};

#if defined(_LP64) || defined(_KERNEL)
	register int *buf; 

#else   
	register long *buf; 

#endif
  . . . 
 #if defined(_LP64) || defined(_KERNEL)

 	IXDR_PUT_INT32(buf, objp->i1);                         

	IXDR_PUT_INT32(buf, objp->i2);                         
	IXDR_PUT_INT32(buf, objp->i3);                         

	IXDR_PUT_INT32(buf, objp->l);                         

	IXDR_PUT_SHORT(buf, objp->s); 
#else                         

 
	IXDR_PUT_LONG(buf, objp->i1);                         

	IXDR_PUT_LONG(buf, objp->i2);                         

	IXDR_PUT_LONG(buf, objp->i3);                         
	IXDR_PUT_LONG(buf, objp->l);                         

	IXDR_PUT_SHORT(buf, objp->s); 
#endif

 
 
 
  Previous   Contents   Next