[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]

Communications Programming Concepts

Programming in RPC

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 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.

Assigning Program Numbers

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:

0-1xxxxxxx This group of numbers is predefined and administered by the operating system. The numbers should be identical for all system customers.
20000000-3xxxxxxx The user defines this group of numbers. The numbers are used for new applications and for debugging new programs.
40000000-5xxxxxxx This group of numbers is transient and is used for applications that generate program numbers dynamically.
60000000-7xxxxxxx Reserved.
80000000-9xxxxxxx Reserved.
a0000000-bxxxxxxx Reserved.
c0000000-dxxxxxxx Reserved.
e0000000-fxxxxxxxx Reserved.

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.

Assigning Version Numbers

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.

Assigning Procedure Numbers

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.

Using Registered RPC Programs

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
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

Using the Highest Layer of RPC

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 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:

rusers Returns information about users on a remote workstation.
havedisk Determines whether the remote workstation has a disk.
rstat Gets performance data from a remote kernel.
rwall Writes to a specified remote workstation.
yppasswd Updates a user password in the Network Information Service (NIS).

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".

Using the Intermediate Layer of RPC

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" .

Using the registerrpc Routine

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.

Using the callrpc Routine

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.

Passing Arbitrary Data Types

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:

Using the Lowest Layer of RPC

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:

Allocating Memory with XDR

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.

Starting RPC from the inetd Daemon

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. Because 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, call the svc_register routine as follows:

svc_register(transp, PROGNUM, VERSNUM, service, 0)

The final flag is 0 because 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

Compiling and Linking RPC Programs

RPC subroutines are part of the libc.a library. Add the following line to the Makefile file:


[ Previous | Next | Table of Contents | Index | Library Home | Legal | Search ]