この節では、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; };