この節では、RPC メッセージプロトコルを、XDR データ記述言語を使用して説明します。メッセージは、次の例のように、トップダウン方式で定義されます。
enum msg_type {
CALL = 0,
REPLY = 1
};
/*
* 呼び出しメッセージに対する応答には、2 つの形式があります。メッセージが
* 受け入れられた場合と拒絶された場合のどちらかです。
*/
enum reply_stat {
MSG_ACCEPTED = 0,
MSG_DENIED = 1
};
/*
* 呼び出しメッセージが受け入れられた場合、
* リモートプロシージャを呼び出したときの
* ステータスが次のように示されます。
*/
enum accept_stat {
SUCCESS = 0, /* RPC が正常に実行された */
PROG_UNAVAIL = 1,
/* リモートサービスにエクスポートされたプログラムがない */
PROG_MISMATCH = 2, /* リモートサービスがそのバージョン番号を
* サポートしていない */
PROC_UNAVAIL = 3, /* プログラムがその手続きをサポートしていない */
GARBAGE_ARGS = 4 /* 手続きが引数を復号化できない */
};
/*
* 呼び出しメッセージが拒絶された原因
*/
enum reject_stat {
RPC_MISMATCH = 0, /* RPC のバージョン番号が 2 でない */
AUTH_ERROR = 1 /* リモートサービスで呼び出し側の認証エラー */
};
/*
* 認証が失敗した原因
*/
enum auth_stat {
AUTH_BADCRED = 1, /* 認証エラーの原因 */
AUTH_REJECTEDCRED = 2, /* クライアントは新規セッションが必要 */
AUTH_BADVERF = 3, /* ベリファイアのエラー */
AUTH_REJECTEDVERF = 4, /* ベリファイアの失効または再使用 */
AUTH_TOOWEAK = 5 /* セキュリティによる拒絶 */
};
/*
* RPC メッセージ:
* どのメッセージもトランザクションID xid と
* それに続く識別型共用体(アームは 2 つ) で始まります。
* 共用体の要素識別子はmsg_type で、2 つのメッセージタイプのうち
* どちらのタイプのメッセージかを示します。REPLY メッセージの xid は、
* 対応するCALL メッセージのxid に一致します。注意: xid フィールドは、
* クライアント側で応答メッセージがどの呼び出しメッセージに対応するかを
* 調べるか、サーバー側で再送信かどうかを調べるためにだけ使用できます。
* サービス側では xid をシーケンス番号として使用することはできません。
*/
struct rpc_msg {
unsigned int xid;
union switch (msg_type mtype) {
case CALL:
call_body cbody;
case REPLY:
reply_body rbody;
} body;
};
/*
* RPC 要求呼び出しの本体:
* RPC プロトコル仕様のバージョン 2 では、rpcvers は 2 でなければ
* なりません。prog、vers、proc の各フィールドにはそれぞれ、
* リモートプログラム、そのバージョン番号、リモートプログラムに入っている
* 呼び出し対象の手続きを指定します。これらのフィールドに続いて
* 2 つの認証パラメータ cred (認証資格) と verf (認証ベリファイア)
* があります。この 2 つの認証パラメータの後には、
* リモートプロシージャへの引数が入りますが、それらは特定プログラムの
* プロトコルで指定されます。
*/
struct call_body {
unsigned int rpcvers; /* この値は 2 でなければならない */
unsigned int prog;
unsigned int vers;
unsigned int proc;
opaque_auth cred;
opaque_auth verf;
/* ここからは手続きに固有の引数 */
};
/*
* RPC 要求への応答の本体:
* 呼び出しメッセージは受け入れられたか拒絶されたかのどちらか
*/
union reply_body switch (reply_stat stat) {
case MSG_ACCEPTED:
accepted_reply areply;
case MSG_DENIED:
rejected_reply rreply;
} reply;
/*
* RPC 要求がサーバーに受け入れられた場合の応答: 要求が受け入れられた場合も
* エラーはあり得ます。最初のフィールドはサーバーが呼び出し側に自分自身を
* 証明する認証ベリファイアです。次のフィールドは共用体で、
* 要素識別子は列挙型 accept_stat です。この共用体の SUCCESS アームは
* プロトコルによって異なります。
* PROG_UNAVAIL、PROC_UNAVAIL、GARBAGE_ARGP の
* アームは void です。PROG_MISMATCH アームにはサーバーが
* サポートしているリモートプログラムのバージョン番号の
* 最大値と最小値が入ります。
*/
struct accepted_reply {
opaque_auth verf;
union switch (accept_stat stat) {
case SUCCESS:
opaque results[0];
/* ここからは手続き固有の戻り値 */
case PROG_MISMATCH:
struct {
unsigned int low;
unsigned int high;
} mismatch_info;
default:
/*
* PROG_UNAVAIL、PROC_UNAVAIL、GARBAGE_ARGS
* の場合はvoid
*/
void;
} reply_data;
};
/*
* RPC 要求がサーバーに拒絶された場合の応答:
* 要求が拒絶されるのには 2 つの原因があります。互換性のあるバージョンの
* RPC プロトコルがサーバーで実行されていない場合(RPC_MISMATCH) と、
* サーバーが呼び出し側の認証を拒否した場合(AUTH_ERROR) です。
* RPC バージョンの不一致の場合は、サーバーがサポートしている
* RPC バージョンの最大値と最小値が返されます。
* 認証拒否の場合は、異常終了ステータスが返されます。
*/
union rejected_reply switch (reject_stat stat) {
case RPC_MISMATCH:
struct {
unsigned int low;
unsigned int high;
} mismatch_info;
case AUTH_ERROR:
auth_stat stat;
};