Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
4.  Programmer's Interface to RPC Standard Interfaces Expert-Level Interface Client Side of the Expert-Level Interface  Previous   Contents   Next 
   
 

The network is selected using setnetconfig(), getnetconfig(), and endnetconfig(). endnetconfig() is not called until after the call to clnt_tli_create(), near the end of the example.

clntudp_create() can be passed an open TLI fd. If passed none (fd == RPC_ANYFD), clntudp_create() opens its own using the netconfig structure for UDP to find the name of the device to pass to t_open().

If the remote address is not known (raddr->sin_port == 0), it is obtained from the remote rpcbind.

After the client handle has been created, you can modify it using calls to clnt_control(). The RPC library closes the file descriptor when destroying the handle, as it does with a call to clnt_destroy() when it opens the fd itself. The RPC library then sets the retry timeout period.

Server Side of the Expert-Level Interface

Example 4-13 shows the server side of Example 4-12. It is called svcudp_create(). The server side uses svc_tli_create().

svc_tli_create() is used when the application needs a fine degree of control, particularly to:

  • Pass an open file descriptor to the application.

  • Pass the user's bind address.

  • Set the send and receive buffer sizes. The fd argument can be unbound when passed in. It is then bound to a given address, and the address is stored in a handle. If the bind address is set to NULL and the fd is initially unbound, it is bound to any suitable address.

Use rpcb_set() to register the service with rpcbind.


Example 4-13 Server for RPC Lower Level

#include <stdio.h>

#include <rpc/rpc.h>
#include <netconfig.h>

#include <netinet/in.h>
 
SVCXPRT *
svcudp_create(fd)
	register int fd;
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	void *handlep;
	struct  t_info tinfo;
 
	/* If no transports available */
	if ((handlep = setnetconfig() ) == (void *) NULL) {
		nc_perror("server");
		return((SVCXPRT *) NULL);
	}
	/*
	 * Try all the transports until it gets one which is
	 * connectionless, family is INET and, name is UDP
	 */
	while (nconf = getnetconfig( handlep)) {
		if ((nconf->nc_semantics == NC_TPI_CLTS) &&

		    (strcmp( nconf->nc_protofmly, NC_INET) == 0 )&&
		    (strcmp( nconf->nc_proto, NC_UDP) == 0 ))
			break;
	}
	if (nconf == (struct netconfig *) NULL) {
		endnetconfig(handlep);
		return((SVCXPRT *) NULL);
	}
	if (fd == RPC_ANYFD) {
		fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
		if (fd == -1) {
			(void) endnetconfig();
			return((SVCXPRT *) NULL);
		}
		madefd = TRUE;
	} else
		t_getinfo(fd, &tinfo);
	svc = svc_tli_create(fd, nconf, (struct t_bind *) NULL,
	                      tinfo.tsdu, tinfo.tsdu);
	(void) endnetconfig(handlep);
	if (svc == (SVCXPRT *) NULL) {
		if (madefd)
			(void) t_close(fd);
		return((SVCXPRT *)NULL);
	}
	return (svc);
}

The network selection here is accomplished similar to clntudp_create(). The file descriptor is not bound explicitly to a transport address because svc_tli_create() does that.

svcudp_create() can use an open fd. It opens one itself using the selected netconfig structure if none is provided.

Bottom-Level Interface

The bottom-level interface to RPC enables the application to control all options. clnt_tli_create() and the other expert-level RPC interface routines are based on these routines. You rarely use these low-level routines.

Bottom-level routines create internal data structures, buffer management, RPC headers, and so on. Callers of these routines, like the expert-level routine clnt_tli_create(), must initialize the cl_netid and cl_tp fields in the client handle. For a created handle, cl_netid is the network identifier (for example, udp) of the transport and cl_tp is the device name of that transport (for example, /dev/udp). The routines clnt_dg_create() and clnt_vc_create() set the clnt_ops and cl_private fields.

Client Side of the Bottom-Level Interface

The following code example shows calls to clnt_vc_create() and clnt_dg_create().


Example 4-14 Client for Bottom Level

/*
 * variables are:
 * cl: CLIENT *
 * tinfo: struct t_info returned from either t_open or t_getinfo
 * svcaddr: struct netbuf *
 */
	switch(tinfo.servtype) {
		case T_COTS:
		case T_COTS_ORD:
			cl = clnt_vc_create(fd, svcaddr,
			 prog, vers, sendsz, recvsz);
			break;
		case T_CLTS:
			cl = clnt_dg_create(fd, svcaddr,
			 prog, vers, sendsz, recvsz);
			break;
		default:
			goto err;
	}

These routines require that the file descriptor be open and bound. svcaddr is the address of the server.

 
 
 
  Previous   Contents   Next