RPC 呼び出しメッセージには、呼び出される手続きを一意に識別する次の 3 つの符号なしフィールドがあります。
リモートプログラム番号
リモートプログラムのバージョン番
リモートプロシージャ番号
プログラム番号は、プログラム番号の登録にあるように、中央の 1 人の管理者が決定します。
プログラムを最初に作成したときは、バージョン番号は通常 1 になります。新規プロトコルは通常、品質と安定性がより高い、成熟したプロトコルへと進化します。このため、コールメッセージのバージョンフィールドで、呼び出し側が使用するプロトコルのバージョンを指定します。バージョン番号を使用することにより、これまで使用していたプロトコルと新規プロトコルとが同じサーバープロセスで使用可能になります。
手続き番号では、どの手続きを呼び出すかを指定します。手続き番号は、各プログラムのプロトコル仕様に記されています。たとえば、ファイルサービスのプロトコル仕様には、手続き番号 5 を読み取り、手続き番号 12 を書き込みなどと記されます。
リモートプログラムのプロトコルがバージョンが変わるたびに変更されるように、RPC メッセージプロトコルも変わることがあります。したがって、呼び出しメッセージには RPC バージョン番号も入っています。ここで説明する RPC のバージョン番号は常に 2 です。
要求メッセージに対する応答メッセージには、次に示すエラー条件を識別できるような情報が入っています。
RPC のリモートプログラム側がプロトコルバージョン 2 を使用していない。サポートしている RPC バージョン番号の最大値と最小値が返される
リモートシステム上で指定したリモートプログラムが使用できない
リモートプログラムは要求されているバージョン番号をサポートしていない。サポートしているリモートプログラムバージョン番号の最大値と最小値が返される
要求されている手続き番号が存在しない。これは、呼び出し側のプロトコルエラーかプログラミングエラーであることが多い
サーバー側がリモートプロシージャへのパラメータに誤りがあると解釈するこのエラーもまた、クライアントとサービスの間のプロトコルの不一致による場合が多い
RPC プロトコルの一部として、呼び出し側からサービスへの認証、および、その反対方向の認証が提供されています。呼び出しメッセージには、資格とベリファイアという 2 つの認証フィールドがあります。応答メッセージには、応答ベリファイアという認証フィールドがあります。RPC プロトコル仕様では、この 3 つのフィールドはすべて次のような隠されたデータ型で定義されています。
enum auth_flavor {
AUTH_NONE = 0,
AUTH_SYS = 1,
AUTH_SHORT = 2,
AUTH_DES = 3,
AUTH_KERB = 4
/* その他のタイプも定義可能 */
};
struct opaque_auth {
enum auth_flavor; /* 認証のタイプ */
caddr_t oa_base; /* その他の認証データのアドレス */
u_int oa_length; /* データ長は MAX_AUTH_BYTES 以下 */
};
opaque_auth 構造体には、列挙型 auth_flavor に続いて、RPC プロトコルには隠された認証データが入ります。
認証フィールドに入っているデータの解釈とセマンティクスは、個々の独立した認証プロトコル仕様で定義します。さまざまな認証プロトコルについては、レコードマーク標準の節を参照してください。
認証パラメータが拒絶された場合は、応答メッセージの中に拒絶理由が返されます。
次の表のように、プログラム番号は 0x20000000 のグループへ分散されます。
表 B–1 RPC プログラム番号|
プログラム番号 |
説明 |
|---|---|
|
00000000 から 1fffffff |
ホストが定義 |
|
20000000 から 3fffffff |
ユーザーが定義 |
|
60000000 から 7fffffff |
予約 |
|
80000000 から 9fffffff |
予約 |
|
a0000000 から bfffffff |
予約 |
|
c0000000 から dfffffff |
予約 |
|
e0000000 から ffffffff |
予約 |
最初のグループの番号は全カスタマで一致している必要があり、Sun で管理しています。一般に使用できるアプリケーションをカスタマが開発した場合は、そのアプリケーションに最初のグループの番号を割り当てなければなりません。
第 2 グループの番号は特定のカスタマアプリケーションのために予約されています。この範囲の番号は、主に新規プログラムのデバッグで使用します。
第 3 グループは、動的にプログラム番号を生成するアプリケーションのために予約されています。
最後のグループは将来のために予約されているので、使用しないでください。
プロトコル仕様を登録するには、email で rpc@sun.com に送信するか、次の住所に送ってください。 RPC Administrator, Sun Microsystems, 901 San Antonio Road, Palo Alto, CA 94043
その際には rpcgen で生成した、プロトコルを記述する「.x」ファイルも同封してください。一意に識別できるプログラム番号を返送します。
標準 RPC サービスの RPC プログラム番号とプロトコル仕様は、/usr/include/rpcsvc のインクルードファイルに入っています。ただし、これらのサービスは登録されているサービスのほんの一部分にすぎません。
本来、RPC プロトコルはリモートプロシージャ呼び出しを目的に作成されています。すなわち、各呼び出しメッセージがそれぞれ 1 つの応答メッセージに一致します。ところが、プロトコル自体はメッセージ引き渡しプロトコルなので、RPC 以外のプロトコルで対応できます。RPC パッケージでサポートされている RPC 以外のプロトコルとしては、バッチとブロードキャストがあります。
バッチを使用すると、クライアントは任意の大きさのコールメッセージシーケンスをサーバーに送信できます。一般にバッチでは、トランスポートとして TCP のような信頼性の高いバイトストリームプロトコルを使用します。バッチを使用すると、クライアントはサーバーからの応答を待たず、サーバーもバッチ要求に対しては応答しません。バッチ呼び出しシーケンスを終了するには、通常、非バッチの RPC 呼び出しを行なってパイプラインをフラッシュします。このときは肯定応答が返されます。詳細については、バッチ処理 を参照してください。
ブロードキャスト RPC では、クライアントがブロードキャストパケットをネットワークに送信し、それに対する数多くの応答を待ちます。ブロードキャスト RPC では、トランスポートに UDP のような非接続型のパケットベースプロトコルを使用します。ブロードキャストプロトコルをサポートするサーバーは、要求を正しく処理できたときだけ応答を返し、エラーが起これば応答は返しません。ブロードキャスト RPC では rpcbind サービスを使用してそのセマンティクスを達成します。詳細については、 ブロードキャスト RPC と rpcbind プロトコル を参照してください。
この節では、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;
};
RPC メッセージを TCP のようなバイトストリームトランスポートの最上位に渡す場合は、メッセージごとに区切り、検出やプロトコルエラーからの回復を可能にします。これをレコードマーク (RM) といいます。1 つの RPC メッセージは 1 つの RM レコードに収められます。
レコードはいくつかのレコードフラグメントで構成されます。レコードフラグメントには、4 バイトのヘッダーに続いて 0 から (2**31) - 1 バイトのフラグメントデータが入っています。データには符号なしバイナリ数値が符号化され、バイト順序は XDR 整数と同様にネットワークのバイト順序に従います。
ヘッダーには次の 2 つの値が符号化されています。