Heading:
RPC binding
Page Numbers: Yes X: 527 Y: 10.5"
Inter-Office Memorandum
ToAlpine (formerly Sierra) designersDateFebruary 25, 1981
FromEd TaftLocationPARC/CSL
SubjectRPC bindingFile[Ivy]<Alpine>Doc>RPCBinding.bravo
XEROX
Remote Procedure Call issues may be divided into three categories:
1.Representation and encapsulation issues: how a procedure’s argument and results are represented, to what extend pointers are dereferenced, what remote procedure descriptors look like, etc.
2.Transport issues: how cooperating RPCs communicate with each other, what underlying protocols are used for reliable transmission, etc.
3.Binding issues: how IMPORTS and EXPORTS of an interface are located and bound together when clients and implementors are on different machines.
These issues are more-or-less orthogonal. In this memo, we concentrate on the third category, referring to the other two only to disclose basic assumptions we are making.
There are various styles of client-server interaction in common use today; these differ primarily in how the client and server are bound. We propose a basic RPC binding model consisting of a set of more-or-less independent operations. We then show how those operations can be combined to achieve several styles of client-server interaction.
The basic model
A machine desiring to export local interfaces or import remote interfaces via RPC runs a program implementing an interface called RPC, whose purpose is to coordinate RPC activity on that machine. RPC exports procedures for registering and otherwise manipulating local and remote interfaces. Additionally, RPCImpl contains all the ‘‘runtime’’ machinery supporting remote procedure calls and returns (i.e., most of categories 1 and 2); these functions are not exported via RPC but rather are invoked implicitly when remote procedure calls are performed.
A program desiring to export a local interface via RPC must perform the operations outlined in the following paragraphs, which will be elaborated upon later.
e1.Obtain an interface record for that interface. For our purposes, an interface record is simply an explicit, runtime representation of an interface—that is, a record of procedure descriptors for the procedures implementing that interface. (We are assuming that Cedar will provide facilities for obtaining interface records, though it is possible to fake this by instead constructing and passing around explicit records of procedures.)
e2.Register that interface with the local RPC. Registration consists of passing in the local interface record and obtaining an InterfaceID—a unique ID for that interface which can be passed to other machines. The RPC remembers the InterfaceID and the interface record so that incoming remote procedure calls mentioning that InterfaceID can be properly mapped to the corresponding local procedures.
e3.Advertise the interface, say by placing the InterfaceID and the exporting machine’s NetAddress in a data base along with any required application-specific information for naming the interface. (Or the interface may simply be passed directly to the client, if the interface has been instantiated specifically for that client rather than being made generally available.)
A program desiring to import a remote interface via RPC must perform these operations:
i1.Obtain the InterfaceID and NetAddress for the desired interface, say by looking up an application-specific name in the data base in which it was advertised.
i2.Register the InterfaceID and NetAddress with the local RPC. In this case, registration consists of passing in the InterfaceID and NetAddress and obtaining an interface record usable locally. Entries in this record are remote procedure descriptors. The RPC remembers the association so that when a call on one of those procedures causes control to enter RPCImpl, the procedure call can be passed off to the correct remote interface in the correct remote machine.
i3.Bind the resulting interface record to the IMPORTS list of the requesting local client.
Some interesting properties of this organization should be noted. First, the operations performed by the exporter and importer are roughly symmetrical: i1 corresponds to e3, i2 to e2, and i3 to e1. Second, the functional decomposition of the total binding task seems quite clean: i1 and e3 are Cedar runtime operations dealing with interface records (which exist for purposes other than facilitating RPC); i2 and e2 are RPC operations that deal solely with the local RPC machinery and not with higher-level semantics of the interfaces being registered; and i3 and e1 are naming and resource location operations that do reflect higher-level semantics.
An example
Based on this model, let us consider how we might deal with the interface FileStore. The basic idea is that we have multiple instances of FileStoreImpl, each corresponding to an independent storage volume. Each volume has a unique ID called a FileStoreID. The volumes are part of file server machines; a given file server can have more than one volume, and consequently more than one instance of FileStoreImpl.
To make the example even more concrete, let us assume that one of the procedures in this interface is OpenFile[FileID, LockMode]. FileID is the unique ID of a file known (or believed) to exist on the storage volume associated with the instance of FileStoreImpl being invoked.
Server
When the server starts up, for each storage volume on that server it performs the following operations:
s0.Instantiates FileStoreImpl for that volume.
s1.Obtains an interface record for the interface FileStore exported by that instance. The interface record is presumably a REF to a record of procedure descriptors; both the REF and the procedure descriptors are meaningful only on the local machine.
s2.Registers that interface with the local RPC, by passing in the interface record and obtaining an InterfaceID. The InterfaceID uniquely identifies that interface record (though it doesn’t describe its location), and consequently it can safely be passed outside the server machine.
s3.Records the association [FileStoreID, InterfaceID, server’s NetAddress] in a shared data base.
It is worth mentioning that operations s1 through s3 might be performed by the initialization code of FileStoreImpl itself.
Client
A client desires to open a file given a FileStoreID and FileID. (We assume that the FileStoreID has already been determined by some higher-level client, e.g., the Cedar Universal File System.) It performs the following operations:
c1.Looks up the FileStoreID in the data base, obtaining the InterfaceID and server’s net address.
c2.Registers the InterfaceID and NetAddress with the local RPC, and obtains an interface record. The interface record is a REF to a record of remote procedure descriptors, whose invocation will cause the RPC runtime machinery to be invoked. However, it should be emphasized that this interface record (and probably even the procedure descriptors themselves) are local, i.e., their representations are not meaningful outside the client machine.
c3.Assigns this interface record to a variable (say, fs1) of type FileStore in the client’s IMPORTS list.
c4.Calls fs1.OpenFile[FileID, LockMode].
Now, step c4 actually performs a remote procedure call, invoking some RPC machinery whose details have not yet been worked out. But the basic idea is that control transfers to the local RPCImpl with the interface record and procedure index as arguments. The interface record is mapped to an InterfaceID, and the InterfaceID and procedure index are sent to the RPC at the NetAddress registered in step c2. The server’s RPCImpl maps the InterfaceID to the local interface record registered in step s2, and finally transfers control to the selected local procedure in that interface record.
Other styles of client-server interaction
Generic interfaces vs. specific instances
In the foregoing example, a client binds to a specific instance of an interface, namely the one associated with a particular resource or entity (the FileStoreID in this case). One can also imagine situations in which a client doesn’t care which instance of an interface it binds to.
In this case, the interface record binding and RPC operations (e1, e2, i2, and i3) would be exactly the same, but the information maintained in the data base (e3 and i1) would be somewhat different. One would instead record something like [InterfaceTypeID, LIST OF [InterfaceID, NetAddress]], where InterfaceTypeID is some encoding of the interface’s type (or perhaps the type name itself and a version stamp). A program exporting that interface would add itself to the list, and a program importing it would make an arbitrary selection from the elements of the list.
Interfaces instantiated on demand
Another familiar situation is the one in which an interface is instantiated at the request of a client to serve that client exclusively. This is best exemplified by the present-day FTP server. This is implemented by a rendezvous server that listens for connection requests; for each request, it creates an independent instance of the FTP server to execute subsequent commands for the requesting client.
This also is easily mapped into the RPC framework. The server machine instantiates a RendezvousServer, and registers and advertises this instance in the usual way. (There are some possible shortcuts here, such as having a ‘‘well-known’’ InterfaceID for a RendezvousServer, much the same as we currently have a well-known socket for an FTP rendezvous server.)
RendezvousServer exports a procedure CreateFTPServer, which creates an instance of interface FTPServer on the same machine and returns an interface record. FTPServer exports the procedures that perform the actual FTP server’s operations, along with a Destroy procedure that destroys the instance.
A client desiring to perform FTP interactions with some server first obtains an interface record for RendezvousServer on that machine, using the procedure described previously. It assigns it to a variable rs of type RendezvousServer and then calls rs.CreateFTPServer. This remote procedure call causes FTPServer to be instantiated on the server machine and an interface record to be returned. (Note that the server’s interface record must be converted into an InterfaceID and registered with the server’s RPC, and the InterfaceID converted into a client interface record and registered with the client’s RPC; it might be practical for this to be done automatically.) The client now has an interface record for a private instance of FTPServer which it can call directly.
Related issues
Authentication
For the most part, authentication can be treated as the responsibility of the client and server programs, not of the RPC binding mechanism. That is, the client and server first create an unauthenticated binding using the procedures already described, then go through an authentication handshake (presumably using RPC) between each other and an authentication server.
There is room for variability in what is being authenticated. For example, the client might be concerned whether it is communicating with an authentic FileStoreImpl; or alternatively it might want to authenticate the actual FileStoreID.
One authentication-related issue which can’t be evaded in the design of RPC is that of secure communication. If remote procedure calls and returns are to be secure, encryption and decryption must occur at or below the level of RPCImpl. Consequently, at a minimum the clients of RPC must be able to specify the encryption key being used across a given interface (i.e., associated with a given InterfaceID). An additional complication is that the server’s RPC must keep track of all clients of a multiple-client interface, unless public-key encryption is used.