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

Communications Programming Concepts


RPC Message Protocol

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.

RPC Protocol Requirements

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:

RPC Messages

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.

RPC Call Message

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 {
     rpcvers_t rpcvers;
     rpcprog_t prog;
     rpcvers_t vers;
     rpcproc_t proc;
     opaque_auth cred;
     opaque_auth verf;
     1 parameter
     2 parameter . . . 
};

The parameters for this structure are:

rpcvers Specifies the version number of the RPC protocol. The value of this parameter is 2 to indicate the second version of RPC.
prog Specifies the number that identifies the remote program. This is an assigned number represented in a protocol that identifies the program needed to call a remote procedure. Program numbers are administered by a central authority and documented in the program's protocol specification.
vers Specifies the number that identifies the remote program version. As a remote program's protocols are implemented, they evolve and change. Version numbers are assigned to identify different stages of a protocol's evolution. Servers can service requests for different versions of the same protocol simultaneously.
proc Specifies the number of the procedure associated with the remote program being called. These numbers are documented in the specific program's protocol specification. For example, a protocol's specification can list the read procedure as procedure number 5 or the write procedure as procedure number 12.
cred Specifies the credentials-authentication parameter that identifies the caller as having permission to call the remote program. This parameter is passed as an opaque data structure, which means the data is not interpreted as it is passed from the client to the server.
verf Specifies the verifier-authentication parameter that identifies the caller to the server. This parameter is passed as an opaque data structure, which means the data is not interpreted as it is passed from the client to the server.
1 parameter Denotes a procedure-specific parameter.
2 parameter Denotes a procedure-specific parameter.

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.

Derived Types

For Itanium-based, the LDT (large data types) feature is turned on for compiling.

For Itanium-based, the derived types are as follows:

Derived Types in a 64-bit Environment
typedef unsigned integer rpcprog_t
typedef unsigned integer rpcvers_t
typedef unsigned integer rpcproc_t

In a 32-bit environment, the derived types are as follows:

Derived Types in a 32-bit Environment
typedef unsigned long rpcprog_t
typedef unsigned long rpcvers_t
typedef unsigned long rpcproc_t

RPC Reply Message

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.

The Reply to an Accepted Request

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:

opaque_auth verf Authentication verifier generated by the server to identify itself to the caller.
enum accept_stat A discriminant that acts as a switch between SUCCESS, PROG_MISMATCH, and other appropriate conditions.

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:

SUCCESS RPC call is successful.
PROG_UNAVAIL The remote server has not exported the program.
PROG_MISMATCH The remote server cannot support the client's version number. Returns the lowest and highest version numbers of the remote program that are supported by the server.
PROC_UNAVAIL The program cannot support the requested procedure.
GARBAGE_ARGS The procedure cannot decode the parameters specified in the call.

Note: An error condition can exist even when a call message is accepted by the server.

The Reply to a Rejected Request

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 */
};


RPC_MISMATCH The server is not running a compatible version of the RPC protocol. The server returns the lowest and highest version numbers available.
AUTH_ERROR The server refuses to authenticate the caller and returns a failure status with the value enum auth_stat. Authentication may fail because of bad or rejected credentials, bad or rejected verifier, expired or replayed verifier, or security problems.

If the server does not authenticate the caller, AUTH_ERROR returns one of the following conditions as the failure status:

enum auth_stat {
     AUTH_BADCRED      = 1, /* bad credentials      */
     AUTH_REJECTEDCRED = 2, /* begin new session    */
     AUTH_BADVERF      = 3, /* bad verifier         */
     AUTH_REJECTEDVERF = 4, /* expired or replayed  */
     AUTH_TOOWEAK      = 5, /* rejected for security*/
};

Marking Records in RPC Messages

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.


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