Remote procedure calls can be made from any language. Remote Procedure Call (RPC) protocol is generally used to communicate between processes on different workstations. However, RPC works just as well for communication between different processes on the same workstation.
The RPC interface can be seen as being divided into three layers: highest, intermediate, and lowest. The highest layer of RPC is totally transparent to the operating system, workstation, and network on which it runs. This level is actually a method for using RPC routines, rather than a part of RPC proper.
The intermediate layer is RPC proper. At the intermediate layer, the programmer need not consider details about sockets or other low-level implementation mechanisms. The programmer simply makes remote procedure calls to routines on other workstations.
The lowest layer of RPC allows the programmer greatest control. Programs written at this level can be more efficient.
Both intermediate and lower-level RPC programming entail assigning program numbers, version numbers, and procedure numbers. An RPC server can be started from the inetd daemon.
A central system authority administers the program number (prog parameter). A program number permits the implementation of a remote program. The first implementation of a program is usually version number 1.
A program number is assigned by groups of 0x20000000 (decimal 536870912), according to the following list:
The first group of numbers is predefined, and should be identical for all customers. If a customer develops an application that might be of general interest, that application can be registered by assigning a number in the first range. The second group of numbers is reserved for specific customer applications. This range is intended primarily for debugging new programs. The third group is reserved for applications that generate program numbers dynamically. The final groups are reserved for future use and should not be used.
Most new protocols evolve into more efficient, stable, and mature protocols. As a program evolves, a new version number (vers parameter) is assigned. The version number identifies which version of the protocol the caller is using. The first implementation of a remote program is usually designated as version number 1 (or a similar form). Version numbers make it possible to use old and new protocols through the same server. See "Using Multiple Program Versions Example".
Just as remote program protocols may change over several versions, the actual RPC message protocol can also change. Therefore, the call message also contains the RPC version number. In the second version of the RPC protocol specification, the version number is always 2.
The procedure number (proc parameter) identifies the procedure to be called. The procedure number is documented in each program's protocol specification. For example, a file service protocol specification can list the read procedure as procedure 5 and the write procedure as procedure 12.
The RPC program numbers and protocol specifications of standard RPC services are in the header files in the /usr/include/rpcsvc directory. The RPC /etc/rpc file describes the RPC program numbers in text so that users can identify the number with the name. The names identified in the text can be used in place of RPC program numbers. These programs, however, constitute only a small subset of those that have been registered.
The following is a list of registered RPC programs including the program number, program name, and program description:
Registered RPC Programs | ||
---|---|---|
Number | Name | Description |
100000 | PMAPPROG | Port mapper |
100001 | RSTATPROG | Remote stats |
100002 | RUSERSPROG | Remote users |
100003 | NFSPROG | Network File System (NFS) |
100004 | YPPROG | Network Information Service (NIS) |
100005 | MOUNTPROG | Mount daemon |
100006 | DBXPROG | Remote dbx |
100007 | YPBINDPROG | NLS binder |
100008 | WALLPROG | Shutdown message |
100009 | YPPASSWDPROG | yppasswd server |
100010 | ETHERSTATPROG | Ether stats |
100011 | RQUOTAPROG | Disk quotas |
100012 | SPRAYPROG | Spray packets |
100013 | IBM3270PROG | 3270 mapper |
100014 | IBMRJEPROG | RJE mapper |
100015 | SELNSVCPROG | Selection service |
100016 | RDATABASEPROG | Remote database access |
100017 | REXECPROG | Remote execution |
100018 | ALICEPROG | Alice Office Automation |
100019 | SCHEDPROG | Scheduling service |
100020 | LOCKPROG | Local lock manager |
100021 | NETLOCKPROG | Network lock manager |
100023 | STATMON1PROG | Status monitor1 |
100024 | STATMON2PROG | Status monitor2 |
100025 | SELNLIBPROG | Selection library |
100026 | BOOTPARAMPROG | Boot parameters service |
100027 | MAZEPROG | Mazewars games |
100028 | YPUPDATEPROG | YP update |
100029 | KEYSERVEPROG | Key server |
100030 | SECURECMDPROG | Secure login |
100031 | NETFWDIPROG | NFS net forwarder init |
100032 | NETFWDTPROG | NFS net forwarder trans |
100033 | SUNLINKMAP_PROG | Sunlink MAP |
100034 | NETMONPROG | Network monitor |
100035 | DBASEPROG | Lightweight database |
100036 | PWDAUTHPROG | Password authorization |
100037 | TFSPROG | Translucent file service |
100038 | NSEPROG | NSE server |
100039 | NSE_ACTIVATE_PROG | NSE activate daemon |
150001 | PCNFSDPROGx | PC password authorization |
200000 | PYRAMIDLOCKINGPROG | Pyramid-locking |
200001 | PYRAMIDSYS5 | Pyramid-sys5 |
200002 | CADDS_IMAGE | CV cadds_image |
300001 | ADT_RFLOCKPROG | ADT file locking |
Programmers who write remote procedure calls can make the highest layer of RPC available to other users through a simple C language front-end routine that entirely hides the networking. To illustrate a call at the highest level, a program can simply call the rnusers routine, a C routine that returns the number of users on a remote workstation. The user need not be explicitly aware of using RPC.
Other RPC service library routines available to the C programmer are:
RPC services, such as the mount and spray commands, are not available to the C programmer as service library routines. Though unavailable, these services have RPC program numbers and can be invoked with the callrpc subroutine. Most of these services have compilable rpcgen protocol description files that simplify the process of developing network applications.
For more information, see "Using the Highest Layer of RPC Example".
The intermediate layer RPC routines are used for most applications. The intermediate layer is sometimes overlooked in programming due to its simplicity and lack of flexibility. At this level, RPC does not allow time-out specifications, choice of transport, or process control in case of errors. Nor does the intermediate layer of RPC support multiple types of call authentication. The programmer often needs these kinds of control.
Remote procedure calls are made with the registerrpc, callrpc, and svc_run system routines, which belong to the intermediate layer of RPC. The registerrpc and callrpc routines are the most fundamental. The registerrpc routine obtains a unique system-wide procedure identification number. The callrpc routine executes the remote procedure call.
Each RPC procedure is uniquely defined by a program number, version number, and procedure number. The program number specifies a group of related remote procedures, each of which has a different procedure number. Each program also has a version number. Therefore, when a minor change, such as adding a new procedure, is made to a remote service, a new program number need not be assigned.
The RPC interface also handles arbitrary data structures, regardless of the different byte orders or structure layout conventions at various workstations. For more information, see the "Using the Intermediate Layer of RPC Example".
Only the User Datagram Protocol (UDP) transport mechanism can use the registerrpc routine. This routine is always safe in conjunction with calls generated by the callrpc routine. The UDP transport mechanism can deal only with arguments and results that are less than 8KB in length.
The RPC registerrpc routine includes the following parameters:
After registering the local procedure, the server program's main procedure calls the svc_run routine, which is the RPC library's remote procedure dispatcher. The svc_run routine then calls the remote procedure in response to RPC messages. The dispatcher uses the XDR data filters that are specified when the remote procedure is registered to handle decoding procedure arguments and encoding results.
The RPC callrpc routine executes remote procedure calls. See "Using the Intermediate Layer of RPC Example".
The callrpc routine includes the following parameters:
Multiple arguments and results can be embedded in structures. If the callrpc routine completes successfully, it returns a value of zero. Otherwise, it returns a nonzero value. The return codes are cast in integer data-type values in the rpc/clnt.h file.
If the callrpc routine gets no answer after several attempts to deliver a message, it returns with an error code. The delivery mechanism is UDP. Adjusting the number of retries or using a different protocol requires the use of the lower layer of the RPC library.
The RPC interface can handle arbitrary data structures, regardless of the different byte orders or structure layout conventions on different machines, by converting the structures to a network standard called XDR before sending them over the wire. The process of converting from a particular machine representation to XDR format is called serializing, and the reverse process is called deserializing.
The input and output parameters of the callrpc and registerrpc routines can be a built-in or user-supplied procedure. For more information, see "Showing How RPC Passes Arbitrary Data Types Example".
The XDR language has the following built-in subroutines:
Although the xdr_string subroutine exists, it passes three parameters to its XDR routine. The xdr_string subroutine cannot be used with the callrpc and registerrpc subroutines, which pass only two parameters. However, the xdr_string routine can be called with the xdr_wrapstring routine, which also has only two parameters.
If completion is successful, XDR subroutines return a nonzero value (that is, a True value in the C language). Otherwise, they return a value of zero (False).
In addition to the built-in primitives are the following prefabricated building blocks:
For the higher layers, RPC takes care of many details automatically. However, the lowest layer of the RPC library allows the programmer to change the default values for these details. The lowest layer of RPC requires familiarity with sockets and their system calls. For more information, see "Using the Lowest Layer of RPC Example" and "Using Multiple Program Versions Example".
The lowest layer of RPC may be necessary in the following situations:
XDR routines not only do input and output, they also do memory allocation. Consider the following XDR routine, xdr_chararr1, which deals with a fixed array of bytes with length SIZE .
xdr_chararr1 (xdrsp, chararr) XDR *xdrsp; char chararr[]; { char *p; int len; p = chararr; len = SIZE; return (xdr_bytes (xdrsp, &p, &len, SIZE)); }
If space has already been allocated in it, chararr can be called from a server. For example:
char chararr [SIZE]; svc_getargs (transp, xdr_chararr1, chararr);
If you want XDR to do the allocation, you need to rewrite this routine in the following way:
xdr_chararr2 (xdrsp, chararrp) XDR *xdrsp; char **chararrp; { int len; len = SIZE; return (xdr_bytes (xdrsp, charrarrp, &len, SIZE)); }
Then the RPC call might look like this:
char *arrptr; arrptr = NULL; svc_getargs (transp, xdr_chararr2, &arrptr); /* *Use the result here */ svc_freeargs (transp, xdr_chararr2, &arrptr);
The character array can be freed with the svc_freeargs macro. This operation does not attempt to free any memory in the variable, indicating the variable is null.
Each XDR routine is responsible for serializing, deserializing, and freeing memory. When an XDR routine is called from the callrpc routine, the serializing part is used. When an XDR routine is called from the svc_getargs routine, the deserializer is used. When an XDR routine is called from the svc_freeargs routine, the memory deallocator is used.
An RPC server can be started from the inetd daemon. The only difference between using the inetd daemon and the usual code is that the service creation routine is called. Since the inet passes a socket as file descriptor 0, the following form is used:
transp = svcudp_create(0); /* For UDP */ transp = svctcp_create(0,0,0); /* For listener TCP sockets */ transp = svcfd_create(0,0,0); /* For connected TCP sockets */
In addition, the svc_register routine should be called as follows:
svc_register(transp, PROGNUM, VERSNUM, service, 0)
The final flag is 0 since the program is already registered by the inetd daemon. To exit from the server process and return control to the inet, the user must explicitly exit. The svc_run routine never returns.
Entries in the /etc/inetd.conf file for RPC services take one of the following two forms:
p_name sunrpc_udp udp wait user server args version
p_name sunrpc_tcp tcp wait user server args version
where p_name is the symbolic name of the program as it appears in the RPC routine, server is the program implementing the server, and version is the version number of the service.
If the same program handles multiple versions, then the version number can be a range, as in the following:
rstatd sunrpc_udp udp wait root /usr/sbin/rpc.rstatd rstatd 100001 1-2
RPC subroutines are part of the libc.a library. Add the following line to the Makefile file:
CFLAGS=-D_BSD -DBSD_INCLUDES