A very general mechanism for client-server applications is provided by RPC, the Remote Procedure Call package. RPC was developed by Sun Micrsystems, and is a collection of tools and library functions. Important applications built on top of RPC are NFS, the Network Filesystem, and NIS, the Network Information System, both of which will be introduced in later chapters.
An RPC server consists of a collection of procedures that client may call by sending an RPC request to the server, along with the procedure parameters. The server will invoke the indicated procedure on behalf of the client, handing back the return value, if there is any. In order to be machine-independent, all data exchanged between client and server is converted to a so-called External Data Representation format (XDR) by the sender, and converted back to the machine-local representation by the receiver.
Sometimes, improvements to an RPC application introduce incompatible changes in the procedure call interface. Of course, simply changing the server would crash all application that still expect the original behavior. Therefore, RPC programs have version numbers assigned to them, usually starting with 1, and with each new version of the RPC interface this counter will be bumped. Often, a server may offer several versions simultaneously; clients then indicate by the version number in their requests which implementation of the service they want to use.
The network communication between RPC servers and clients is somewhat peculiar. An RPC server offers one or more collections of procedures; each set is being called a program, and is uniquely identified by a program number. A list mapping service names to program numbers is usually kept in /etc/rpc, an excerpt of which is reproduced below in figure .
# # /etc/rpc - miscellaenous RPC-based services # portmapper 100000 portmap sunrpc rstatd 100001 rstat rstat_svc rup perfmeter rusersd 100002 rusers nfs 100003 nfsprog ypserv 100004 ypprog mountd 100005 mount showmount ypbind 100007 walld 100008 rwall shutdown yppasswdd 100009 yppasswd bootparam 100026 ypupdated 100028 ypupdate
In TCP/IP networks, the authors of RPC were faced with the problem of mapping program numbers to generic network services. They chose to have each server provide both a TCP and a UDP port for each program and each version. Generally, RPC applications will use UDP when sending data, and only fall back to TCP when the data to be transferred doesn't fit into a single UDP datagram.
Of course, client programs have to have a way to find out which port a program number maps to. Using a configuration file for this would be too unflexible; since RPC applications don't use reserved ports, there's no guarantee that a port originally meant to be used by our database application hasn't been taken by some other process. Therefore, RPC applications pick any port they can get, and register it with the so-called portmapper daemon. The latter acts as a service broker for all RPC servers running on its machine: a client that wishes to contact a service with a given program number will first query the portmapper on the server's host which returns the TCP and UDP port numbers the service can be reached at.
This method has the particular drawback that it introduces a single point of failure, much like the inetd daemon does for the standard Berkeley services. However, this case is even a little worse, because when the portmapper dies, all RPC port information is lost; this usually means you have to restart all RPC servers manually, or reboot the entire machine.
On , the portmapper is called rpc.portmap and resides in /usr/sbin. Other than making sure it is started form rc.inet2, the portmapper doesn't require any configuration work.