ヘッダーをスキップ
TxRPC を使用した Oracle Tuxedo アプリケーションのプログラミング
  目次へ
目次

戻る
戻る
 
 

B DCE ゲートウェイ アプリケーション

ここでは、次の内容について説明します。

この付録の内容

この付録は、「アプリケーション例」で解説したアプリケーション例 rcpsimp を元に構築されています。サーバは OSF/DCE サーバに変更され、またゲートウェイが使用されますので、Oracle Tuxedo ATMI クライアントは明示的バインドと認証済み RPC を使ってサーバと通信できます。この対話型アプリケーションのソース ファイルは、Oracle Tuxedo ATMI ソフトウェア開発キットに付属しています。

前提条件

このトピックでは DCE に関する知識が必要ですが、このマニュアルには DCE チュートリアルは含まれていません。参考文献として『Guide to Writing DCE Applications』(John Shirley、O'Reilly and Associates, Inc.) を参照してください。

DCE ゲートウェイ アプリケーションとは

このアプリケーションは、アプリケーション例 rpcsimp の拡張版です。「付録 A」の場合と同様に、クライアントはリモート プロシージャ コール (オペレーション) to_upper() と to_lower() を呼び出します。

この例では、RPC は Oracle Tuxedo クライアントから DCE ゲートウェイ プロセスに転送され、DCE ゲートウェイ プロセスが要求を DCE サーバに送ります。この例をもう少し現実的なものとするため、ゲートウェイ プロセスから DCE サーバへの通信では、自動バインドと認証済み RPC の代わりに明示的バインディグを使用します。

以下に本プログラム例を構成、実行する手順を解説します。クライアントは「アプリケーション例」で説明した、どのプラットフォーム上でも実行できます。クライアントの構築や実行の方法は同じなので、この章ではこれ以上の説明は行いません。ゲートウェイと DCE サーバは、DCE ソフトウェアがインストールされた POSIX プラットフォームで実行する必要があります。この付録では、ワークステーション プラットフォーム上でのクライアントのインストールやコンパイルについては説明しません。

このサンプル プログラムは OSF/DCE 準拠のソフトウェアを組み込んだプラットフォームで動作します。

rpcsimp アプリケーションのインストール、コンフィグレーション、実行

以下のステップは、サンプル アプリケーションのインストール、コンフィグレーション、実行を行う方法を示しています。

ステップ 1: アプリケーション ディレクトリの作成

rpcsimp 用のディレクトリを作成し、そのディレクトリに移動します。

mkdir rpcsampdir
cd rpcsampdir

注意 :

この様にしておくと、作業開始時にあった rpcsimp 関連のファイルと、作業中に作成した新たなファイルを容易に把握できます。標準シェル (/bin/sh) または Korn シェルを使用してください。C シェル (csh) は使わないでください。

ステップ 2: 環境の設定

必要な環境変数を設定し、エクスポートします。

TUXDIR=<Oracle Tuxedo ルート ディレクトリのパス名>
TUXCONFIG=<ユーザが指定する作業ディレクトリのパス名>/tuxconfig
PATH=$PATH:$TUXDIR/bin
# SVR4, Unixware
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib
# HPUX
SHLIB_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib
# RS6000
LIBPATH=$LD_LIBRARY_PATH:$TUXDIR/lib
export TUXDIR TUXCONFIG PATH LD_LIBRARY_PATH SHLIB_PATH LIBPATH

TUXDIRPATH は、Oracle Tuxedo のディレクトリ構造内のファイルにアクセスし、Oracle Tuxedo コマンドを実行するのに必要です。コンフィグレーション ファイルがロードできるようにするには、TUXCONFIG を設定する必要があります。共有オブジェクトを使用する場合、LD_LIBRARY_PATH 環境変数も設定します。

ステップ 3: ファイルのコピー

rpcsimp 用のファイルをアプリケーション ディレクトリにコピーします。

cp $TUXDIR/apps/rpcsimp/* .

ここでは一部のファイルを編集し、実行形式にするので、ソフトウェアに同梱されたオリジナルのファイルではなく、コピーしたファイルを使用して作業を開始することをお勧めします。

ステップ 4: ファイルの一覧表示

ファイルを一覧表示します。

$ ls
client.c
dcebind.c
dceepv.c
dcemgr.c
dceserver.c
rpcsimp.mk
simp.idl
simpdce.acf
ubbconfig
$

(このセクションで参照しない一部のファイルは省略しています。)

アプリケーションを構成するファイルは次のセクションで説明します。「アプリケーション例」で説明したファイル、client.csimp.idlubbconfig については、ここでは解説しません。

IDL ACF ファイル - simpdce.acf

サンプル コード B-1 simpdce.acf

[explicit_handle]interface changecase
{
}

「付録 A」の例で用いた simp.idl ファイルは、ゲートウェイと DCE サーバの構築に使用されます。しかし、simp.idl ファイルは DCE コンパイラと Oracle Tuxedo の IDL コンパイラの両方でコンパイルされるために、2 つの simp.h ヘッダ ファイルが同じ名前で作成されます。また、クライアントにではなく、サーバに明示的バインドを指定できるように、この例では ACF ファイルを使用しています。バインドを指定しない TxRPC 用のものと、明示的ハンドルをもつ DCE/RPC 用のものを使用して、同一ディレクトリ内で第 2 のファイル名に IDL ファイルをリンクすることをお勧めします。この場合、simp.idlsimpdce.idl に名前が変更され、また関連する ACF ファイルは simpdce.acf になります。Makefile は simpdce.idl を作成し、さらに IDL コンパイラを実行するときに simpdce.acf も検索します。インタフェースのすべてのオペレーションが明示的ハンドルを使用することを示すために、ACF ファイルが使用されている点に注意してください。第 1 パラメータとして [handle] パラメータを指定せずにオペレーションが IDL ファイル内で定義されているので、1 つのオペレーションが自動的に関数プロトタイプとスタブ関数呼び出しに追加されます。

関数のバインド - dcebind.c

ここではページ数の制限から dcebind.c 用のソース コードは示していませんが、$TUXDIR/apps/rpcsimp にあります。

このファイルには次の 3 種類の作業を行う関数、dobind() が含まれます。

  • 目的のインタフェース仕様で DCE サーバ用のバインド ハンドルを取得し、さらに完全に解決されたハンドルの関連する端点を取得します。

  • サーバのプリンシパル名を取得し、セキュリティ レジストリをチェックしてプリンシパルが指定されたグループのメンバーであるかどうか判別することによって、サーバの認証をある程度行います。

  • 認証済み RPC が実行されるようバインド ハンドルにアノテーションを付けます。保護レベルは、DCE プライベート キーによる認証と DCE PAC を基本とした認可を使用するパケット レベルの整合性 (パケット チェックサム checksum による呼び出しごとの相互認証) です。

dcebind.c では次の事項を修正する必要があります。

  • <HOST> は、DCE サーバが実行されるホスト マシンの名前に変更する必要があります。これはディレクトリに格納されるサービス名の一部であって、_host で終わるサービス名の規約に従っています。完全にサフィックスを取り除くこともできます (削除する場合は、dceserver.c でも同じ変更を行う必要があります)。

  • <SERVER_PRINCIPAL_GROUP> は、サーバを実行する DCE プリンシパルに関連付けられたグループに変更する必要があります。これは相互認証の一部として使用されます。

  • cell_admin として rgy_edit を実行してサーバ プリンシパル グループを作成します。サーバ プリンシパルを作成し、グループを持つプリンシパルにアカウントを追加して、サーバにキー テーブルを作成します。クライアントを実行するためには、ユーザ自身のプリンシパルとアカウントも作成します。これらの DCE エンティティを生成するスクリプト例をステップ 8 の「DCE のコンフィグレーション」の項に示します。

エントリ ポイント ベクトル - dceepv.c

サンプル コード B-2 dceepv.c

#include <simpdce.h>   /* IDL コンパイラによって生成されるヘッダ */
#include <dce/rpcexc.h> /* RAISE マクロ */
static void myto_upper(rpc_binding_handle_t hdl, idl_char *str);
static void myto_lower(rpc_binding_handle_t hdl, idl_char *str);
/*
 * マネージャのエントリ ポイント ベクトルは、
 * 有効な DCE バインド ハンドルを生成して DCE サーバに送れるように定義されます。
 * Tuxedo TxRPC はハンドルをサポートしないので、エントリ ポイント関数への入力ハンドルは、
 * 常に NULL になることに注意してください。
 */
 /* 2 つのオペレーションを持つマネージャ エントリ ポイント ベクトル */
changecase_v1_0_epv_t changecase_v1_0_s_epv = {
  myto_upper,
  myto_lower
};
int dobind(rpc_binding_handle_t *hdl);

void
myto_upper(rpc_binding_handle_t hdl, idl_char *str)
{
  rpc_binding_handle_t handle;
  if (dobind(&handle) 0) {  /* サーバ用のバインド ハンドルを取得 */
   userlog("binding failed");
   RAISE(rpc_x_invalid_binding);
  }
  to_upper(handle, str);   /* DCE クライアント スタブを呼び出す */
}

void
myto_lower(rpc_binding_handle_t hdl, idl_char *str)
{
  rpc_binding_handle_t handle;
  if (dobind(&handle) 0) {  /* サーバ用のバインド ハンドルを取得 */
   userlog("binding failed");
   RAISE(rpc_x_invalid_binding);
  }
  to_lower(handle, str);   /* DCE クライアント スタブを呼び出す */
}

dceepv.c にはゲートウェイで使用されるマネージャ エントリ ポイント ベクトルが含まれます。マネージャ エントリ ポイント ベクトルは Oracle Tuxedo サーバ スタブによって呼び出され、DCE クライアント スタブを呼び出します。構造体のデータ型は simpdce.h で定義され、dceepv.c にインクルードされます。またデータ型は、ローカル関数 myto_upper()myto_lower() によって初期化されます。これらの関数はそれぞれ dobind() を呼び出して、認証済み RPC のためにアノテーションが付けられたバインド ハンドルを取得し、関連するクライアント スタブ関数を呼び出します。

DCE マネージャ - dcemgr.c

サンプル コード B-3 dcemgr.c

#include <stdio.h>
#include <ctype.h>
#include "simpdce.h"    /* IDL コンパイラによって生成されるヘッダ */
#include <dce/rpcexc.h> /* RAISE マクロ */
#include <dce/dce_error.h> /* dce_error_inq_text を呼び出すために必要 */
#include <dce/binding.h>  /* レジストリにバインド */
#include <dce/pgo.h>    /* レジストリ インタフェース */
#include <dce/secidmap.h> /* グローバル名をプリンシパル名に変換 */
void
checkauth(rpc_binding_handle_t handle)
{
  int error_stat;
  static unsigned char error_string[dce_c_error_string_len];
  sec_id_pac_t *pac;           /* クライアント パッケージ */
  unsigned_char_t *server_principal_name; /* 要求されるサーバ プリンシパル */
  unsigned32  protection_level;     /* 保護レベル */
  unsigned32  authn_svc;         /* 認証サービス */
  unsigned32  authz_svc;         /* 認可サービス */
  sec_rgy_handle_t rgy_handle;
  error_status_t status;
  /*
   * クライアントがこの呼び出しのために選択した認証パラメータを
   * チェックします。
   */
   rpc_binding_inq_auth_client(
     handle,           /* 入力ハンドル */
     (rpc_authz_handle_t *)&pac,  /* 返されるクライアント パッケージ */
     &server_principal_name,    /* 返される要求サーバのプリンシパル */
     &protection_level,      /* 返される保護レベル */
     &authn_svc,          /* 返される認証サービス */
     &authz_svc,    /* 返される認可サービス */
     &status);
  if (status != rpc_s_ok) {
     dce_error_inq_text(status, error_string, &error_stat);
     fprintf(stderr, "%s %s\n", "inq_auth_client failed",
       error_string);
     RAISE(rpc_x_invalid_binding);
     return;
  }
  /*
   * 呼び出し側が、必要な
   * 保護レベル、認証レベルおよび認可レベルを指定していることを確認します。
   */
  if (protection_level != rpc_c_protect_level_pkt_integ ││
    authn_svc != rpc_c_authn_dce_secret ││
    authz_svc != rpc_c_authz_dce) {
      fprintf(stderr, "not authorized");
      RAISE(rpc_x_invalid_binding);
      return;
    }
    return;
}
void
to_upper(rpc_binding_handle_t handle, idl_char *str)
{
  idl_char *p;
  checkauth(handle);
  /* ACL または参照モニタ チェックはここで実行できます */
  
  /* 大文字に変換 */
  for (p=str; *p != '\0 '; p++)
    *p = toupper((int)*p);
  return;
}
void
to_lower(rpc_binding_handle_t handle, idl_char *str)
{
  idl_char *p;
  checkauth(handle);
  /* ACL または参照モニタ チェックはここで実行できます */
  /* 小文字に変換 */
  for (p=str; *p != '\0 '; p++)
    *p = tolower((int)*p);
  return;
}

dcemgr.c には DCE サーバ用のマネージャ コードがあります。checkauth() 関数は、クライアントの認証 (保護、認証、認可のレベル) を検査するユーティリティ関数です。各オペレーション、to_upper および to_lower はこの関数を呼び出してクライアントの妥当性を検査し、次にオペレーション自体を実行します。アクセス制御リストを使用するアプリケーションでは、ACL 検査は認証検査の後、オペレーションの実行の前に行われます。

DCE サーバ - dceserver.c

ここではページ数の制限から dceserver.c 用のソース コードは示しません。使用する環境に応じて、このファイルにはいくつか修正を加える必要があります。

  • <HOST> は、DCE サーバが実行されるホスト マシンの名前に変更する必要があります。これはディレクトリに格納されるサービス名の一部であって、_host で終わるサービス名の規約に従っています。完全にサフィックスを取り除くこともできます (削除する場合は、dcebind.c でも同じ変更を行う必要があります)。

  • <DIRECTORY> は、サーバ キー テーブルを作成するディレクトリのフルパス名を設定します。次のコマンドを実行すると、キー テーブルが作成されます。

    rgy_edit
    ktadd -p SERVER_PRINCIPAL -pw PASSWORD -f SERVER_KEYTAB
    q
    

ここで、SERVER_PRINCIPAL は、サーバが実行される DCE プリンシパル、PASSWORD はプリンシパルに関連付けられたパスワード、SERVER_KEYTAB はサーバ キー テーブルの名前です。

<PRINCIPAL> は、サーバが実行される DCE プリンシパルの名前に変更する必要があります。

ANNOTATION は、アノテーションがサーバ用のディレクトリ エントリに保存されるように変更できます。

dceserver.c は、実際にはアプリケーションで 2 回使用されます。1 回は DCE サーバ用の main() として使用され、もう 1 回は DCE ゲートウェイ用の tpsvrinit() (makefile で gwinit.c にリンクされ、DTPSVRINIT を使用してコンパイルされます) として使用されます。

特別なマクロ定義を指定しないでコンパイルすると、このファイルは、次の作業を行う DCE サーバのための main() (argcargv コマンドライン オプションを持ちます) を生成します。

  • インタフェースの登録。

  • サーバ バインド情報と端点の作成。

  • サーバ テーブル内の情報を使用し、サーバ プリンシパル用の DCE ログイン コンテキストの確立。

  • 認証情報の登録。

  • バインドの取得と、端点マップ内への情報の登録。

  • バインド情報のディレクトリ ネームスペースへのエクスポート。

  • ネームスペース内のグループへの名前の追加 (省略可能)。

  • 要求のリスン。

  • rpc_server_listen が復帰した後のクリーンアップ。

このプログラムは、コマンドライン オプションを調べ、それらを使用するように修正できます。

-DTCLIENT でコンパイルすると、このファイルは上記のように main() を生成しますが、tpinit() を呼び出してクライアントとして Oracle Tuxedo アプリケーションに参加し、終了する前に tpterm() を呼び出します。これは、プロセスが DCE サーバおよび Oracle Tuxedo クライアントになるような、DCE から Oracle Tuxedo に渡される呼び出し用の DCE ゲートウェイとして使用されます。

-DTPSVRINIT でコンパイルすると、このファイルは、次の作業行う Oracle Tuxedo サーバのために tpsvrinit() (argcargv サーバ コマンドライン オプションを持ちます) を生成します。

  • サーバ キー テーブル内の情報を使用して、プリンシパル用の DCE ログインの確立。

  • 認証情報の登録。

  • サーバに関連付けられたリソース マネージャを開くための tx_open の呼び出し。

このプログラムは、コマンドライン オプションを調べ、それらを使用するように修正できます。

これらの各事例で、ログイン コンテキストは establish_identity を呼び出すことで確立されますが、この establish_identity は、サーバのネットワーク識別子を取得し、キー テーブル ファイル内のサーバのシークレット キーを使用して識別子を解除し、プロセスのログイン コンテキストを設定します。2 つのスレッドが開始されます。最初のスレッドは有効期限が切れる前にログイン コンテキストを最新状態に更新し、もう一つのスレッドはサーバのシークレット キーを定期的に変更します。

Makefile - rpcsimp.mk

サンプル コード B-4 rpcsimp.mk

CC=cc
CFLAGS=
TIDL=$(TUXDIR)/bin/tidl
LIBTRPC=-ltrpc
all: client server
# Tuxedo クライアント
client: simp.h simp_cstub.o
  CC=$(CC) CFLAGS=$(CFLAGS) $(TUXDIR)/bin/buildclient -oclient \
    -fclient.c -fsimp_cstub.o -f$(LIBTRPC)
#
# Tuxedo サーバ省略
#
# Tuxedo ゲートウェイ例
# 上記の Tuxedo クライアントとゲートウェイ サーバおよび DCE サーバを使用
#
#
# Alpha FLAGS/LIBS
#DCECFLAGS=-D_SHARED_LIBRARIES -Dalpha -D_REENTRANT -w -I. \
  -I/usr/include/dce -I$(TUXDIR)/include
#DCELIBS=-ldce -lpthreads -lc_r -lmach -lm
#
#
# HPUX FLAGS/LIBS
#DCECFLAGS=-Aa -D_HPUX_SOURCE -D_REENTRANT -I. \
  -I/usr/include/reentrant -I${TUXDIR}/include
#DCELIBS=-Wl,-Bimmediate -Wl,-Bnonfatal -ldce -lc_r -lm
#
IDL=idl
ALL2=client simpgw dceserver
all2: $(ALL2)
# Tuxedo から DCE へのゲートウェイ
simpdce.idl: simp.idl
  rm -f simpdce.idl
  ln simp.idl simpdce.idl
gwinit.c: dceserver.c
  rm -f gwinit.c
  ln dceserver.c gwinit.c
gwinit.o: gwinit.c
  $(CC) -c $(DCECFLAGS) -DTPSVRINIT gwinit.c
dceepv.o: dceepv.c simpdce.h
   $(CC) -c $(DCECFLAGS) dceepv.c
dcebind.o: dcebind.c simpdce.h
  $(CC) -c $(DCECFLAGS) dcebind.c
simpgw: simpdce.idl gwinit.o dcebind.o dceepv.o
  blds_dce -i -no_mepv -o simpgw -f -g -f gwinit.o -f \ 
    dcebind.o -f dceepv.o simpdce.idl
# DCE サーバ
simpdce_sstub.o simpdce.h: simpdce.idl
  $(IDL) -client none -keep object simpdce.idl
dceserver.o: dceserver.c simpdce.h
  $(CC) -c $(DCECFLAGS) dceserver.c
dcemgr.o: dcemgr.c simpdce.h
  $(CC) -c $(DCECFLAGS) dcemgr.c
dceserver: simpdce_sstub.o dceserver.o dcemgr.o
  $(CC) dceserver.o simpdce_sstub.o dcemgr.o -o dceserver \ 
    $(DCELIBS)
# クリーンアップ
clean::
  rm -f *.o server $(ALL2) ULOG.* TUXCONFIG
  rm -f stderr stdout *stub.c *.h simpdce.idl gwinit.c
clobber: clean

makefile は実行可能クライアント、ゲートウェイ、DCE サーバ プログラムを構築します。

このソフトウェアを構築する前に、rpcsimp.mk を修正して DCE サーバを構築するための正しいオプションとライブラリを設定する必要があります。上記で示したように、makefile には複数のプラットフォームに対応した設定が含まれています。使用しているプラットフォームに応じて、該当する DCECFLAGSDCELIBS 変数ペアのコメント文指定を解除します (シャープ記号を削除します)。異なるプラットフォームを使用しているのであれば、独自の定義を追加します。

makefile を少し書き直せば、クライアントは「アプリケーション例」の場合と同じ方法で構築できます。simpdce.idlblds_dce に渡すことで DCE ゲートウェイが構築され、blds_dce は DCE に対してゲートウェイとして機能する Oracle Tuxedo ATMI サーバを構築します。gwinit.o (-DTPSVRINIT でコンパイルされた dceserver.c)、dobind.o (DCE サーバ用のバインド ハンドルを取得)、dceepv.o (マネージャ エントリ ポイント ベクトル) も含まれています。IDL コンパイラが独自のマネージャ エントリ ポイント ベクトルを生成しないよう、-i -no_mepv が指定されることに注意してください。DCE サーバは、DCE IDL コンパイラで simpdce.idl をコンパイルし、dceserver.odcemgr.o をインクルードすることで構築されます。

ステップ 5: コンフィグレーションの変更

  1. ASCII の ubbconfig コンフィグレーション ファイルは、「アプリケーション例」の説明どおりに変更する必要があります。このステップは必須です。

  2. また *SERVERS セクションでは、シャープ記号 (#) を行の先頭に付け "server" 行をコメント文にし、dceserver 行ではコメント文の指定を解除します。

ステップ 6: アプリケーションの構築

  1. ソフトウェアを構築する前に、上記で説明した様に rpcsimp.mk を修正して DCE サーバを構築するために正しいオプションとライブラリを設定する必要があります。

  2. 次のコマンドを実行してクライアントとサーバ プログラムを構築します。

    make -f rpcsimp.mk TUXDIR=$TUXDIR all2
    

ステップ 7: コンフィグレーション ファイルのロード

次のコマンドを実行してバイナリの TUXCONFIG コンフィグレーション ファイルをロードします。

tmloadcf -y ubbconfig

ステップ 8: DCE のコンフィグレーション

上記で説明したアプリケーション例を実行するための DCE エンティティの設定手順を次に示します。すべての文字が大文字で表される識別子は、使用する環境に応じてカスタマイズ化します。

  • すでに独自の DCE プリンシパルを持っている場合は、MYGROUPMYPRINCIPAL、または関連するアカウントを作成する必要はありません。

  • この例では、cell_admin パスワードはデフォルトの -dce と想定していますが、このパスワードは必要に応じて変更できます。

  • サーバは Oracle Tuxedo 管理者として起動し、サーバ キー テーブルの読み取りが行える必要があるので、SERVER_PRINCIPAL は Oracle Tuxedo 管理者の識別子と同じにします。

サンプル コード B-5 DCE コンフィグレーション

$ dce_login cell_admin -dce-
$ rgy_edit
> domain group
> add SERVER_PRINCIPAL_GROUP
> add MYGROUP
> domain principal
> add SERVER_PRINCIPAL
> add MYPRINCIPAL
> domain account
> add SERVER_PRINCIPAL -g SERVER_PRINCIPAL_GROUP -o none -pw \ 
    SERVERPASSWORD -mp -dce-
> add MYPRINCIPAL -g MYGROUP -o none -pw MYPASSWORD -mp -dce-
> ktadd -p SERVER_PRINCIPAL -pw SERVERPASSWORD -f SERVER_KEYTAB
> q
$ chown SERVER_PRINCIPAL SERVER_KEYTAB
$ chmod 0600 SERVER_KEYTAB

ステップ 9: コンフィグレーションの起動

  1. SERVER_PRINCIPAL (サーバ キー テーブルのオーナー) としてログインします。

  2. 次のコマンドを実行して DCE サーバを起動します。

    dceserver &
    
    

    DCE サーバは、要求のリスンを開始する前に「Server ready」というメッセージを表示します。

  3. 次のコマンドを実行して Oracle Tuxedo ATMI アプリケーションを起動します。

    tmboot -y
    

ステップ 10: クライアントの実行

変換する文字列を指定してクライアント プログラムを実行できます。変換する文字列は省略できます。クライアント プログラムは、まず文字列を大文字に変換し、この後小文字に変換します。

$ client HeLlO
to_upper returns: HELLO
to_lower returns: hello
$

ステップ 11: コンフィグレーションの停止

  1. 次のコマンドを実行して、アプリケーションを停止します。

    tmshutdown -y
    
  2. DCE サーバを停止します。

ステップ 12: 作成ファイルのクリーンアップ

次のコマンドを入力して、作成したファイルを削除します。

make -f rpcsimp.mk clean