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:
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
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
These routines require that the file descriptor be open and bound. svcaddr is the address of the server.