This chapter provides a high-level description of the Remote Procedure
Call (RPC) model specified by this document. Implementations must comply
with the specified model in order to guarantee both application
portability and interoperability between RPC peers.1
The RPC mechanism maps the local procedure call paradigm onto an environment where the calling procedure and the called procedure are distributed between different execution contexts that usually, but not necessarily, reside on physically separate computers that are linked by communications networks.
A procedure is defined as a closed sequence of instructions that is entered from, and returns control to, an external source. Data values may be passed in both directions along with the flow of control. A procedure call is the invocation of a procedure. A local procedure call and an RPC behave similarly; however, there are semantic differences due to several properties of RPCs:
While a local procedure call depends on a static relationship between the calling and the called procedure, the RPC paradigm requires a more dynamic behaviour. As with a local procedure call, the RPC establishes this relationship through binding between the calling procedure (client) and the called procedure (server). However, in the RPC case a binding usually depends on a communications link between the client and server RPC run-time systems. A client establishes a binding over a specific protocol sequence to a specific host system and endpoint.
Unlike a local procedure call, which commonly uses the call-by-reference passing mechanism for input/output parameters, RPCs with input/output parameters have copy-in, copy-out semantics due to the differing address spaces of calling and called procedures.
Beyond execution errors that arise from the procedure call itself, an RPC introduces additional failure cases due to execution on physically separate machines. Remoteness introduces issues such as remote system crash, communications links, naming and binding issues, security problems, and protocol incompatibilities.
Executing procedure calls across physical machine boundaries has additional security implications. Client and server must establish a security context based on the underlying security protocols, and they require additional attributes for authorising access.
The RPC model makes a functional distinction between clients and servers. A client requests a service, and a server provides the service by making resources available to the remote client.
Two entities partially determine the relationship between a client and
a server instance: RPC interfaces and RPC objects. Both interfaces and
objects are identified by UUIDs. (See
An RPC interface is the description of a set of remotely callable
An interface identifier is a UUID that uniquely identifies the
RPC objects are either server instances or other resources that are
operated on and managed by RPC servers, such as devices, databases
and queues. Servers here are the instances of services (applications)
that are provided to RPC clients. Binding to RPC objects is
facilitated by RPC, but object usage is optional and in the domain of
application policies. Hence, RPC objects provide a means of
object-oriented programming in the RPC environment, but allow
applications to determine how these entities are actually being
implemented. The object identifier is a UUID, called an object
UUID that uniquely identifies the object on which the RPC is
Object UUIDs for server instances and for resources cannot be intermixed. If multiple server instances are distinguished via object UUIDs (also called instance UUIDs), each binding operation only supports a single embedded object UUID. If the usage of multiple object UUIDs is required, these may be passed as explicit call arguments.
Servers may refer to multiple RPC objects, and RPC objects may be referenced by multiple servers; servers typically use different object UUIDs to refer to the same RPC object. RPC objects may be accessed by operations defined by one or a set of RPC interfaces.
To identify classes of RPC objects, these may also be tagged with
type UUIDs. RPC has no predefined notion of an object or types
A client may bind to a server for a particular interface only if the client interface meets with the following conditions:
From the version numbering rules, it can be seen that the minor version number is used to indicate that an upwardly compatible change has been made to the interface. The rules for changing version numbers are as follows:
The following are upwardly compatible changes, and may be made to an existing interface definition provided the minor or major version number is increased:
Any change to an existing interface definition not listed in
A specific remote operation, equivalent to a local function call in C,
is instantiated by one RPC. The operation performed by an RPC is
determined by the interface (identifier and version) and the operation
number. Each instance of an RPC is uniquely identified by a distinct
pair of session and call identifiers.2
A session is uniquely determined by the activity (connectionless
Multiple session identifiers may correspond to a single client and server execution context pair, which is identified by the cas_id (connectionless protocol, obtained through the conversation manager handshake) or the assoc_group_id (connection-oriented protocol).
A called remote procedure can initiate another RPC. The second RPC is nested with the first RPC. Initial and nested RPCs are distinct according to the definition of an RPC; they are different RPC threads and operate on distinct sessions.
A specialised form of nested RPC involves a called remote procedure that makes an RPC to the execution context of the calling client application thread. Calling the original client's execution context requires that a server application thread is listening in that execution context. Also, the second remote procedure needs a server binding handle for the execution context of the calling client.
Execution semantics identify how many times a server-side procedure may be executed during a given client-side invocation. The guarantees provided by the RPC execution semantics are independent of the underlying communications environment. All invocations of remote procedures risk disruption due to communications failures. However, some procedures are more sensitive to such failures, and their impact depends partly on how reinvoking an operation transparently to the client affects its results.
The operation declarations of an RPC interface definition indicate the effect of multiple invocations on the outcome of the operations. The at-most-once execution semantic guarantees that operations are not executed multiple times.
The execution semantics for RPCs are summarised in
Semantics | Meaning | |
---|---|---|
at-most-once | The operation must execute either once, partially, or not at all. This is the default execution semantics for remote procedure calls (also called non-idempotent). | |
idempotent | The operation can execute more than once. The manager routine must
assure that executing more than once using the same input arguments
does not produce undesirable side effects.
An implementation of the RPC protocol machines may treat an idempotent call request as a non-idempotent call. This is a valid transformation. RPC supports maybe semantics and broadcast semantics as special forms of idempotent operations. | |
_ | ||
Semantics | Meaning | |
_ | _ | |
maybe | The caller neither requires nor receives any response or fault indication for an operation, even though there is no guarantee that the operation completed. An operation with maybe semantics is implicitly idempotent and must lack output parameters. | |
_ | _ | |
broadcast | The operation is always broadcast to all host systems on the local network, rather than delivered to a specific server system. An operation with broadcast semantics is implicitly idempotent; broadcast semantics are supported only by connectionless protocols. |
With the RPC communications protocols, a maybe call lacks
execution guarantees; an idempotent call, including
broadcast, guarantees that the data for an RPC is received and
processed zero or more times; and an at-most-once call
guarantees that the call data is received and processed at most one
time (may be executed partially or zero times). Both idempotent
and at-most-once services guarantee that a sequence of calls in
a session are processed in the order of invocation by the client.
Server application code can store information it needs for a particular client, such as the state of previous RPCs the client made, as part of a client context. During a series of remote procedure calls, the client may need to refer to the client context maintained by a specific server instance. To provide a client with a means of referring to its client context, the client and server pass back and forth an RPC-specific parameter called a context handle. A context handle is a reference to the server instance and the client context of a particular client. A context handle ensures that subsequent RPCs from the client can reach the server instance that is maintaining context for the client (commonly known as "stateful" servers).
On completing the first procedure in a series, the server returns a context handle to the client. The context handle identifies the client context that the server uses for subsequent operations. The client stores the handle and can return it unchanged in subsequent calls to the same server. Using the handle, the server finds the context and provides it to the called remote procedure.
The server maintains the client context for a client until one of the following occurs:
For a specification of the context_handle attribute, its usage,
and its relation to binding handles, see
Each RPC occurs in the context of a thread. A thread is a
single sequential flow of control with one point of execution at any
instant. A thread created and managed by application code is an
application thread.
RPC applications use application threads to issue both RPCs and RPC run-time calls. An RPC client contains one or more client application threads, each of which may perform one or more RPCs. (A client application thread may not make any RPC, or zero calls may be performed if a communications failure was detected.)
In addition, for executing called remote procedures, an RPC server
uses one or more call threads that the RPC run-time system provides.
An RPC extends across client and server execution contexts. Therefore,
when a client application thread calls a remote procedure, it becomes
part of a logical thread of execution known as an RPC thread.
The RPC thread of a successful RPC moves through the execution phases
illustrated in
The execution phases of an RPC thread, as shown in
While a called remote procedure is executing, the call thread becomes part of the RPC thread. When the call finishes executing, the call thread ceases being part of the RPC thread.
An RPC server can concurrently execute as many RPCs as it has call
threads. When a server is using all of its call threads, the server
application thread may continue listening for incoming RPCs. While
waiting for a call thread to become available, the RPC server run-time
environment may queue incoming calls. Queuing incoming calls avoids RPCs
failing during short-term congestion. This queue capability for
incoming calls is implementation-dependent.
A cancel is an asynchronous notification from a cancelling thread to a cancelled thread, generally used to cancel an operation in progress. The RPC architecture extends the semantics of cancels to incorporate RPCs.
In the absence of an RPC, both the thread initiating a cancel and the thread to be cancelled must belong to the same local execution context. In the presence of an RPC, the desired semantic is that the system should behave as if the remote procedure were local and part of the cancelled thread's execution context. That is, if a thread has called a remote procedure, is waiting for the remote procedure to complete, and is cancelled, its RPC run-time system will handle the cancel and forward it to the called procedure's RPC run-time system, where it will locally cancel the thread running the called procedure.
RPC forces the convention that the ability to cancel asynchronously must be lexically scoped (in the same lexical unit, such as a function or procedure). Therefore, at the completion of an RPC, the RPC run-time system will always restore the asynchronous delivery state prior to the call, regardless of any unbalanced asynchronous cancellability that may exist within the RPC. This behaviour may be different from the local case, where unbalanced asynchronous cancelability may not be detected. (For further information on the semantics of threads and cancels, see IEEE P1003.4a.)
Well-behaved programs must also observe the convention that general cancelability must be lexically scoped. If the caller is within a general cancelability disabled scope at the time an RPC is called, RPC will never see the cancel; it will only become visible after the RPC completes and the caller ends the general cancellability disabled scope.
Well-behaved remote procedures, as well as the RPC system, do not pass their thread identity to any other (user) threads, and therefore cannot be locally cancelled. There is one exception to this: if the RPC run-time system ascertains that communications are lost, it cancels the called procedure to initiate its orderly termination. Therefore, any remote procedure must still protect its invariants with a suitable general and asynchronous cancellability scope. RPC must provide a means of specifying that a remote procedure begins (and ends) its execution in a disabled scope for either general or asynchronous cancellability in order to avoid a race condition between the beginning of the procedure and establishing the cancellability scopes within the procedure.
Cancels operate on the RPC thread exactly as they would on a local
thread, except for an application-specified cancel time-out period. A
cancel time-out period is an optional value that limits the
During an RPC, if its thread is cancelled and the cancel time-out period expires before the call returns, the calling thread regains control and the call is orphaned at the server. An orphaned call may continue to execute in the call thread. However, the call thread is no longer part of the RPC thread, and the orphaned call is unable to return results to the client; the caller does not know whether or not the called routine has terminated yet, how it may have terminated, or even if it executed.
While executing as part of an RPC thread, a call thread can be cancelled only by a client application thread. The local cancel semantics can be guaranteed for all RPCs that do not fail due to server or communication errors. That is, cancels can be transferred remotely to or from the called procedures. In the case where an RPC fails due to either server or communication failures, it is indeterminate whether cancels were preserved, just as it is indeterminate whether the procedure executed zero or one time.
The RPC architecture specifies neither what causes a cancel, nor what
an application does when cancelled. This is application-specific.
Nor does the architecture place any semantics on
the cancel; again the application must decide what it means.
The following sections cover binding, endpoint addresses and name services.
Binding expresses the relationship between a client and a server. Binding includes information that associates the client's invocation of an RPC with the server's implementation (that is, the manager routines) of the call. The binding information identifying a server to a client is called server binding information. Binding information identifying a client to a server is called the client binding information.
To make a specific instance of locally maintained binding information available to a given server or client, the RPC run-time system creates a local reference, called the binding handle. Servers and clients use binding handles to refer to binding information in RPC run-time calls or remote procedure calls.
Binding information includes the following components:
An RPC server specifies to the RPC run-time system the set of protocol sequences to use when listening for incoming calls.
RPC run-time system creates one or more server binding handles for each protocol sequence. Each server binding handle refers to binding information for a single potential binding. A server obtains a complete list of its binding handles from its RPC run-time system.
A client obtains a single binding handle or a set of binding handles from its RPC run-time system. It selects one binding handle for invoking one or a sequence of RPCs to a given server. Server binding information for each server binding handle on a client contains binding information for one potential binding.
If the network address in the server binding information on a client
refers to a "host-addressable" network service, it may be partial,
lacking an endpoint. A partially bound binding handle corresponds to
a system, but not to a particular server instance. When invoking a
remote procedure call using a partially bound binding handle, a client
gets an endpoint either from the interface specification or from an
endpoint map on the server's system. Adding the endpoint to the
server binding information results in a fully bound binding handle.
An endpoint is the address of a specific server instance on a host system. Two types of endpoints exist: well-known endpoints and dynamic endpoints.
Well-known endpoints can be declared for an RPC interface (in the interface declaration) or for a server instance.
The endpoint mapper is an RPC service that manages dynamic endpoints. The remainder of this section specifies the services offered by an endpoint mapper, and discusses how the RPC run-time system uses those services.
The endpoint mapper service may only be applicable to systems that provide "host-addressable" transport services. The notions of endpoints and well-known endpoints are derived from the Internet Protocol Suite, but may be applicable to other network protocol stacks as well. In order to provide for application portability, it is mandatory, when dynamic endpoints are used, that RPC implementations on systems with these types of transport services comply with this specification.
An endpoint mapper may be used to help resolve the address of a server. This is typically used with network addresses that have a small range of values for the local endpoint address (for example, an IP port) and/or by servers that want to dynamically define an endpoint address. Typically, in such cases a server exports its node address to the name service. The endpoint mapper's endpoint address is well known. The server also registers its interfaces, interface version and object UUIDs with its local endpoint mapper, along with a dynamically determined local endpoint address.
An RPC client wishing to use the server will (typically) query the
name service to determine the address, using one of the RPC name
service APIs. The address returned includes a value that signifies the
endpoint mapper endpoint, which is a well-known endpoint (see
An erroneous or malicious endpoint mapper implementation can cause denial of service, but otherwise does not affect the security of the system.
The use of the endpoint mapping service is transparent to client name service operations.
At the client stub to RPC run-time interface, every RPC specifies a primitive binding handle that includes the server address. If the system-specific endpoint address specified is one of the well-known endpoint addresses for the endpoint mapping service, and the interface specified is not the endpoint mapping service interface3, then the endpoint mapping service on the desired target system is requested to resolve the partially bound server binding handle into a fully bound server binding handle.
The client run-time system of a connection-oriented RPC issues a call to the endpoint mapping service on the desired target system prior to the originating call. When the call successfully completes, the effective endpoint for the binding handle is set to the dynamically determined value returned by the endpoint mapping service. This endpoint is then used to make the actual call requested.
The client run-time system of a connectionless RPC issues the first request of the originating call with a partially bound server binding handle. The endpoint mapping service resolves this partially bound handle into a fully bound server binding handle and redirects the call. The server then returns the dynamically determined value directly to the client for use in subsequent messages.
If the request for resolving the partially bound server binding handle into a fully bound server binding handle fails, then the originating RPC fails with an error status.
The use of an endpoint mapping service is transparent to the call and
the server RPC run-time system with one exception: with a dynamically assigned
port, when the server exports binding information to a name service,
the export operations must export a value that signifies the endpoint
mapper service rather than the dynamically assigned port.
The RPC architecture requires a means to allow clients to discover appropriate servers. This specification defines the use of a distributed name service to store information about servers, service groups and configuration profiles. A candidate name service must be able to store all the object attributes specified here. Multiple name services may satisfy this requirement, but a client and server can only bind successfully through a name service if they share use of some common information base.
Each name service object entry consists of a number of attributes.
If a redundant value is inserted in the set, a new entry is not made. If a non-existent value is removed from a set, no error is generated. The order of elements in a set is not defined, and any order observed is neither significant nor deterministic; that is, implementations may vary, but applications must not make any assumptions on the ordering.
Different name services may have different syntaxes to represent object names; their object name syntax is not specified in the RPC specification. The RPC operations that use object names require the different syntaxes to be explicitly distinguished to avoid ambiguity and to allow the implementations to interpret the name values properly. Since different name services also may have different conventions for naming attributes, and since the names of the attributes are not directly user visible through the RPC services, for each different name service there is a mapping from the defined class names to name service-specific names.
The following declarations define the name service data types required
typedef struct {
byte major;
byte minor;
} class_version_t;
/* Opaque octet string */
typedef struct {
u_int16 count; /* store little-endian */
[ptr, size_is(count)] byte *value;
} octet_string_t;
/* One layer in a protocol tower */
typedef struct {
octet_string_t protocol_id;
octet_string_t address;
} prot_and_addr_t;
/* A protocol tower */
typedef struct {
u_int16 count; /* store little-endian */
[ptr, size_is(count)] prot_and_addr_t *floors;
} protocol_tower_t;
/*
* Name service names are stored as canonical string names
* according to the rules for the relevant name service.
*/
typedef byte canonical_string_name_t[]; /* Using ASCII encoding */
/* An element within a profile.
* There may be multiple set members for the same interface.
* The UUID NIL with versions 0 indicates the default profile,
* i.e. linkage to a parent profile.
*/
typedef struct {
uuid_t if_uuid; /* store little-endian */
u_int16 if_vers_major; /* store little-endian */
u_int16 if_vers_minor; /* store little-endian */
u_int8 priority; /* legal values are 0
(highest) through 7 */
u_int8 annot_size; /* annotation size */
u_int16 member_size; /* member size, store
little-endian */
[size_is(annot_size)] byte annotation[]; /* ASCII encoding*/
[size_is(member_size)] canonical_string_name_t member;
} profile_element_t;
typedef char class_name_t[31]; /* ISO_LATIN_1 Attribute class name */
In order to communicate, the RPC client and server must agree both upon the protocols that both will employ, and upon the operational parameters of these protocols. In addition, client and server must possess address information that indicates to each layer of protocol where to deliver data.
A protocol tower (encoded by the protocol_tower_t data type)
is a protocol sequence along with its related address and
protocol-specific information. A protocol sequence is an ordered list of
protocol identifiers. Protocol identifiers are octet strings,
Addressing and other protocol specific information is affiliated with each protocol identifier in a protocol tower. The addressing information indicates the access point through which this layer provides service to the next higher layer protocol in the sequence. Other protocol-specific information may be included in this field. The interpretation of this address and other information is protocol-dependent. Typically, a protocol sequence will extend from the network layer to the application layer.
An RPC client and server must have at least one common protocol tower where the protocol identifiers (the left-hand sides) match. Otherwise they do not share a common stack of protocols and cannot communicate.
Protocol Identifier for | Identifier Value | Related Information |
---|---|---|
Layer i+1 protocol identifier | Layer i+1 value | Layer i+1 parameters and address data selecting layer i+2 protocol. |
Layer i protocol identifier | i value | Layer i parameters and address data selecting layer i+1 protocol. |
Layer i-1 protocol identifier | i-1 value | Layer i-1 parameters and address data selecting layer i protocol. |
The server_name attributes of a single name service entry describe a single RPC server (that is, instance) and its protocol and addressing information. Any name service object class may contain server_name attributes if not otherwise prohibited by the class.
The class RPC_Entry may be used if no other class is applicable.
The hierarchy of protocols and addresses is expressed in terms of a
protocol_tower data type. The server_name object attributes
are defined in
Single or | |||
---|---|---|---|
Attribute Name | Set Valued | Data Type | Description |
CDS_Class | Single | class_name_t | An existing class, or RPC_Entry if created by RPC. |
CDS_ClassVersion | Single | class_version_t | An existing class version of the class definition or, 1.0 if created by RPC. |
RPC_ClassVersion | Single | class_version_t | Version 1.0; may already exist. |
RPC_ObjectUUIDs | Set | uuid_t, little-endian order | Optional UUIDs of the referenced server objects. |
RPC_Codesets | Single | rpc_codeset_mgmt_t | The code sets supported by this server. |
CDS_Towers | Set | protocol_tower_t | The set of protocol towers for this server. |
The CDS_Towers attribute must encode both the RPC-specific protocol
layers, and the underlying network, transport, session and
presentation layers, as applicable. The RPC-specific layers are "on
top" (lowest array subscripts) and are specified in
Protocol | |||
---|---|---|---|
Identifier for | Identifier Format | Related Information | Comments |
Interface,
major version | UUID_type_identifier | The minor version, u_int16, little-endian order. | Value derived from encoding algorithm (see
|
Transfer Syntax,
major version | UUID_type_identifier | The minor version, u_int16, little-endian order. | Value derived from encoding algorithm (see
|
RPC Protocol and
major version | u_int8 | The minor version u_int16, little-endian order. | See
|
The encoding of the protocol identifier for a particular interface,
or for a particular transfer syntax is specified in
The other layers depend on the particular environment.
Protocol | |||
---|---|---|---|
Identifier for | Identifier Value | Related Information | Comments |
Interface,
major version | UUID_type_identifier | Minor version | Value derived from encoding algorithm (see
|
NDR V1.1
Transfer Syntax | UUID_type_identifier | - | Value derived from encoding algorithm (see
|
RPC CO protocol,
major version | 0b hexadecimal | Minor version | - |
DOD TCP | 07 hexadecimal | Port | Port address is 16-bit unsigned integer, big-endian order. |
DOD IP | 09 hexadecimal | Host address | Host address is 4 octets, big-endian order. |
A name service group attribute refers to a management defined group of equivalent servers. Any name service object class may contain a group attribute if not otherwise prohibited by the class. The class RPC_Entry may be used if no other class is applicable.
Each element of the set RPC_Group is of the data type canonical_string_name_t and represents the name of another name service object containing either a name service server_name attribute or another name service group attribute.
The group object attributes are defined in
Single or | |||
---|---|---|---|
Attribute Name | Set Valued | Data Type | Description |
CDS_Class | Single | class_name_t | An existing class, or RPC_Entry if created by RPC. |
CDS_ClassVersion | Single | class_version_t | An existing class version of the class definition or 1.0 if created by RPC. |
RPC_ClassVersion | Single | class_version_t | Version 1.0; may already exist. |
RPC_Group | Set | canonical_string_name_t | The set of server object names or service group names for this service_group. |
A name service profile attribute refers to a principal or host's desired server profile. Any name service object class may contain a profile attribute if not otherwise prohibited by the class. The class RPC_Entry may be used if no other class is applicable.
Each element of the set attribute RPC_Profile is of the data type profile_element_t and represents an ordered list of providers for a particular interface (UUID). A profile with the nil interface UUID indicates the default profile to use if no matching interface is found. Each profile element contains an ordered list of the names of name service objects containing any combination of server_name, group and/or profile attributes.
The profile object attributes are defined in
Single or | |||
---|---|---|---|
Attribute Name | Set Valued | Data Type | Description |
CDS_Class | Single | class_name_t | An existing class, or RPC_Entry if created by RPC. |
CDS_ClassVersion | Single | class_version_t | An existing class version of the class definition, or 1.0 if created by RPC. |
RPC_ClassVersion | Single | class_version_t | Version 1.0; may already exist. |
RPC_Profile | Set | profile_element_t | The set of providers comprising the configuration profiles. |
The encoding of the name service objects may be viewed from three perspectives:
A name service entry storing RPC attributes uses the class
value RPC_Entry if no other class applies.
The RPC service detects various classes of unusual or exceptional terminations of an RPC. These failure cases are either originated in the server application and manager routines, detected and raised in the server run-time system, or are communications failures detected locally in the client RPC run-time system.
Fault status conditions (fault PDU) always indicate error conditions that are generated in the manager routines or server application. The server protocol machine does not process fault status codes.
Reject status conditions (reject PDU in connectionless protocol, fault PDU in connection-oriented protocol) usually originate in the protocol machines or the underlying resources (communications, systems) and may require additional processing such as clean up of resources at the server protocol machine. The following set of reject messages indicate that a failed call has not been executed at the RPC server:
Unless the protocol machine can detect the execution state by some
other means (connection-oriented protocol), none of the other reject
and fault conditions can determine whether a call has already been
partially executed.
[??] Some characters or strings that appear in the printed document are not easily representable using HTML.
Please note that the html version of this specification may contain formatting aberrations. The definitive version is available as an electronic publication on CD-ROM from The Open Group.
Contents | Next section | Index |