ONC+ 開発ガイド

TS-RPC から TI-RPC への移行について

トランスポート独立の RPC ルーチン (TI-RPC ルーチン) を使用すると、アプリケーション開発者はトランスポート層へのアクセスレベルを自由に選択できます。最上位レベルのルーチンは、トランスポートが完全に抽象化されて、本当の意味でトランスポート独立になっています。下位レベルのルーチンを使用すると、旧バージョンと同じように個々のトランスポートに依存したアクセスレベルになります。

この節では、トランスポート特定 RPC (TS-RPC) アプリケーションを TI-RPC へ移行するための非公式ガイドになっています。表 4-9 では、いくつかのルーチンを選んで相違点を示します。ソケットとトランスポート層インタフェース (TLI) の移行の問題点についての詳細は、『Transport Interfaces Programming Guide』を参照してください。

アプリケーションの移行

TCP または UDP に基づくアプリケーションはバイナリ互換モードで実行できます。すべてのソースファイルをコンパイルし直したり、リンクし直したりできるのは、一部のアプリケーションだけです。RPC呼び出しだけを使用し、ソケット、TCP、UDP に固有の機能を使用していないアプリケーションがこれに当たります。

ソケットセマンティクスに依存していたり、TCP や UDP の固有の機能を使用しているアプリケーションでは、コードの変更や追加が必要な場合があります。ホストアドレス形式を使用したり、バークレイUNIX の特権ポートを使用するアプリケーションがこれに当たります。

ライブラリ内部や個々のソケット仕様に依存していたり、特定のトランスポートアドレスに依存するアプリケーションは、移行の手間も大きく、本質的な変更が必要な場合もあります。

移行の必要性

TI-RPC へ移行することの利点を次に示します。

特殊事項

libnsl ライブラリ

ネットワーク関数は libc から外されました。コンパイル時には libnsl を明示的に指定して、ネットワーク・サービス・ルーチンをリンクする必要があります。

旧インタフェース

旧インタフェースの多くは libnsl ライブラリでもサポートされていますが、TCP と UDP でしか使用できません。それ以外の新たなトランスポートを利用するには、新インタフェースを使用する必要があります。

名前・アドレス変換機能

トランスポート独立にするには、アドレスを直接使用できません。すなわち、アプリケーションでアドレス変換を行う必要があります。

TI-RPC と TS-RPC の相違点

トランスポート独立型の RPC とトランスポート特定の RPC との主な相違点を 表 4-9に示します。TI-RPC と TS-RPC の比較については、「旧バージョンとの比較」のサンプルプログラムを参照してください。

表 4-9 TI-RPC と TS-RPC の相違点

項目 

TI-RPC 

TS- RPC 

デフォルトのトランスポート選択 

TI-RPC では TLI インタフェースを使用する。 

TS-RPC ではソケットインタフェースを使用する。 

RPC アドレス結合 

TI-RPC ではサービスの結合に rpcbind() を使用する。rpcbind() はアドレスを汎用アドレス形式で扱う。

TS-RPC ではサービスの結合に portmap を使用する。

トランスポート情報  

トランスポート情報はローカルファイル /etc/netconfig に保存する。netconfig で指定したトランスポートはすべてアクセス可能になる。

トランスポートは TCP と UDP だけをサポートする。 

ループバックトランスポート  

rpcbind サービスではサーバ登録に安全なループバックトランスポートが必要。

TS-RPC サービスではループバックトランスポートは不要。 

ホスト名の解決 

TI-RPC のホスト名の解決順序は、/etc/netconfig で指定した動的ライブラリのエントリ順で決定される。

ホスト名の解決はネームサービスが 実行する。順序は hosts データベースのステートで設定される。 

ファイル記述子 

ファイル記述子は TLI 端点とみなす。 

ファイル記述子はソケットとみなす。 

rpcgen

TI-RPC の rpcgen では、複数引数、値渡し、サンプルクライアントとサンプルサーバファイルのサポートを追加。

SunOS 4.1 と直前のリリースは TI-RPC rpcgen に対して一覧表示された特徴はサポートしない。

ライブラリ 

TI-RPC では、アプリケーションが libnsl ライブラリにリンクしていることを必要とする。

TS-RPC の機能はすべて libc で提供される。

マルチスレッドのサポート 

マルチスレッド RPC クライアントとサーバがサポートされる。 

マルチスレッド RPC はサポートされない。 

関数の互換性のリスト

この節では、RPC ライブラリ関数を機能別にグループ化して示します。各グループ内では、旧バージョンと同じ関数、機能が追加された関数、旧バージョンにはなかった新規関数、に分けて示します。


注 -

アスタリスクの付いた関数は、新バージョンへの移行期間はサポートされていますが、Solaris の将来のバージョンではなくなる可能性があります。


クライアントハンドルの作成

次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。

clnt_destroy
clnt_pcreateerror
*clntraw_create
clnt_spcreateerror
*clnttcp_create
*clntudp_bufcreate
*clntudp_create
clnt_control
clnt_create
clnt_create_timed
clnt_create_vers
clnt_dg_create
clnt_raw_create
clnt_tli_create
clnt_tp_create
clnt_tp_create_timed
clnt_vc_create

サービスの作成と廃棄

次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。

svc_destroysvcfd_create
*svc_raw_create
*svc_tp_create
*svcudp_create
*svc_udp_bufcreate
svc_create
svc_dg_create
svc_fd_create
svc_raw_create
svc_tli_create
svc_tp_create
svc_vc_create

サービスの登録と登録削除

次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。

*registerrpc
*svc_register
*svc_unregister
xprt_register
xprt_unregister
rpc_reg
svc_reg
svc_unreg

SunOS 4.x との互換性呼び出し

次の関数は、旧バージョンと同じで、現在の SunOS で使用できます。

*callrpc
clnt_call
*svc_getcaller - IP に基づくトランスポートでのみ使用可。
rpc_call
svc_getrpccaller

ブロードキャスト

次の関数の機能は旧バージョンと同じです。旧バージョンとの互換性を保つためにだけサポートされています。

*clnt_broadcast

clnt_broadcast()portmap サービスにだけブロードキャストできます。

portmap と rpcbind の両方にブロードキャストできる次の関数が現在の SunOS で使用できます。

rpc_broadcast

アドレス管理

TI-RPC ライブラリ関数は、portmaprpcbind の両方で使用できますが、それぞれサービスが異なるため、次のように 2 組の関数が提供されています。

次の関数は portmap と共に使用します。

pmap_set
pmap_unset
pmap_getport
pmap_getmaps
pmap_rmtcall

次の関数は rpcbind と共に使用します。

rpcb_set
rpcb_unset
rpcb_getaddr
rpcb_getmaps
rpcb_rmtcall

認証

次の関数の機能は旧バージョンと同じです。旧バージョンとの互換性を保つためにだけサポートされています。

authdes_create
authunix_create
authunix_create_default
authdes_seccreate
authsys_create
authsys_create_default

その他の関数

現バージョンの rpcbind ではタイムサービス (主として、安全な RPC のためにクライアント側とサーバ側の時間を同期させるときに使用) が提供されており、rpcb_gettime() 関数で利用できます。pmap_getport()rpcb_getaddr() は、登録サービスのポート番号を取り出すときに使用します。サーバでバージョンが 2、3、4 の rcpbind が実行されている場合には、rpcb_getaddr() を使用します。pmap_getport() はバージョン 2 が実行されている場合しか使用できません。

旧バージョンとの比較

例 4-42例 4-43 では、クライアント作成部分が TS-RPC と TI-RPC とでどう違うかを示します。どちらのプログラムも次のことを実行します。


例 4-42 TS-RPC におけるクライアント作成

	struct hostent *h;
	struct sockaddr_in sin;
	int sock = RPC_ANYSOCK;
	u_short port;
	struct timeval wait;

	if ((h = gethostbyname( "host" )) == (struct hostent *) NULL)
{
		syslog(LOG_ERR, "gethostbyname failed");
		exit(1);
	}
	sin.sin_addr.s_addr = *(u_long *) hp->h_addr;
	if ((port = pmap_getport(&sin, PROGRAM, VERSION, "udp")) == 0) {
		syslog (LOG_ERR, "pmap_getport failed");
		exit(1);
	} else
		sin.sin_port = htons(port);
	wait.tv_sec = 25;
	wait.tv_usec = 0;
	clntudp_create(&sin, PROGRAM, VERSION, wait, &sock);

TI-RPC では、UDP トランスポートは netid udp を持つものとみなします。netidはよく知られた名前でなくてもかまいません。


例 4-43 TI-RPC でのクライアント作成

	struct netconfig *nconf;
	struct netconfig *getnetconfigent();
	struct t_bind *tbind;
	struct timeval wait;

	nconf = getnetconfigent("udp");
	if (nconf == (struct netconfig *) NULL) {
		syslog(LOG_ERR, "getnetconfigent for udp failed");
		exit(1);
	}
	fd = t_open(nconf->nc_device, O_RDWR, (struct t_info *)NULL);
	if (fd == -1) {
		syslog(LOG_ERR, "t_open failed");
		exit(1);
	}
	tbind = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR);
	if (tbind == (struct t_bind *) NULL) {
		syslog(LOG_ERR, "t_bind failed");
		exit(1);
	}
	if (rpcb_getaddr( PROGRAM, VERSION, nconf, &tbind->addr, "host")
								== FALSE) {
		syslog(LOG_ERR, "rpcb_getaddr failed");
		exit(1);
	}
	cl = clnt_tli_create(fd, nconf, &tbind->addr, PROGRAM, VERSION,
	                      0, 0);
	(void) t_free((char *) tbind, T_BIND);
	if (cl == (CLIENT *) NULL) {
		syslog(LOG_ERR, "clnt_tli_create failed");
		exit(1);
	}
	wait.tv_sec = 25;
	wait.tv_usec = 0;
	clnt_control(cl, CLSET_TIMEOUT, (char *) &wait);

例 4-44例 4-45では、ブロードキャスト部分が旧バージョンと SunOS 5.3 とでどう違うかを示します。SunOS 4.xclnt_broadcast() は SunOS 5.3 の rpc_broadcast() とほぼ同じです。大きく異なるのは、collectnames() 関数で重複アドレスを削除し、ブロードキャストに応答したホスト名を表示する点です。


例 4-44 TS-RPC におけるブロードキャスト

statstime sw;
extern int collectnames();

clnt_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,         
    	xdr_void, NULL, xdr_statstime, &sw, collectnames);
	...
collectnames(resultsp, raddrp)
	char *resultsp;
	struct sockaddr_in *raddrp;
{
	u_long addr;
	struct entry *entryp, *lim;
	struct hostent *hp;
	extern int curentry;

	/* 重複アドレスはカット */
	addr = raddrp->sin_addr.s_addr;
	lim = entry + curentry;
	for (entryp = entry; entryp < lim; entryp++)
		if (addr == entryp->addr)
			return (0);
	...
	/* ホスト名がわかればホスト名、わからなければアドレスを表示 */
	hp = gethostbyaddr(&raddrp->sin_addr.s_addr, sizeof(u_long),
	    AF_INET);
	if( hp == (struct hostent *) NULL)
		printf("0x%x", addr);
	else
		printf("%s", hp->h_name);
}

例 4-45 は、TI-RPC におけるブロードキャストを示します。


例 4-45 SunOS 5.3 におけるブロードキャスト

statstime sw;
extern int collectnames();

rpc_broadcast(RSTATPROG, RSTATVERS_TIME, RSTATPROC_STATS,
     xdr_void, NULL, xdr_statstime, &sw, collectnames, (char *)
0);
	...
collectnames(resultsp, taddr, nconf)
	char *resultsp;
	struct t_bind *taddr;
	struct netconfig *nconf;
{
	struct entry *entryp, *lim;
	struct nd_hostservlist *hs;
	extern int curentry;
	extern int netbufeq();

	/* 重複アドレスはカット */
	lim = entry + curentry;
	for (entryp = entry; entryp < lim; entryp++)
		if (netbufeq( &taddr->addr, entryp->addr))
			return (0);
	...
	/* ホスト名がわかればホスト名、わからなければアドレスを表示 */
	if (netdir_getbyaddr( nconf, &hs, &taddr->addr ) == ND_OK)
		printf("%s", hs->h_hostservs->h_host);
	else {
		char *uaddr = taddr2uaddr(nconf, &taddr->addr);
		if (uaddr) {
			printf("%s¥n", uaddr);
			(void) free(uaddr);
		} else
			printf("unknown");
	}
}
netbufeq(a, b)
	struct netbuf *a, *b;
{
	return(a->len == b->len && !memcmp( a->buf, b->buf, a->len));
}