ONC+ 開発ガイド

プログラムと手続き番号

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

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

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

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

リモートプログラムのプロトコルがバージョンが変わるたびに変更されるように、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 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, 901 San Antonio Road, Palo Alto, CA 94043

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

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

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

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

バッチ

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

ブロードキャスト RPC

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

RPC メッセージプロトコル

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


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