The Remote Procedure Call (RPC) message protocol consists of two distinct structures: the call message and the reply message. A client makes a remote procedure call to a network server and receives a reply containing the results of the procedure's execution. By providing a unique specification for the remote procedure, RPC can match a reply message to each call (or request) message.
The RPC message protocol is defined using the eXternal Data Representation (XDR) data description, which includes structures, enumerations, and unions. See "RPC Language Descriptions" for more information.
When RPC messages are passed using the TCP/IP byte-stream protocol for data transport, it is important to identify the end of one message and the start of the next one.
The RPC message protocol requires:
To help reduce network administration and eliminate protocol roll-over errors, implementation bugs, and user errors, features that detect the following conditions are useful:
The initial structure of an RPC message is as follows:
struct rpc_msg { unsigned int xid; union switch (enum msg_type mtype) { case CALL: call_body cbody; case REPLY; reply_body rbody; } body; };
All RPC call and reply messages start with a transaction identifier, xid , which is followed by a two-armed discriminated union. The union's discriminant is msg_type, which switches to one of the following message types: CALL or REPLY. The msg_type has the following enumeration:
enum msg_type { CALL = 0, REPLY = 1 };
The xid parameter is used by clients matching a reply message to a call message or by servers detecting retransmissions. The server side does not treat the xid parameter as a sequence number.
The initial structure of an RPC message is followed by the body of the message. The body of a call message has one form. The body of a reply message, however, takes one of two forms, depending on whether a call is accepted or rejected by the server.
Each remote procedure call message contains the following unsigned integer fields to uniquely identify the remote procedure:
The body of an RPC call message takes the following form:
struct call_body { unsigned int rpcvers; unsigned int prog; unsigned int vers; unsigned int proc; opaque_auth cred; opaque_auth verf; 1 parameter 2 parameter . . . };
The parameters for this structure are:
The client can send a broadcast packet to the network and wait for numerous replies from various servers. The client can also send an arbitrarily large sequence of call messages in a batch to the server.
The RPC protocol for a reply message varies depending on whether the call message is accepted or rejected by the network server.
The reply message to a request contains information to distinguish the following conditions:
The RPC reply message takes the following form:
enum reply_stat stat { MSG_ACCEPTED = 0, MSG_DENIED = 1 };
The enum reply_stat discriminant acts as a switch to the rejected or accepted reply message forms.
An RPC reply message for a request accepted by the network server has the following structure:
struct accepted_reply areply { opaque_auth verf; union switch (enum accept_stat stat) { case SUCCESS: opaque results {0}; /* procedure specific results start here */ case PROG_MISMATCH: struct { unsigned int low; unsigned int high; } mismatch_info; default: void; } reply_data; };
The structures within the accepted reply are:
The accept_stat enumeration data type has the following definitions:
enum accept_stat { SUCCESS = 0, /* RPC executed successfully */ PROG_UNAVAIL = 1, /* remote has not exported program */ PROG_MISMATCH = 2, /* remote cannot support version # */ PROC_UNAVAIL = 3, /* program cannot support procedure */ GARBAGE_ARGS = 4, /* procedure cannot decode params */ };
The structures within the accept_stat enumeration data type are defined as follows:
Note: An error condition can exist even when a call message is accepted by the server.
A call message can be rejected by the server for two reasons: either the server is not running a compatible version of the RPC protocol, or there is an authentication failure.
An RPC reply message for a request rejected by the network server has the following structure:
struct rejected_reply rreply { union switch (enum reject_stat stat) { case RPC_MISMATCH: struct { unsigned int low; unsigned int high; } mismatch_info; case AUTH_ERROR: enum auth_stat stat; };
The enum reject_stat discriminant acts as a switch between RPC_MISMATCH and AUTH_ERROR. The rejected call message returns one of the following status conditions:
enum reject_stat { RPC_MISMATCH = 0, /* RPC version number is not 2 */ AUTH_ERROR = 1, /* remote cannot authenticate caller */ };
When RPC messages are passed using the TCP/IP byte-stream protocol for data transport, it is important to identify the end of one message and the start of the next one. This is called record marking (RM).
A record is composed of one or more record fragments. A record fragment is a four-byte header, followed by 0 to 232 -1 bytes of fragment data. The bytes encode an unsigned binary number, similar to XDR integers, in which the order of bytes is from highest to lowest. This binary number encodes a Boolean and an unsigned binary value of 31 bits.
The Boolean value is the highest-order bit of the header. A Boolean value of 1 indicates the last fragment of the record. The unsigned binary value is the length, in bytes, of the data fragment.
Note: A protocol disagreement between client and server can cause remote procedure parameters to be unintelligible to the server.