ONC+ 開発ガイド

プログラムと手続き番号

RPC 呼び出しメッセージには、呼び出される手続きを一意に識別する次の 3 つの符号なしフィールドがあります。

プログラム番号は、「プログラム番号の登録」にあるように、中央の 1 人の管理者が決定します。

プログラムを最初に作成したときは、バージョン番号は通常 1 になります。プロトコルは次第に改善されて、安定し、よりよいプロトコルになるため、呼び出し側のプロセスでは、呼び出しメッセージのバージョンフィールドを使用してどのプロトコルバージョンを使用するかを指定できます。バージョン番号を使用することにより、これまで使用していたプロトコルと新規プロトコルとが同じサーバープロセスで「使用可能」になります。

手続き番号では、どの手続きを呼び出すかを指定します。手続き番号は、各プログラムのプロトコル仕様に記されています。たとえば、ファイルサービスのプロトコル仕様には、手続き番号 5 は read で、手続き番号 12 は write というように記されています。

遠隔プログラムのプロトコルがバージョンが変わるたびに変更されるように、RPC メッセージプロトコルも変わることがあります。したがって、呼び出しメッセージには RPC バージョン番号も入っています。ここで説明する RPC のバージョン番号は常に 2 です。

要求メッセージに対する応答メッセージには、次に示すエラー条件を識別できるような情報が入っています。

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 に示すように分散されます。

表 B-1 RPC プログラム番号

プログラム番号 

説明 

00000000 - 1fffffff 

ホストが定義 

20000000 - 3fffffff 

ユーザーが定義 

40000000 - 5fffffff

一時的 (カスタマ作成アプリケーションのために予約)

60000000 - 7fffffff 

予約 

80000000 - 9fffffff 

予約 

a0000000 - bfffffff 

予約 

c0000000 - dfffffff 

予約 

e0000000 - ffffffff 

予約 

最初のグループの番号は全カスタマで一致している必要があり、Sun で管理しています。一般に使用できるアプリケーションをカスタマが開発した場合は、そのアプリケーションに最初のグループの番号を割り当てなければなりません。

第 2 グループの番号は特定のカスタマアプリケーションのために予約されています。この範囲の番号は、主に新規プログラムのデバッグで使用します。

第 3 グループは、動的にプログラム番号を生成するアプリケーションのために予約されています。

最後のグループは将来のために予約されているので、使用しないでください。

プログラム番号の登録

プロトコル仕様を登録するには、email で rpc@sun.com に送信するか、次の住所に送ってください。

RPC Administrator
Sun Microsystems, Inc
901 San Antonio Road.
Palo Alto,CA 94043
U.S.A. 650-960-1300

その際には rpcgen で生成した、プロトコルを記述する「.x」ファイルも同封してください。一意に識別できるプログラム番号を返送します。

標準 RPC サービスの RPC プログラム番号とプロトコル仕様は、/usr/include/rpcsvc のインクルードファイルに入っています。ただし、これらのサービスは登録されているサービスのほんの一部分にすぎません。

RPC プロトコルのその他の使用方法

本来、RPC プロトコルは遠隔手続き呼び出しを目的に作成されています。すなわち、各呼び出しメッセージがそれぞれ 1 つの応答メッセージに一致します。ところが、プロトコル自体はメッセージ引き渡しプロトコルなので、RPC 以外のプロトコルで対応できます。RPC パッケージでサポートされている RPC 以外のプロトコルとしては、バッチとブロードキャストがあります。

バッチ

バッチを使用すると、クライアントは任意の大きさの呼び出しメッセージシーケンスをサーバーに送信できます。一般にバッチでは、トランスポートとして TCP のような信頼性の高いバイトストリームプロトコルを使用します。バッチを使用すると、クライアントはサーバーからの応答を待たず、サーバーもバッチ要求に対しては応答しません。バッチ呼び出しシーケンスを終了するには、通常、非バッチの RPC 呼び出しを行なってパイプラインをフラッシュします。このときは肯定応答が返されます。詳細については、「バッチ処理」の節を参照してください。

ブロードキャスト RPC

ブロードキャスト RPC では、クライアントがブロードキャストパケットをネットワークに送信し、それに対する数多くの応答を待ちます。ブロードキャスト RPC では、トランスポートに UDP のような非接続型のパケットベースプロトコルを使用します。ブロードキャストプロトコルをサポートするサーバーは、要求を正しく処理できたときだけ応答を返し、エラーが起これば応答は返しません。ブロードキャスト RPC では rpcbind サービスを使用してそのセマンティクスを達成します。詳細については、 「ブロードキャスト RPC」、および rpcbind プロトコル」 の節を参照してください。

RPC メッセージプロトコル

この節では、RPC メッセージプロトコルを、XDR データ記述言語を使用して説明します。メッセージは、例 B-1で示すようにトップダウン形式で定義します。


例 B-1 RPC メッセージプロトコル

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 つの値が符号化されています。