入り口に戻る

原文はこちら。翻訳にあたって、オープンソースグループ・ジャパンの MIT ライセンスの訳を参考にした。

関数型(function prototype)の表記を一部変更。(typedef ~~Proc)

Inter-Client Exchange Library(日本語試訳)

X Consortium Standard

Ralph Mor

X Consortium

X Version 11, Release 7.7

Version 1.0

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium.

(訳)

(以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可する。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれる。)

(上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとする。)

(ソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証もなく提供される。ここでいう保証には、商品性、特定の目的への適合性、および権利非侵害についての保証も含まれるが、それに限定されるものではない。X CONSORTIUM は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとする。)

(X Consortium の名称は、この表示に記載されている場合を除き、X Consortium の事前の書面による承認を得ずに、宣伝であろうとその他の形であろうと、ソフトウェアの販売を促進するもの、またはソフトウェアの使用その他の扱いを奨励するものに使用してはならない。)


目次

1. ICE の概略
2. ICE ライブラリ - ICE の C 言語インタフェイス
3. 対象読者
4. ヘッダファイルとライブラリ名
5. 接頭辞について
6. プロトコルの登録
メッセージを処理するコールバック
認証方式
7. ICE 接続
ICE 接続の開設
ICE 接続の待受け
ホスト名に基く認証(ICE 接続)
ICE 接続の受入れ
ICE 接続の閉鎖
接続看視手続き
8. プロトコルの設定と終了
9. メッセージの処理
10. Ping
11. ICElib の情報取得関数を使う
12. ICE メッセージ
ICE メッセージを送る
ICE メッセージを読む
13. エラーの処理
14. マルチスレッドで使用する
15. 補助関数
16. 謝辞
A. 認証作業のための用役関数
B. MIT-MAGIC-COOKIE-1 による認証

第一章 ICE の概略

  クライアント間の交信に使えるプロトコルとしては、様々なものが考えられる。そして、その種のプロトコルの間には多くの類似点と共通の機能が見出せる。例えば、認証(authentication)、版の交渉(version negotiation)、バイト順の交渉(byte order negotiation)などである。Inter-Client Exchange (ICE) プロトコルの狙いは、そのようなプロトコルを構築するための骨組みを規定することである。ICE プロトコルを用いることで、共通の交渉機構を使い回せるようになるとともに、単一の伝送接続(transport connection)上での多重プロトコル通信が可能になる。

第二章 ICE ライブラリ - ICE の C 言語インタフェイス

  ICE を利用しようとするクライアントは、まず自身が理解できるプロトコルの群を ICE ライブラリに登録しなければならない。各プロトコルに対して、主たる命令コード(major opcode)が動的に割りてられる。主命令コードは 1 - 255 の範囲の値をとる(交信を試みる二つのクライアントの間で、同一のプロトコルに対して異なる主命令コードが割り当てられることもある)。次にクライアントは他のクライアントとの接続を開くか、さもなくば、他のクライアントからの接続を待ち受ける。この段階で認証を行うことができる。一つのクライアントが、他のクライアントへの接続を図りながら、同時に自身への接続を待ち受けるということも可能である(入れ籠型のセッションマネージャがその例)。二つのクライアントの間に一度 ICE 接続が確立された後、使用したいプロトコルを「活性化」するために、クライアントの一方から ProtocolSetup を提起する必要がある。他の一方が ProtocolSetup を受理すると(ここでも認証を行うことができる)、両クライアントはそのプロトコル固有のメッセージ群を用いて交信できるようになる。単一の ICE 接続の上で、複数のプロトコルを稼働させることが可能である。ある ICE 接続において最早使われていないプロトコルが存在するとき、ICE ライブラリにその旨を通知するのはクライアントの仕事である。但し、各下位プロトコル(subprotocol)がプロトコルの終了作業を開始する方法については、ICE では定めない。

  ICE ライブラリでは、受け取ったメッセージを処理するためにコールバック(callback)を利用している。コールバックを用いることで、ProtocolSetup メッセージや認証作業を舞台裏で始末できるようになる。クライアントが特定のメッセージを待ち受けて処理から返らない(block)時に、ICE ライブラリで他のメッセージのために領域を確保する必要がない、ということもコールバックの利点の一つである。

第三章 対象読者

  この文書は主に、ICE を基層としたプロトコルのライブラリを開発する人に向けて書かれている。一般的には、ICE を利用するアプリケーションは直接 ICE ライブラリの関数を呼び出すのではなく、個々のプロトコル・ライブラリの関数を呼び出すものである。しかしながら、ICE 接続を受け入れるため、交信開始時に ICE ライブラリの関数をいくらか呼び出さなければならないアプリケーションも存在するであろう(例えば、クライアントからの接続を受け付けるセッションマネージャなど)。とはいえ、総じてプロトコル・ライブラリは、 ICE 内部の細かい点をアプリケーションから隠すように設計すべきである。

第四章 ヘッダファイルとライブラリ名

  ヘッダファイル <X11/ICE/ICElib.h> で ICElib の全てのデータ型と関数型(function prototype)を定義する。ICElib.h はヘッダファイル <X11/ICE/ICE.h> を取り込んでいる(include)。ICE.h で ICElib の全ての定数を定義する。メッセージの読み書きを行う必要のあるプロトコル・ライブラリは、ヘッダファイル <X11/ICE/ICEmsg.h> を取り込む(include)。

  アプリケーションに ICElib を結合する(link)には、-lICE を用いるものとする。

第五章 接頭辞について

  ProtocolSetup を提起したクライアントと ProtocolReply で応答するクライアントとを区別するため、ICE ライブラリで使用する名前には以下の接頭辞を付ける。

  • IcePo - Ice Protocol Originator プロトコルの開始方

  • IcePa - Ice Protocol Acceptor プロトコルの受理方

第六章 プロトコルの登録

  二者のクライアントが特定のプロトコルに則ったメッセージを交換し合うには、双方とも同プロトコルを ICE ライブラリに登録していなければならない。登録を通じて両者は、同プロトコルに対する主命令コードを取得し、メッセージ処理や認証作業を行うコールバックを設定する。登録用の関数が二つ、別々に用意されている。

  • 一つは ProtocolSetup を提起する側で用いるもの。

  • 一つは ProtocolReply で応答する側が用いるもの。

  両クライアントによる ICE 接続の確立に先んじてプロトコルの登録を行うのが望ましい。プロトコルの登録が ICE 接続の成立後に行われる場合、プロトコルが未だ登録されていない内に同プロトコルの ProtocolSetup が届いてしまうという事態も起こり得る。ICE 接続の成立前にプロトコルを登録することが不可能であれば、先の競合状態が生じないよう、適当な予防策を講じるべきである。

  関数 IceRegisterForProtocolSetup は、ProtocolSetup を提起するクライアントが使用する。

int IceRegisterForProtocolSetup(const char *protocol_name, const char *vendor, const char *release, int version_count, IcePoVersionRec *version_recs, int auth_count, const char **auth_names, IcePoAuthProc *auth_procs, IceIOErrorProc io_error_proc);

protocol_name

登録するプロトコルの名前を表す文字列。

vendor

開発者を表す文字列。意味は同プロトコルで定める。

release

公開版を表す文字列。意味は同プロトコルで定める。

version_count

同プロトコルの使用可能な版の数。

version_recs

版番号とそれに対応するコールバックの組の配列。

auth_count

使用可能な認証方式の数。

auth_names

使用可能な認証方式の名前の配列。

auth_procs

認証を行うコールバックの配列。各認証方式に一つづつ。

io_error_proc

入出力エラーのハンドラ(処理器)、もしくは NULL。

  関数 IceRegisterForProtocolSetup は、成功すれば未使用の主命令コードを、エラーが起きれば -1 を返す。プロトコルを実際に利用できる状態にするには、この主命令コードを付して関数 IceProtocolSetup を呼び出す必要がある。プロトコルが一度有効になった後、同プロトコルに基づく全てのメッセージは、この主命令コードを指定して送信するものとする。

  一つのプロトコル・ライブラリで同一プロトコルの複数の版を運用することも可能である。引数 version_recs には、そのプロトコルの利用可能な版を、優先度に関して降順に並べる。一つ一つの版の情報(version record)は、プロトコルの主たる版番号(major version)、従たる版番号(minor version)及び受け取ったメッセージを処理するためのコールバック関数から成る。


typedef struct {
  int major_version;
  int minor_version;
  IcePoProcessMsgProc process_msg_proc;
} IcePoVersionRec;

  ProtocolSetup を提起したクライアントによって受信されるメッセージ群を処理するのは、コールバック関数 IcePoProcessMsgProc の仕事である。更なる情報は、メッセージを処理するコールバック を見よ。

  プロトコルが利用可能な状態になる前の段階で認証を要求することもできる。プロトコル・ライブラリは、自身の対応している認証方式を ICE ライブラリに登録しておかなければならない。引数 auth_names と引数 auth_procs には、それぞれ、認証方式の名前とそれを実行するコールバックを、優先度に関して降順に列挙する。コールバック関数 IcePoAuthProc についての情報は、認証方式 を見よ。

  コールバック IceIOErrorProc は、ICE 接続が予期せぬ形で途切れた場合に呼び出される。そのような事態の発生を知る必要がなければ、io_error_proc に NULL を渡すものとする。詳しくは、エラーの処理 を参照。

  関数 IceRegisterForProtocolReply は、ProtocolSetup に対して ProtocolReply で応答するクライアントによって使用される。

int IceRegisterForProtocolReply(const char *protocol_name, const char *vendor, const char *release, int version_count, IcePaVersionRec *version_recs, int auth_count, const char **auth_names, IcePaAuthProc *auth_procs, IceHostBasedAuthProc host_based_auth_proc, IceProtocolSetupProc protocol_setup_proc, IceProtocolActivateProc protocol_activate_proc, IceIOErrorProc io_error_proc);

protocol_name

登録するプロトコルの名前を表す文字列。

vendor

開発者を表す文字列。意味は同プロトコルで定める。

release

公開版を表す文字列。意味は同プロトコルで定める。

version_count

同プロトコルの使用可能な版の数。

version_recs

版番号とそれに対応するコールバックの組の配列。

auth_count

使用可能な認証方式の数。

auth_names

使用可能な認証方式の名前の配列。

auth_procs

認証を行うコールバックの配列。各認証方式に一つづつ。

host_based_auth_proc

ホスト名に基づく認証のためのコールバック。

protocol_setup_proc

ProtocolSetup に対する認証が通った時、ProtocolReply の送信に先立って呼び出されるコールバック。

protocol_activate_proc

ProtocolReply の送信後に呼び出されるコールバック。

io_error_proc

入出力エラーのハンドラ(処理器)、もしくは NULL。

  IceRegisterForProtocolReply は、成功すれば未使用の主命令コードを、エラーが起きれば -1 を返す。返ってきた主命令コードは、このプロトコルに則って送信される以後のメッセージ全てで使用されるものとする。

  一つのプロトコル・ライブラリで同一プロトコルの複数の版を運用することも可能である。引数 version_recs には、そのプロトコルの利用可能な版を、優先度に関して降順に並べる。一つ一つの版の情報(version record)は、プロトコルの主たる版番号(major version)、従たる版番号(minor version)及び受け取ったメッセージを処理するためのコールバック関数から成る。


typedef struct {
  int major_version;
  int minor_version;
  IcePaProcessMsgProc process_msg_proc;
} IcePaVersionRec;

  ProtocolSetup を受理したクライアントに届けられるメッセージ群を処理するのは、コールバック IcePaProcessMsgProc の仕事である。詳しくは メッセージを処理するコールバック を見よ。

  プロトコルが利用可能な状態になる前の段階で認証を要求することもできる。プロトコル・ライブラリは、自身の対応している認証方式を ICE ライブラリに登録しておかなければならない。引数 auth_names と引数 auth_procs には、それぞれ、認証方式の名前とそれを実行するコールバックを、優先度に関して降順に列挙する。コールバック IcePaAuthProc についての情報は、認証方式 を見よ。

  認証に失敗し、且つ ProtocolSetup を提起しているクライアントが認証を要求していない場合、開始方クライアントのホスト名を付してコールバック IceHostBasedAuthProc を呼び出す。もしこのコールバックが True を返せば、たとえ元々の認証に失敗していたとしても、ProtocolSetup は成功となる。True しか返さない IceHostBasedAuthProc を登録することで、実質的に認証機能が無効になることに注意する。ホスト名に基づく認証を一切許可しない場合には、引数 host_based_auth_proc に NULL を渡すものとする。

typedef Bool (*IceHostBasedAuthProc)(char *host_name);

host_name

ProtocolSetup を送信したクライアントのホスト名。

  引数 host_name は protocol/hostname の形をとる文字列である。protocol の部分には、{tcp, decnet, local} の何れか一つが入る。

  ProtocolSetup メッセージの処理と認証作業がコールバックによって舞台裏で実行されることから、プロトコル・ライブラリには ProtocolSetup の完了を知るための仕組みが必要になる。この仕組みは二つの段階に分かれる。第一段階では、認証を成功裡に終えてから ICE ライブラリが ProtocolReply を送信するまでの間に、コールバック IceProtocolSetupProc を呼び出す。設定中のプロトコルで必要な資源はこの時に割り当てる。IceProtocolSetupProc の戻り値が成功を意味するものであれば、ICE ライブラリは ProtocolReply を送信し、それに続いて同ライブラリにてコールバック IceProtocolActivateProc を呼び出す。IceProtocolSetupProc が蹉跌した場合は、ProtocolSetup に対する返答として、相手方のクライアントへエラーが送られる。

  IceProtocolActivateProc は必須のコールバックではない。ProtocolReply の直後にプロトコル・ライブラリでメッセージを生成する場合に限って此れを登録する。このコールバックが不要であれば、protocol_activate_proc に NULL を渡す。

typedef Status (*IceProtocolSetupProc)(IceConn ice_conn, int major_version, int minor_version, char *vendor, char *release, IcePointer *client_data_ret, char **failure_reason_ret);

ice_conn

ICE 接続オブジェクト。

major_version

プロトコルの主たる版番号。

minor_version

プロトコルの従たる版番号。

vendor

開発者を表す文字列。プロトコルの開始方によって登録されたもの。

release

公開版を表す文字列。プロトコルの開始方によって登録されたもの。

client_data_ret

コールバックで設定するクライアント・データ。

failure_reason_ret

失敗の原因。

  引数 client_data_ret に格納されたポインタは、ICE 接続上で此のプロトコルに宛ててメッセージが届く度に、コールバック IcePaProcessMsgProc に渡される。

  vendor と release に渡される文字列は、用が済んだ時点で free を用いて解放するものとする。

  IceProtocolSetupProc が不首尾に終わった場合、同コールバックは実値 0 の Status を返すとともに、failure_reason_ret に文字列領域を割り当て、そこに失敗の理由を格納する。この領域を解放するのは ICE ライブラリの仕事である。

  コールバック IceProtocolActivateProc は次のように定義されている。

typedef void (*IceProtocolActivateProc)(IceConn ice_conn, IcePointer client_data);

ice_conn

ICE 接続オブジェクト。

client_data

コールバック IceProtocolSetupProc で設定されたクライアント・データ。

  コールバック IceIOErrorProc は、ICE 接続が予期せぬ形で途切れた場合に呼び出される。そのような事態の発生を知る必要がなければ、io_error_proc に NULL を渡すものとする。詳しくは、エラーの処理 を参照。

メッセージを処理するコールバック

  アプリケーションは、(select を通じて) ICE 接続上に未読のデータがあることを知った時、関数 IceProcessMessages を呼び出す。メッセージの処理 を参照。IceProcessMessages において 0 でない主命令コードの付いた ICE メッセージ・ヘッダを読み取った時( 0 は ICE プロトコルが使用する)、同関数は、メッセージの残りの部分を読み込み、開封し、場合によっては、処理するための関数を呼び出さなければならない。

  ProtocolSetup を提起したクライアントの下にメッセージが届いた場合、コールバック IcePoProcessMsgProc を呼び出す。

typedef void (*IcePoProcessMsgProc)(IceConn ice_conn, IcePointer client_data, int opcode, unsigned long length, Bool swap, IceReplyWaitInfo *reply_wait, Bool *reply_ready_ret);

ice_conn

ICE 接続オブジェクト。

client_data

同 ICE 接続において此のプロトコルに紐付けられているクライアント・データ。

opcode

メッセージの従たる命令コード。

length

ICE ヘッダ以降のメッセージの長さ(8 バイト単位)。

swap

バイト順の交換が必要か否かを表すフラグ。

reply_wait

呼出し元のクライアントが返答を待っているのか否かを表す。

reply_ready_ret

True に設定されていれば、返答の準備ができているということ。

  ProtocolSetup を受理したクライアントの下にメッセージが届いた場合、コールバック IcePaProcessMsgProc を呼び出す。

typedef void (*IcePaProcessMsgProc)(IceConn ice_conn, IcePointer client_data, int opcode, unsigned long length, Bool swap);

ice_conn

ICE 接続オブジェクト。

client_data

同 ICE 接続において此のプロトコルに紐付けられているクライアント・データ。

opcode

メッセージの従たる命令コード。

length

ICE ヘッダ以降のメッセージの長さ(8 バイト単位)。

swap

バイト順の交換が必要か否かを表すフラグ。

  メッセージを読み込むためのマクロが定義されているので、上記の両コールバックはこれを利用する(「ICE メッセージを読む」を参照)。バイト順の交換が必要になることもあり得るという点に注意する。ICE ヘッダの length 欄のバイト順交換は、必要があれば ICElib にて行われる。

  両コールバックにおいて、引数 client_data には ProtocolSetup の際に登録したクライアント・データへのポインタが格納されている。IcePoProcessMsgProc の場合、クライアント・データは IceProtocolSetup 呼出しの中で設定される(訳註:SMlib では SmcConn がクライアント・データとして渡される)。IcePaProcessMsgProc の場合、クライアント・データはコールバック IceProtocolSetupProc の中で設定される(訳註:SMlib では SmsConn がクライアント・データとして渡される)。

  コールバック IcePoProcessMsgProc では、引数 reply_wait を確認する必要がある。もし replay_wait が NULL であれば、ICE ライブラリは次のように判断する。即ち、この関数はコールバックを通じてクライアントにメッセージを届けるものと看做される。例えば、ここでのメッセージがセッション管理における「Save Yourself」メッセージであるとすると、当関数はコールバック経由でクライアントに「Save Yourself」を通知するということである。このようなコールバックが実際にどのように定義されるかは、実装次第である。

  一方、reply_wait が NULL でない場合、クライアントは先に自身が送信したメッセージに対する返信もしくはエラー報告を待ち受けているものと見做される。reply_wait は IceReplyWaitInfo 型である。


typedef struct {
  unsigned long sequence_of_request;
  int major_opcode_of_request;
  int minor_opcode_of_request;
  IcePointer reply;
} IceReplyWaitInfo;

  IceReplyWaitInfo 構造体にはメッセージの主/従命令コードと通し番号が入っているが、これは、現在待ち受けている返信が為される所以となったメッセージのものである。同構造体には、返信メッセージが書き込まれる領域へのポインタも含まれている(プロトコル・ライブラリにおいて、この IcePointer を返信用の適当な型に読み替える)。大抵、返信メッセージには固定長の部分が存在し、そして、この固定長データ部分を内部に保持する構造体へのポインタは、返信を待っているクライアントが用意する。可変長のデータがある場合、コールバック IcePoProcessMsgProc において追加の記憶領域が確保され、その領域へのポインタが先の固定長構造体の中に格納される。もしデータが丸ごと可変長であれば(例えば可変長文字列一つ)、返信を待ち受ける方のクライアントは、ポインタ一つを保持できる固定長領域へのポインタを渡すだけで良い。そして、コールバック IcePoProcessMsgProc が記憶領域を新たに確保し、その領域へのポインタを(渡されたポインタの指し示す固定長領域に)書き込む。返信を受け取ったクライアントは、自身のために割り当てられた記憶領域の解放作業を引き受けるものとする。

  reply_wait が NULL ではなく、且つ IcePoProcessMsgProc において同 reply_wait に対する返信もしくはエラー報告がある場合(つまりコールバックが生成されなかった場合)、引数 reply_ready_ret を True に設定する。エラーを返すのは、待ち受けられている返信にそのエラーが直接関連している時だけである、という点に注意する。それ以外の時は、IcePoProcessMsgProc は内部でエラーを処理するか、実装ライブラリのエラー・ハンドラ(処理器)を呼び出す。

  reply_wait が NULL の場合は reply_ready_ret も NULL であろうから、このポインタに如何なる値も書き込まないよう気をつけなければならない。

  一方、コールバック IcePaProcessMsgProc では、クライアントへメッセージを渡すにあたって、常にコールバックを利用する。例えば、ここでのメッセージがセッション管理における「Interact Request」メッセージであるとすると、この関数ではコールバック経由でクライアントに「Interact Request」を通知することになる。

  コールバック IcePaProcessMsgProcIcePoProcessMsgProc のように reply_wait を利用しないのは次の理由による。即ち、サーバとして振舞うプロセスは、返信を待って他の入力を弾くわけにはいかないからである(接続を試みる方のクライアントが異常な動作をした結果、際限なくメッセージをブロックする(返信が来るまで関数から戻らない)ようになると、他のクライアントとは通信できなくなってしまう)。

認証方式

  先に述べたように、プロトコル・ライブラリは、自身が対応している認証方式を ICE ライブラリに登録しなければならない。各認証方式に対して、二つのコールバックを登録することができる。

  • 一つは、ProtocolSetup を提起する側の処理を行うコールバック。

  • 一つは、この要求を受理もしくは拒否する側の処理を行うコールバック。

  IcePoAuthProc は、ProtocolSetup を提起したクライアントの立場から呼び出されるコールバックである。このコールバックは、他のクライアントから送られてくる先頭メッセージ「Authentication Required」もしくは後続メッセージ「Authentication Next Phase」に応えることができなければならない。

typedef IcePoAuthStatus (*IcePoAuthProc)(IceConn ice_conn, IcePointer *auth_state_ptr, Bool clean_up, Bool swap, int auth_datalen, IcePointer auth_data, int *reply_datalen_ret, IcePointer *reply_data_ret, char **error_string_ret);

ice_conn

ICE 接続オブジェクト。

auth_state_ptr

認証のコールバック手続きで使用する状態情報へのポインタ。

clean_up

True は認証が済んでいることを意味する。その場合、この関数はこれまで保持していた状態情報を片付ける。この時、後ろの六つの引数は無視する。

swap

True であれば、auth_data はバイト順を入れ替える必要がある(内容によっては)。

auth_datalen

認証データのバイト長。

auth_data

認証者からのデータ。

reply_datalen_ret

この関数の戻り値たる返信データのバイト長。

reply_data_ret

この関数で返される返信データ。

error_string_ret

認証手続きの関数中でエラーが発生した場合、同関数はエラー文を割り当てた上で返り値とする。

  認証方式によっては、作業の完遂に複数の段階を要することもある。その為、クライアントの認証作業中に IcePoAuthProc を複数回呼び出すことがあり得る。そして、その複数の呼出しの合間にも保持し続けなければならない状態情報があるであろう。各 ProtocolSetup の開始時点では *auth_state_ptr は NULL であり、この関数(IcePoAuthProc)を通じて状態の初期化と同ポインタの設定を行う。このポインタは、後続の本コールバックの呼出しにおいて、先行コールバックが記録した状態情報を取得するのに用いられる。

  必要であれば、関数 IceConnectionString を呼び出すことで、ProtocolSetup を受理するクライアントのネットワーク ID を取得することができる。

  free を用いて reply_data_ret と error_string_ret の両ポインタを解放するのは ICElib の仕事である。

  auth_data のポインタが揮発性の(volatile)記憶領域を指していることもあり得る。コールバックの呼出し完了以後もデータを保持する必要があれば、忘れずに複製を作っておく。

  IcePoAuthProc は、次の四つの値の何れか一つを返す。

  • IcePoAuthHaveReply - 返信は入手可能。

  • IcePoAuthRejected - 認証が拒否された。

  • IcePoAuthFailed - 認証に失敗した。

  • IcePoAuthDoneCleanup - 片付けを終えた。

  IcePaAuthProc は、ProtocolSetup を受信したクライアントの立場から呼び出されるコールバックである。

typedef IcePaAuthStatus (*IcePaAuthProc)(IceConn ice_conn, IcePointer *auth_state_ptr, Bool swap, int auth_datalen, IcePointer auth_data, int *reply_datalen_ret, IcePointer *reply_data_ret, char **error_string_ret);

ice_conn

ICE 接続オブジェクト。

auth_state_ptr

認証のコールバック手続きで使用する状態情報へのポインタ。

swap

True であれば、auth_data はバイト順を入れ替える必要がある(内容によっては)。

auth_datalen

プロトコル開始方からの認証データのバイト長。

auth_data

プロトコル開始方からの認証データ。

reply_datalen_ret

この関数の戻り値たる認証データの長さ。

reply_data_ret

この関数の戻り値たる認証データ。

error_string_ret

認証の拒否もしくは蹉跌に際し、戻り値としてエラー文が格納される。

  認証方式によっては、作業の完遂に複数の段階を要することもある。その為、クライアントの認証作業中に IcePaAuthProc を複数回呼び出すことがあり得る。そして、その複数の呼出しの合間にも保持し続けなければならない状態情報があるであろう。各 ProtocolSetup の開始時点では、auth_datalen は 0、*auth_state_ptr は NULL であり、この関数(IcePaAuthProc)を通じて状態の初期化とポインタの設定を行う。このポインタは、後続の本コールバックの呼出しにおいて、先行コールバックが記録した状態情報を取得するのに用いられる。

  必要であれば、関数 IceConnectionString を呼び出すことで、ProtocolSetup を受理するクライアントのネットワーク ID を取得することができる。

  auth_data のポインタが揮発性の(volatile)記憶領域を指していることもあり得る。コールバックの呼出し完了以後もデータを保持する必要があれば、忘れずに複製を作っておく。

  reply_data_ret と error_string_ret の両ポインタを伝送し、且つ free を用いて解放するのは、ICElib の仕事である。

  IcePaAuthProc は、次の四つの値の何れか一つを返す。

  • IcePaAuthContinue - 認証を続ける(あるいは始める)。

  • IcePaAuthAccepted - 認証に成功した。

  • IcePaAuthRejected - 認証を拒否した。

  • IcePaAuthFailed - 認証に失敗した。

第七章 ICE 接続

  二つのクライアントの間で ICE 接続を確立するには、一方に接続を待ち受けるクライアントが、他方に接続を提起するクライアントが存在しなければならない。大多数のクライアントは接続を提起する側なので、まずその方から取り上げる。

ICE 接続の開設

  ICE 接続を待ち受けている他のクライアントとの間に接続を開設するには、IceOpenConnection を用いる。

IceConn IceOpenConnection(char *network_ids_list, IcePointer context, Bool must_authenticate, int major_opcode_check, int error_length, char *error_string_ret);

network_ids_list

相手のクライアントのネットワーク ID(複数可)を記す。

context

不透明型オブジェクトへのポインタもしくは NULL。これを用いて ICE 接続の共有が可能か判断する(後述)。

must_authenticate

True の時、相手方のクライアントは認証を省くことができない。

major_opcode_check

新しい ICE 接続の生成を義務づけるために使用する(後述)。

error_length

引数 error_string_ret の長さ。

error_string_ret

null 文字終端のエラーメッセージを返す(もし存在すれば)。引数 error_string_ret は利用者の用意した記憶領域を参照する。error_length の数値分のバイトしか使用しない。

  IceOpenConnection は、成功すれば、不透明な(opaque) ICE 接続オブジェクトを返す。失敗すれば、NULL を返す。

  引数 network_ids_list には、コンマで区切ったネットワーク ID 群の並びを渡す。まず先頭のネットワーク ID を使って接続を試みる。これが失敗すれば、二番目のネットワーク ID を使って試行し、これが失敗すれば以下同様。各ネットワーク ID は次の書式をとる。

tcp/<hostname>:<portnumber>もしくは
decnet/<hostname>::<objname>もしくは
local/<hostname>:<path> 

  大抵のプロトコル・ライブラリは、内部で IceOpenConnection を呼び出す、ある種の開設関数(open function)を備えることになるであろう。IceOpenConnection を呼び出した時、既設の ICE 接続の利用が認められることもある(接続相手のクライアントが同一の場合)。一方、ICE 接続の共用が望ましくないこともある。

  引数 context によって、ICE 接続の共用の可否を判断する。context が NULL であれば、当関数の呼出者は常に接続の共有を試みる。context が NULL でなければ、呼出方は、自身が指定したものとは異なる、NULL でない context と結びついた既設の ICE 接続を用いない。

  加えて、major_opcode_check に 0 でない主命令コードの値が渡された場合、既設の ICE 接続でその主命令コードが使用されていない時に限って、同接続を利用する。これを使えば、二つのクライアントの間で、同一プロトコルを用いた ICE 接続を複数設けるよう指示することも可能である。

  認証に必要な処理は ICE ライブラリの内部で行われる。認証データを取得する方法は実装によって異なる。[1]

  IceOpenConnection の呼出しが終わると、クライアントは ProtocolSetup を送受信できるようになる(IceRegisterForProtocolSetup を呼び出している方は送信、IceRegisterForProtocolReply を呼び出している方は受信が可能)。

ICE 接続の待受け

  ICE 接続を受け入れようとするクライアントは、接続要求を察知できるように、まず IceListenForConnections または IceListenForWellKnownConnections を呼び出さなければならない。これらの関数の結果、不透明な待受けオブジェクト(opaque "listen" objects)の配列が取得できる。利用可能な伝送方式(transport method)の種類一つにつき(例、Unix Domain、TCP、DECnet など)、一つのオブジェクトが割り当てられる。

  通常、クライアントは、各伝送方式中の利用可能な名前(訳註:ポート番号、オブジェクト名、経路名)の生成と、待受けオブジェクト群(listen objects)の取得を ICElib に依頼する。そうしたクライアントは次に、IceComposeNetworkIdList を用いて ICElib が定めた名前(訳註:ポート番号、オブジェクト名、経路名)を取り出し、接続開設を試みる他のクライアントから、それらの名前が利用できるようにする。時には、予め決められた伝送オブジェクト名(transport object names)で接続を待ち受けなければならないこともあろう。そうしたクライアントは、IceListenForWellKnownConnections を用いて、待受けオブジェクト群(listen objects)の名前(訳註:ポート番号、オブジェクト名、経路名)を指定することができる。

Status IceListenForConnections(int *count_ret, IceListenObj **listen_objs_ret, int error_length, char *error_string_ret);

count_ret

生成された待受けオブジェクト(listen objects)の数を返す。

listen_objs_ret

不透明な待受けオブジェクト(opaque listen objects)へのポインタの配列を返す。

error_length

引数 error_string_ret の長さ。

error_string_ret

エラーがあれば、null 文字終端のエラーメッセージを返す。ポインタ error_string_ret は利用者の用意した領域を指す。error_length の数値分のバイト数しか使用されない。

  IceListenForConnections の戻り値は、失敗すれば 0、成功すれば正の値である。

Status IceListenForWellKnownConnections(char *port_id, int *count_ret, IceListenObj **listen_objs_ret, int error_length, char *error_string_ret);

port_id

接続を待つアドレスのポート識別子を渡す。文字列中には、スラッシュ("/")やコンマ(".")が含まれてはいけない。これらは将来の利用に備えて使わずにおく。

count_ret

生成された待受けオブジェクト(listen objects)の数を返す。

listen_objs_ret

不透明な待受けオブジェクト(opaque listen objects)へのポインタの配列を返す。

error_length

引数 error_string_ret の長さ。

error_string_ret

エラーがあれば、null 文字終端のエラーメッセージを返す。ポインタ error_string_ret は、利用者の用意した記憶領域を指す。error_length の数値分のバイト数しか使用されない。

  IceListenForWellKnownConnections は、既知の伝送方式(transport)の一つ一つを port_id の頭に付加する方法で、ネットワーク ID の一覧を構成し、その結果を用いて待受けオブジェクト群(listen objects)を作成する。port_id には、ICE ネットワーク ID 中のポート番号(portnumber)、オブジェクト名(objname)、もしくは経路(path)の部分が入る。あるネットワーク ID に対して待受けオブジェクト(listen object)が作成できなかった場合、そのネットワーク ID は無視する。一つも待受けオブジェクトが作成されなければ、IceListenForWellKnownConnections は失敗を意味する戻り値を返す。

  IceListenForWellKnownConnections の戻り値は、失敗すれば 0、成功すれば正の値である。

  待受けオブジェクトを閉鎖・解放するには、IceFreeListenObjs を用いる。

void IceFreeListenObjs(int count, IceListenObj *listen_objs);

count

待受けオブジェクト(listen object)の数。

listen_objs

待受けオブジェクト群(listen objects)。

  待受けオブジェクト(listen object)に対する新たな接続を検出するには、その待受けオブジェクトに結び付けられている記述子に対して、select を使用する。

  記述子を取得するには、IceGetListenConnectionNumber を用いる。

int IceGetListenConnectionNumber(IceListenObj listen_obj);

listen_obj

待受けオブジェクト(listen object)。

  待受けオブジェクトに結び付けられたネットワーク ID の文字列表現を取得するには、IceGetListenConnectionString を用いる。

char *IceGetListenConnectionString(IceListenObj listen_obj);

listen_obj

待受けオブジェクト(listen object)。

  ネットワーク ID は次の書式で記述される。

tcp/<hostname>:<portnumber>もしくは
decnet/<hostname>::<objname>もしくは
local/<hostname>:<path> 

  ネットワーク ID 群をコンマで区切って並べた文字列(IceOpenConnection に渡せる形式)を作るには、IceComposeNetworkIdList を用いる。

char *IceComposeNetworkIdList(int count, IceListenObj *listen_objs);

count

待受けオブジェクト(listen objects)の数。

listen_objs

待受けオブジェクト群(listen objects)。

ホスト名に基づく認証(ICE 接続)

  ICE 接続の開設を試みた時、認証に失敗し、且つ開始方クライアントが認証を要求していない場合、開始方クライアントに接続の最後の機会を与えるべく、ホスト名に基づく認証手続き(host based authentication procedure)を呼び出すことができる。各待受けオブジェクトには、この種のコールバックが一つ備わっている。関数 IceSetHostBasedAuthProc を用いて、このコールバックの設定を行う。

void IceSetHostBasedAuthProc(IceListenObj listen_obj, IceHostBasedAuthProc host_based_auth_proc);

IceListenObj

待受けオブジェクト(listen object)。

host_based_auth_proc

ホスト名に基づく認証手続き。

  各待受けオブジェクトは、初期状態において、ホスト名に基づく認証手続きを何ら有していない。既にホスト名認証が設定されている場合、引数 host_based_auth_proc に NULL を渡すことによって、同認証手続きを消去することができる。

typedef Bool (*IceHostBasedAuthProc)(char *host_name);

host_name

ICE 接続の開設を試みたクライアントのホスト名。

  引数 host_name には「protocol/ hostname」の形をとる文字列を渡す。ここでの「protocol」には、{tcp、decnet、local} の何れか一つが入る。

  IceHostBasedAuthProc から True が返れば、たとえ元々の認証に失敗していても、接続は許可される。常に True を返す IceHostBasedAuthProc を登録することで、認証機能を実質的に無効にすることができる点に注意する。

  ホスト名に基づく認証は ProtocolSetup の段階でも使用可能である。この段階で使うコールバックは、関数 IceRegisterForProtocolReply で指定する(プロトコルの登録を見よ)。

ICE 接続の受入れ

  IceListenForConnections で取得した待受けオブジェクト(listen object)にて接続の試みを検知した後、IceAcceptConnection を呼び出す。この関数は、新しく不透明な ICE 接続オブジェクト返す。

IceConn IceAcceptConnection(IceListenObj listen_obj, IceAcceptStatus *status_ret);

listen_obj

新たな接続を検知した待受けオブジェクト(listen object)。

status_ret

戻り値たる状態情報。

  引数 status_ret は、次の値のどれか一つに設定される。

  • IceAcceptSuccess - 受入れ作業は成功し、この関数は新しい接続オブジェクトを返す。

  • IceAcceptFailure - 受入れ作業は失敗し、この関数は NULL を返す。

  • IceAcceptBadMalloc - 記憶領域の確保が失敗し、この関数は NULL を返す。

  一般に、新しい接続を検知するには、待受けオブジェクトに結び付けられたファイル記述子に対して select を実行する。新しい接続が見つかった時は、関数 IceAcceptConnection を呼び出す。IceAcceptConnection は、仮設状態の新 ICE 接続を返すことがある。これは、接続が有効になる前の段階で、認証を行うことがあるためである。ICE ライブラリは仮設状態の接続が有効になるまでの間、他の接続要求を弾くわけにはいかないので(接続を試みるクライアントが不適切な動きをすると、際限なく接続要求をブロックしてしまう(接続が有効になるまで関数から返らない))、アプリケーション側で接続が有効な状態に変わるのを待たなければならない。

  次の擬似コードによって、接続を受理する過程を例示する。

new_ice_conn = IceAcceptConnection (listen_obj, &accept_status);
if (accept_status != IceAcceptSuccess)
{
     ファイル記述子を閉じて戻る
}

status = IceConnectionStatus (new_ice_conn);
time_start = time_now;

while (status == IceConnectPending)
{
     select() on {new_ice_conn, all open connections}

     for (each ice_conn in the list of open connections)
          if (data ready on ice_conn)
          {
               status = IceProcessMessages (ice_conn, NULL, NULL);
               if (status == IceProcessMessagesIOError)
                    IceCloseConnection(ice_conn);
          }
     if data ready on new_ice_conn
     {
          /*
          * IceProcessMessages は、接続が仮設でなくなる
          * まで呼び出される。これによって、接続設定要求
          * と認証手続きを処理する。
          */

          IceProcessMessages ( new_ice_conn, NULL, NULL);
          status = IceConnectionStatus (new_ice_conn);
     }
     else
     {
          if (time_now - time_start > MAX_WAIT_TIME)
               status = IceConnectRejected;
     }
}

if (status == IceConnectAccepted)
{
     Add new_ice_conn to the list of open connections
}
else
{
     IceCloseConnection
     new_ice_conn
}

  IceAcceptConnection が呼び出され、接続が有効になると、クライアントは ProtocolSetup を送受信できるようになる(IceRegisterForProtocolSetup を呼び出している方は送信、IceRegisterForProtocolReply を呼び出している方は受信が可能)。

ICE 接続の閉鎖

  IceOpenConnectionIceAcceptConnection で作成された ICE 接続を閉じるには、IceCloseConnection を用いる。

IceCloseStatus IceCloseConnection(IceConn ice_conn);

ice_conn

閉鎖する ICE 接続。

  ある接続を実際に閉じるには、以下の条件が満たされなければならない、

  • 同 ICE 接続の開設参照数(open reference count)が 0 に達しなければならない。IceOpenConnection が呼び出された時、まず既に開かれている ICE 接続の利用を試みる。既存の接続が利用可能であれば、IceOpenConnection は同接続の開設参照数を一つ増やす。そのため、ある ICE 接続を閉じるには、IceOpenConnection の各呼出しに対して、それに応じた IceCloseConnection が一つ呼び出されなければならない。このような接続は、最後の IceCloseConnection を受けて初めて切断可能になる。

  • 同 ICE 接続の実効プロトコル数(active protocol count)が 0 に達しなければならない。同接続において ProtocolSetup が成功する度に、実効プロトコル数が一つ増える。クライアントは、同接続上の使う予定のなくなったプロトコルに対して、関数 IceProtocolShutdown を呼び出し、これによって実効プロトコル数を一つ減らす(プロトコルの設定と終了を見よ)。

  • 同 ICE 接続において終了交渉(shutdown negotiation)が可能である場合、接続相手のクライアントが接続切断に同意しなければならない。

  IceCloseConnection は、次の値の何れか一つを返す。

  • IceClosedNow - ICE 接続は、この時点で閉鎖された。看視手続き(watch procedures)が呼び出され、接続資源が解放された。

  • IceClosedASAP - ICE 接続上で入出力エラーが発生したが、まだ IceProcessMessages の入れ籠の内から IceCloseConnection が呼び出されている最中である。この時点で看視手続きは既に呼び出されているが、接続は能う限り早く能わざる限り遅く解放される(IceProcessMessages の入れ籠の層が 0 に達し、同関数が IceProcessMessagesConnectionClosed を返した時)。

  • IceConnectionInUse - 他の生きたプロトコルがこの接続を使用しているため、今回は切断されなかった。

  • IceStartedShutdownNegotiation - この時点では接続は閉鎖されなかった。そして、ICE 接続の相手方クライアントとの終了交渉(shutdown negotiation)が始まった。実際に接続が切断された時は、IceProcessMessagesIceProcessMessagesConnectionClosed を返す。

  ICE 接続の相手方クライアントが終了交渉(shutdown negotiation)を提起することなく接続を断ったことが分かった時は、関数 IceSetShutdownNegotiation を呼び出して、終了交渉を行わない設定に切り替える。これによって、IceCloseConnection が壊れた接続に対して書き込んでしまうことを防ぐ。

void IceSetShutdownNegotiation(IceConn ice_conn, Bool negotiate);

ice_conn

有効な ICE 接続オブジェクト。

negotiate

Falseを渡せば、終了交渉は行われなくなる。

  ICE 接続の終了交渉に関する設定を調べるには、IceCheckShutdownNegotiation を用いる。

Bool IceCheckShutdownNegotiation(IceConn ice_conn);

ice_conn

有効な ICE 接続オブジェクト。

  IceCheckShutdownNegotiationTrue を返すのは、引数で指定した接続において終了交渉が行われるよう設定されている時である。そうでない場合、False が返る。どの接続も、初期状態では交渉を行う設定になっている。この設定は、関数 IceSetShutdownNegotiation を使わなければ変更できない。

接続看視手続き

  看視手続き(watch procedure)を新たに登録するには、IceAddConnectionWatch を用いる。登録された看視手続きは、ICElib が IceOpenConnectionIceAcceptConnection によって新しい接続を開く度に、あるいは IceCloseConnection によって接続を閉じる度に、呼び出されることになる。

Status IceAddConnectionWatch(IceWatchProc watch_proc, IcePointer client_data);

watch_proc

ICElib で接続が開閉される時に呼び出される看視手続き(watch procedure)。

client_data

このポインタは看視手続き呼出し時にその引数として渡される。

  IceAddConnectionWatch の戻り値は、失敗すれば 0、成功すれば正の値である。

  幾度かの IceOpenConnection の呼出しの結果、同一の ICE 接続が共用されることもあるという点に注意する。このような場合、看視手続きは、最初に接続が確立された時(認証成功後)にしか呼び出されない。同様に、接続が共有されている可能性があるので、IceCloseConnection を通じて実際に接続が切断された時に限り、看視手続きが呼び出される(IceConn の解放直前)。

  新しい接続が作成された時に select mask にファイル記述子を加え、接続が破棄された時にファイル記述子を取り除くアプリケーションにとって、この看視手続きはとても役に立つものである。接続が共有されている可能性があるので、select mask に対して何時ファイル記述子を加えたり除いたりすべきなのか、看視手続き無しに知るのは難しい。

  ICE ライブラリに複数の看視手続き(watch procedures)を登録できる。手続きが複数ある時の呼出し順序は、何ら想定すべきでない。

  看視手続き登録の時点において、ICE ライブラリに一つでも ICE 接続が作成されていれば、そうした ICE 接続の一つ一つに対して、直ちに同看視手続きが呼び出される。その際、引数 opening に True を渡す。

  看視手続きの関数型は IceWatchProc である。

typedef void (*IceWatchProc)(IceConn ice_conn, IcePointer client_data, Bool opening, IcePointer *watch_data);

ice_conn

開設あるいは閉鎖される ICE 接続。この接続と結び付いたファイル記述子を取得するには、IceConnectionNumber を呼び出す。

client_data

IceAddConnectionWatch の呼出し時に指定したクライアント・データへのポインタ。

opening

接続が開かれる際の呼出しでは True、閉じる際の呼出しでは False

watch_data

クライアント・データへのポインタを保存するために使用できる。

  opening が True の時、クライアントは、接続終了まで保持する必要のあるデータを指すように、ポインタ *watch_data を設定する。看視手続きはその後、opening に False を渡して、再び呼び出される。

  看視手続きを削除するには、IceRemoveConnectionWatch を用いる。

void IceRemoveConnectionWatch(IceWatchProc watch_proc, IcePointer client_data);

watch_proc

IceAddConnectionWatch で登録した看視手続き。

client_data

IceAddConnectionWatch で登録したポインタ client_data。



  [1] X Consortium(X 協会)の ICElib の実装では、「 .ICEauthority 」ファイルを使用する(附録 Aを見よ)。

第八章 プロトコルの設定と終了

  与えられた ICE 接続において、プロトコル一つを有効化するには、IceProtocolSetup を用いる。

IceProtocolSetupStatus IceProtocolSetup(IceConn ice_conn, int my_opcode, IcePointer client_data, Bool must_authenticate, int *major_version_ret, int *minor_version_ret, char **vendor_ret, char **release_ret, int error_length, char *error_string_ret);

ice_conn

有効な ICE 接続オブジェクト。

my_opcode

設定するプロトコルの主命令コード(major opcode)。これは IceRegisterForProtocolSetup で返されたもの。

client_data

このポインタで記録しているクライアント・データは、コールバック IcePoProcessMsgProc の引数となる。

must_authenticate

もし True であれば、相手方クライアントは認証を飛ばしてはいけない。

major_version_ret

戻り値として、使用するプロトコルの主たる版番号(major version)が格納される。

minor_version_ret

戻り値として、使用するプロトコルの従たる版番号(minor version)が格納される。

vendor_ret

開発者を示す文字列。プロトコルの受理方が記す。

release_ret

公開版を示す文字列。プロトコルの受理方が記す。

error_length

引数 error_string_ret の長さを示す。

error_string_ret

エラーがあれば、null 文字終端のエラーメッセージを返す。引数 error_string_ret は利用者の用意した領域を参照する。error_length の数値分のバイト数しか使用しない。

  文字列 vendor_ret と文字列 release_ret は、必要でなくなった時は free を用いて解放するものとする。

  IceProtocolSetup は、次の値の何れか一つを返す。

  • IceProtocolSetupSuccess - major_version_ret、minor_version_ret、vendor_ret、release_ret が設定された。

  • IceProtocolSetupFailure もしくは IceProtocolSetupIOError - 蹉跌の理由が error_string_ret に入っている。major_version_ret、minor_version_ret、vendor_ret、release_ret は設定されず。

  • IceProtocolAlreadyActive - 引数で指定された ICE 接続において、このプロトコルは既に有効である。major_version_ret、minor_version_ret、vendor_ret、release_ret は設定されず。

  ICE 接続上のあるプロトコルが最早使われなくなった時は、IceProtocolShutdown を用いて ICE ライブラリにその旨を通知する。

Status IceProtocolShutdown(IceConn ice_conn, int major_opcode);

ice_conn

有効な ICE 接続オブジェクト。

major_opcode

終了するプロトコルの主命令コード(major opcode)。

  IceProtocolShutdown の戻り値は、失敗すれば 0、成功すれば正の値である。

  指定された主命令コードが登録されていないものであった場合、あるいは、指定された主命令コードを持つプロトコルが、指定された ICE 接続において一度も有効化されていない場合、IceProtocolShutdown は蹉跌する。有効化された(activated)とは、同接続において ProtocolSetup に成功した状態のことを指す。ICE では、各下位プロトコル(sub-protocol)がどのようにしてプロトコルの終了を提起するかについては、定めていないことに注意する。

第九章 メッセージの処理

  ICE 接続上で受け取ったメッセージを処理するには、IceProcessMessages を用いる。

IceProcessMessagesStatus IceProcessMessages(IceConn ice_conn, IceReplyWaitInfo *reply_wait, Bool *reply_ready_ret);

ice_conn

有効な ICE 接続オブジェクト。

reply_wait

呼出し元のクライアントが返答を待っているのか否かを表す。

reply_ready_ret

戻り値として True に設定された時は、返答が用意できたということである。

  IceProcessMessages には、二つの使い方がある。

  • 第一の使い方。クライアントは、メッセージを生成した後、その返答を得るまで繰り返し IceProcessMessages を呼び出して、ブロック(入力待機)することができる。(訳註:使用例は X11R7.7/lib/libSM-1.2.1/src/sm_client.c がある。)

  • 第二の使い方。ICE 接続上に読み込むべきデータが存在することを知らせる select を受けて、クライアントは reply_wait に NULL を渡して IceProcessMessages を呼び出す。ICE ライブラリはメッセージの全身(complete message)を 0 個以上処理できる。ブロックされないメッセージは(返答の入力待機が為されないメッセージは)、常にコールバックを呼び出して処理する。

  IceReplyWaitInfo 構造体にはメッセージの主/従命令コードと通し番号が入っているが、これは、現在待ち受けている返信が為される所以となったメッセージのものである。同構造体には、返信メッセージが書き込まれる領域へのポインタも含まれている(プロトコル・ライブラリにおいて、この IcePointer を返信用の適当な型に読み替える)。大抵、返信メッセージには固定長の部分が存在し、そして、この固定長データ部分を内部に保持する構造体へのポインタは、返信を待っているクライアントが用意する。可変長のデータがある場合、コールバック IcePoProcessMsgProc において追加の記憶領域が確保され、その領域へのポインタが先の固定長構造体の中に格納される。もしデータが丸ごと可変長であれば(例えば可変長文字列一つ)、返信を待ち受ける方のクライアントは、ポインタ一つを保持できる固定長領域へのポインタを渡すだけで良い。そして、コールバック IcePoProcessMsgProc が記憶領域を新たに確保し、その領域へのポインタを(渡されたポインタの指し示す固定長領域に)書き込む。返信を受け取ったクライアントは、自身のために割り当てられた記憶領域の解放作業を引き受けるものとする。(訳註:X11R7.7/lib/libICE-1.0.8/src/process.c の場合、IceProcessMessages の内部では、主命令コード等に従って _IceProcessCoreMsgProc 型関数、IcePoProcessMsgProc 型関数、もしくは IcePaProcessMsgProc 型関数を呼び出している。)

typedef struct {
     unsigned long sequence_of_request;
     int major_opcode_of_request;
     int minor_opcode_of_request;
     IcePointer reply;
} IceReplyWaitInfo;

  reply_wait が NULL ではなく、且つ IceProcessMessages において同 reply_wait に対する返信もしくはエラー報告がある場合(つまりコールバックが生成されなかった場合)、引数 reply_ready_ret を True に設定する。

  reply_wait が NULL であれば、この関数を呼び出した者は reply_ready_ret にも NULL を渡しているはずであり、このポインタには何も格納されないことが保証される。

  IceProcessMessages は次の値の何れか一つを返す。

  • IceProcessMessagesSuccess - エラーは起きなかった。

  • IceProcessMessagesIOError - 入出力エラーが発生した。この関数を呼び出した者は IceCloseConnection を使用して、明示的に接続を閉じなければならない。

  • IceProcessMessagesConnectionClosed - ICE 接続は既に切断されている(終了交渉の故に、あるいは IceProcessMessages の入れ籠階層が 0 でない為に、接続の切断が遅れている)。ICE 接続資源は既に解放されているので、この時点で接続に対する操作を試みてはいけない。

第十章 Ping

  ICE 接続の相手方クライアントに対して「Ping」メッセージを送信するには、IcePing を用いる。

Status IcePing(IceConn ice_conn, IcePingReplyProc ping_reply_proc, IcePointer client_data);

ice_conn

有効な ICE 接続オブジェクト。

ping_reply_proc

Ping の応答が届いた時に呼び出すコールバック。

client_data

このポインタはコールバック IcePingReplyProc に渡される。

  IcePing は失敗すれば 0 を、成功すれば正の値を返す。

  IceProcessMessages では Ping の応答を処理するために、IcePingReplyProc を呼び出す。

typedef void (*IcePingReplyProc)(IceConn ice_conn, IcePointer client_data);

ice_conn

有効な ICE 接続オブジェクト。

client_data

IcePing の呼出し時に指定した、クライアント・データへのポインタ。

第十一章 ICElib の情報取得関数を使う

IceConnectStatus IceConnectionStatus(IceConn ice_conn);

  IceConnectionStatus は ICE 接続の状態値を返す。戻り値には以下のものがある。

  • IceConnectPending - 接続は未だ有効ではない(つまり、認証作業中である)。これは IceAcceptConnection によって作成された接続に対してしか意味を持たない。

  • IceConnectAccepted - 接続は受け入れられた。これは IceAcceptConnection によって作成された接続に対してしか意味を持たない。

  • IceConnectRejected - 接続は拒否された(つまり、認証に失敗した)。これは IceAcceptConnection によって作成された接続に対してしか意味を持たない。

  • IceConnectIOError - 引数で指定された接続において、入出力エラーが発生した。

char *IceVendor(IceConn ice_conn);

  IceVendor は、引数で指定した接続の ICE ライブラリの開発者識別文字列を返す。取得した文字列は、用が済んだところで、free を呼び出して解放する。

char *IceRelease(IceConn ice_conn);

  IceRelease は、同接続の ICE ライブラリの公開版番号識別文字列を返す。取得した文字列は、用が済んだところで、free を呼び出して解放する。

int IceProtocolVersion(IceConn ice_conn);

  IceProtocolVersion は、引数で指定した接続において用いられている ICE プロトコルの主たる版番号(major version)を返す。

int IceProtocolRevision(IceConn ice_conn);

  IceProtocolRevision は、引数で指定した接続において用いられている ICE プロトコルの従たる版番号(minor version)を返す。

int IceConnectionNumber(IceConn ice_conn);

  IceConnectionNumber は、引数で指定された ICE 接続のファイル記述子を返す。

char *IceConnectionString(IceConn ice_conn);

  IceConnectionString は、接続を受理した方のクライアントのネットワーク ID を返す。取得した文字列は、用が済んだところで、free を呼び出して解放する。

unsigned long IceLastSentSequenceNumber(IceConn ice_conn);

  IceLastSentSequenceNumber は、引数で指定された ICE 接続において最後に送信されたメッセージの通し番号を返す。

unsigned long IceLastReceivedSequenceNumber(IceConn ice_conn);

  IceLastReceivedSequenceNumber は、引数で指定された ICE 接続において最後に受信されたメッセージの通し番号を返す。

Bool IceSwapping(IceConn ice_conn);

  IceSwapping は、引数で指定された ICE 接続において、メッセージを読み込む際にバイト順の交換が必要である場合、True を返す。

IcePointer IceGetContext(IceConn ice_conn);

  IceGetContext は、IceOpenConnection で作成された接続に結び付けられている文脈(context)を返す。(訳註:X11R7.7/lib/libICE-1.0.8/include/X11/ICE/ICElib.h 及び X11R7.7/lib/libICE-1.0.8/src/connect.c では、関数名は IceGetConnectionContext である。)

第十二章 ICE メッセージ

  全ての ICE メッセージには、8 バイトの標準ヘッダがある。メッセージの読み書きを行う ICElib のマクロは、以下に掲げる命名規則に則って、メッセージ・ヘッダを解釈する。

     CARD8	major_opcode;
     CARD8	minor_opcode;
     CARD8	data[2];
     CARD32	length B32;

  メッセージ・ヘッダの三番目と四番目のバイト(訳註:上記の data[2])は、必要に応じて使用する。length 欄の値は 8 バイト単位で記す。

ICE メッセージを送る

  ICE ライブラリは、メッセージの生成に用いる出力バッファ(output buffer)を保持している。ICE を基層とするプロトコルのライブラリでは、メッセージ群をまとめて一括処理することや、出力バッファを適宜放流する(flush)ことが可能である。

  ICE 接続において入出力エラーが発生した場合、以後の全ての書込み操作は無視される。更なる情報は、エラー処理を見よ。

  ICE 出力バッファの容量を知るには、IceGetOutBufSize を用いる。

int IceGetOutBufSize(IceConn ice_conn);

ice_conn

有効な ICE 接続オブジェクト。

  ICE 出力バッファを放流する(flush)には、IceFlush を用いる。

int IceFlush(IceConn ice_conn);

ice_conn

有効な ICE 接続オブジェクト。

  出力バッファは、メッセージの生成に不十分な空き領域しかない場合、暗々裏に放流されることがあるので注意する。

  以下のマクロは ICE メッセージの生成に使用できる。

IceGetHeader(IceConn ice_conn, int major_opcode, int minor_opcode, int header_size, <C_data_type> *pmsg);

ice_conn

有効な ICE 接続オブジェクト。

major_opcode

メッセージの主命令コード。

minor_opcode

メッセージの従命令コード。

header_size

メッセージ・ヘッダの大きさ(バイト単位)。

<C_data_type>

C 言語における、メッセージ・ヘッダの実際のデータ型。

pmsg

メッセージ・ヘッダの領域を指すポインタ。 このマクロの呼出しの後、ライブラリはメッセージ・ヘッダ中にデータを格納できるようになる。

  IceGetHeader を用いて、引数で指定した ICE 接続におけるメッセージ・ヘッダを準備する。この準備作業では、メッセージ(*pmsg)の主・従命令コードを設定し、メッセージ長を表す(*pmsg の) length 欄をヘッダ長と同じ値に合わせる。この後ろに可変長のデータが続く場合は、メッセージの length 欄を更新するものとする。

IceGetHeaderExtra(IceConn ice_conn, int major_opcode, int minor_opcode, int header_size, int extra, <C_data_type> *pmsg, char *pdata);

ice_conn

有効な ICE 接続オブジェクト。

major_opcode

メッセージの主命令コード。

minor_opcode

メッセージの従命令コード。

header_size

メッセージ・ヘッダの大きさ(バイト単位)。

extra

ヘッダ部分を除いた、後続データの大きさ(バイト単位)。

<C_data_type>

C 言語における、メッセージ・ヘッダの実際のデータ型。

pmsg

メッセージ・ヘッダの領域を指すポインタ。 このマクロの呼出しの後、ライブラリはメッセージ・ヘッダ中にデータを格納できるようになる。

pdata

メッセージ・ヘッダの領域の直後に位置する ICE 出力バッファへのポインタが返る。可変長データはここに格納される。ICE 出力バッファに十分な空き領域がなかった場合、pdata は NULL に設定される。

  IceGetHeaderExtra を用いて、大きさの確定した(比較的小さな)可変長データを伴うメッセージを生成する。このメッセージの全身(complete message)は ICE 出力バッファに納まらなければならない。

IceSimpleMessage(IceConn ice_conn, int major_opcode, int minor_opcode);

ice_conn

有効な ICE 接続オブジェクト。

major_opcode

メッセージの主命令コード。

minor_opcode

メッセージの従命令コード。

  IceSimpleMessage を用いて、ICE ヘッダ・メッセージと同じ大きさの、且つそれ以上の後続データを持たないメッセージを生成する。

IceErrorHeader(IceConn ice_conn, int offending_major_opcode, int offending_minor_opcode, int offending_sequence_num, int severity, int error_class, int data_length);

ice_conn

有効な ICE 接続オブジェクト。

offending_major_opcode

エラーが検出されたプロトコルの主命令コード。

offending_minor_opcode

エラーが検出されたプロトコルにおける従命令コード。

offending_sequence_num

エラーを起こしたメッセージの通し番号。

severity

IceCanContinueIceFatalToProtocol もしくは IceFatalToConnection

error_class

エラー・クラス(error class)。

data_length

ヘッダに続く領域に書き込まれるデータの長さ(8 バイト単位)。

  IceErrorHeader によって、エラー・メッセージのヘッダを準備する。

  ICE で接続された二者のクライアントが、同一のプロトコルに対して相異なる主命令コードを用いている可能性のあることに注意する。上記マクロに渡す offending_major_opcode は、エラー・メッセージを送信した方のクライアントに割り当てられた主命令コードである。

  全てのプロトコルに共通の一般エラー(generic errors)には、0x8000~0xFFFF の範囲の値で表されるクラス(class)がある。詳細は規格文書 Inter-Client Exchange Protocol を見よ。

IceBadMinor0x8000
IceBadState0x8001
IceBadLength0x8002
IceBadValue0x8003

  プロトコル毎のエラーのクラスは、0x0000~0x7fff の範囲で表す。

  ICE 接続にデータを書き込むには、マクロ IceWriteData を用いる。データが ICE 出力バッファに収まる時は、そこにデータを転写する。そうでない時は、ICE 出力バッファを放流した上で、直接データを送信する。

  このマクロは IceGetHeader 及び IceErrorHeader と組み合わせて使用する。

IceWriteData(IceConn ice_conn, int bytes, char *data);

ice_conn

有効な ICE 接続オブジェクト。

bytes

書き込むデータのバイト数。

data

書き込むデータ。

  データを 16 ビット単位で書き込むには、IceWriteData16 を用いる。

IceWriteData16(IceConn ice_conn, int bytes, char *data);

ice_conn

有効な ICE 接続オブジェクト。

bytes

書き込むデータのバイト数。

data

書き込むデータ。

  データを 32 ビット単位で書き込むには、IceWriteData32 を用いる。

IceWriteData32(IceConn ice_conn, int bytes, char *data);

ice_conn

有効な ICE 接続オブジェクト。

bytes

書き込むデータのバイト数。

data

書き込むデータ。

  ICE 出力バッファへの転写作業を省くには、IceSendData を用い、ネットワーク接続を通じて直接データを送信する。この際、必要であれば、まず ICE 出力バッファが放流される。

IceSendData(IceConn ice_conn, int bytes, char *data);

ice_conn

有効な ICE 接続オブジェクト。

bytes

送信するデータのバイト数。

data

送信するデータ。

  32 ビットもしくは 64 ビットの境界に揃えるには、IceWritePad を用いる。詰め物は最大で 7 バイトまで指定できる。

IceWritePad(IceConn ice_conn, int bytes);

ice_conn

有効な ICE 接続オブジェクト。

bytes

書き込む詰め物のバイト数。

ICE メッセージを読む

  ICE ライブラリは、メッセージの読み込みに用いる入力バッファを保持している。ICE ライブラリが、入力待機せずに適宜読み込みを行う様に実装された場合(nonblocking reads)、読み込み作業の度に 0 個以上のメッセージの全身(complete message)が入力バッファに読み込まれる。結果として、この節で説明する、メッセージ読み込みを行うマクロの全てについて、次のことが言える。即ち、引数で指定された接続において実際の読み込み作業が行われるのは、入力バッファ中にデータが既に存在しない時に限られる。

  ICE 入力バッファの容量を知るには、IceGetInBufSize を用いる。

int IceGetInBufSize(IceConn ice_conn);

ice_conn

有効な ICE 接続オブジェクト。

  メッセージを読み込む時は、入出力エラーの有無を確認するよう気をつけなければならない。読込みの際に、メッセージ中の何処かで何らかの入出力エラーが発生した場合、そのメッセージは捨てるものとする。以下で説明するマクロの何れかを用いてメッセージを読み込んだ後には、マクロ IceValidIO を用いて、接続上で入出力エラーが発生したか否かを調べることができる。ある ICE 接続において入出力エラーが発生してしまった後は、全ての読み込み操作は無視される。更なる情報は、エラーの処理を見よ。

Bool IceValidIO(IceConn ice_conn);

ice_conn

有効な ICE 接続オブジェクト。

  以下のマクロを用いて ICE メッセージを読み込むことができる。

IceReadSimpleMessage(IceConn ice_conn, <C_data_type> *pmsg);

ice_conn

有効な ICE 接続オブジェクト。

<C_data_type>

C 言語における、メッセージ・ヘッダの実際のデータ型。

pmsg

このポインタはメッセージ・ヘッダに合わせられる。

  IceReadSimpleMessage を用いて、次のようなメッセージを処理する。即ち、大きさが ICE ヘッダと同じ 8 バイトであり、且つヘッダ中の予備の 2 バイトを使って付加データを保持しているメッセージを処理する。ICE ライブラリは、メッセージの主命令コードを得るために、常にこの最初の 8 バイトを読み込む、という点に注意する。IceReadSimpleMessage は、単にこの 8 バイトへのポインタを返すだけであり、実際には如何なるデータも入力バッファに読み込まない。

  可変長データを伴うメッセージの読込みには、二通りのやり方がある。一つは、IceReadCompleteMessage を用いて、メッセージの全身を一度に読み込む方法である。もう一つは、先にメッセージ・ヘッダを読み込み(ICE ヘッダの 8 バイトより大きいこともある)、次いで可変長データ部分を適度に区切って読み込む方法である。後者については、IceReadMessageHeaderIceReadData を見よ。

IceReadCompleteMessage(IceConn ice_conn, int header_size, <C_data_type> *pmsg, char *pdata);

ice_conn

有効な ICE 接続オブジェクト。

header_size

メッセージ・ヘッダの大きさ(バイト単位)。

<C_data_type>

C 言語における、メッセージ・ヘッダの実際のデータ型。

pmsg

このポインタはメッセージ・ヘッダに合わせられる。

pdata

このポインタはメッセージの可変長データ部分に合わせられる。

  ICE 入力バッファに十分な空きがあれば、IceReadCompleteMessage はメッセージの全身を ICE 入力バッファに読み込む。空きがなければ、可変長データ部分を容れるバッファを新たに確保する。このマクロの呼出しの後、引数 pdata を NULL と比べて、バッファを確保するのに十分なメモリが存在したことを確かめるものとする。

   IceReadCompleteMessage を呼び出してメッセージを処理した後には、IceDisposeCompleteMessage を呼び出すものとする。

IceDisposeCompleteMessage(IceConn ice_conn, char *pdata);

ice_conn

有効な ICE 接続オブジェクト。

pdata

IceReadCompleteMessage で取得した、可変長データ部分へのポインタ。

  可変長データを容れるためにバッファを確保しなければならなかった場合(ICE 入力バッファに収まらなかったが故に)、そのバッファはこのマクロを通じて、ICElib の手で解放される。

IceReadMessageHeader(IceConn ice_conn, int header_size, <C_data_type> *pmsg);

ice_conn

有効な ICE 接続オブジェクト。

header_size

メッセージ・ヘッダの大きさ(バイト単位)。

<C_data_type>

C 言語における、メッセージ・ヘッダの実際のデータ型。

pmsg

このポインタはメッセージ・ヘッダに合わせられる。

  IceReadMessageHeader は、メッセージのヘッダだけを読み込む。残りのデータは、IceReadData 系のマクロで読み込むことになる。このメッセージ読込みの手法は、可変長データ部分を適度に区切って読み込まなければならない時に採用する。

  利用者が用意したバッファに直接データを読み込むには、IceReadData を用いる。

IceReadData(IceConn ice_conn, int bytes, char *pdata);

ice_conn

有効な ICE 接続オブジェクト。

bytes

読み込むバイト数。

pdata

利用者が用意した当バッファにデータが読み込まれる。

  データを 16 ビット単位で読み込むには、IceReadData16 を用いる。(訳註:X11R7.7/lib/libICE-1.0.8 では未実装。引数 swap を無視して IceReadData と同じ作業を実行している。)

IceReadData16(IceConn ice_conn, Bool swap, int bytes, char *pdata);

ice_conn

有効な ICE 接続オブジェクト。

swap

True であれば、値(the values)のバイト順交換を行う。

bytes

読み込むバイト数。

pdata

利用者が用意した当バッファにデータが読み込まれる。

  データを 32 ビット単位で読み込むには、IceReadData32 を用いる。(訳註:X11R7.7/lib/libICE-1.0.8 では未実装。引数 swap を無視して IceReadData と同じ作業を実行している。)

IceReadData32(IceConn ice_conn, Bool swap, int bytes, char *pdata);

ice_conn

有効な ICE 接続オブジェクト。

swap

True であれば、値(the values)のバイト順交換を行う。

bytes

読み込むバイト数。

pdata

利用者が用意した当バッファにデータが読み込まれる。

  32 ビットもしくは 64 ビットの境界に揃えるには、IceReadPad を用いる。詰め物は最大で 7 バイトまで指定できる。

IceReadPad(IceConn ice_conn, int bytes);

ice_conn

有効な ICE 接続オブジェクト。

bytes

詰め物のバイト数。

第十三章 エラーの処理

  ICElib には標準のエラー・ハンドラ(処理器)が二つある。

  • 一つは、主に致命的な事態(fatal conditions)を扱う(例えば、機器の故障で接続が絶えた等)。

  • 一つは、ICE 固有のプロトコル・エラーを扱う。

  もし独自のエラー処理手続きを設定したいのであれば、上の二つのエラー・ハンドラは、利用者の用意した手続きと取り替えることができる。この取替えは何度でも可能である。

  ICE エラー・ハンドラを設定するには、IceSetErrorHandlerを用いる。

IceErrorHandler IceSetErrorHandler(IceErrorHandler handler);

handler

ICE エラー・ハンドラ。標準のハンドラに戻すには、NULL を渡す。

  IceSetErrorHandler は、この時まで使用されていたエラー・ハンドラを返す。

  ICE エラー・ハンドラは、予期せぬ ICE プロトコル・エラー(主命令コード 0)が発生した時に呼び出される。標準搭載のハンドラの動作は、説明的な文を stderr に表示し、重症度が「致命的(fatal)」であれば、0 でない値を付して exit を呼び出す、というものである。exit で終了してしまうのが望ましくない場合、アプリケーション側で独自のエラー・ハンドラを登録する。

  他のプロトコルの法域で起こるエラーは、それぞれのプロトコル・ライブラリで処理することに注意する(各ライブラリに独自のエラー・ハンドラ備えるものとする)。

  ICE エラー・ハンドラの関数型は IceErrorHandler である。

typedef void (*IceErrorHandler)(IceConn ice_conn, Bool swap, int offending_minor_opcode, unsigned long offending_sequence_num, int error_class, int severity, IcePointer values);

ice_conn

ICE 接続オブジェクト。

swap

値(the values)のバイト順交換が必要か否かを示す印。

offending_minor_opcode

違反したメッセージの ICE 従命令コード。

offending_sequence_num

違反したメッセージの通し番号。

error_class

違反したメッセージのエラー・クラス。

severity

IceCanContinueIceFatalToProtocol もしくは IceFatalToConnection

values

指定された従命令コードとクラス次第で必要となるエラー値。

  ICE の層では、以下のエラー・クラスが定義されている。


IceBadMinor
IceBadState
IceBadLength
IceBadValue
IceBadMajor
IceNoAuth
IceNoVersion
IceSetupFailed
IceAuthRejected
IceAuthFailed
IceProtocolDuplicate
IceMajorOpcodeDuplicate
IceUnknownProtocol

  詳しくは Inter-Client Exchange Protocol を見よ。

  致命的な入出力エラーを処理するために、IceSetIOErrorHandler を用いる。

IceIOErrorHandler IceSetIOErrorHandler(IceIOErrorHandler handler);

handler

入出力エラーのハンドラ(処理器)。標準のハンドラに戻すには、NULL を渡す。

  IceSetIOErrorHandler は、この時まで使用されていた入出力エラー・ハンドラを返す。

  ICE 入出力エラー・ハンドラの関数型は、IceIOErrorHandler である。

typedef void (*IceIOErrorHandler)(IceConn ice_conn);

ice_conn

ICE 接続オブジェクト。

  ICElib で入出力エラーを処理するには、二通りのやり方がある。

  • 一つ目は、入出力エラーの処理に必要な全ての作業を入出力エラー・ハンドラに行わせ、さりながら、そのエラー・ハンドラ中では IceCloseConnection を呼び出さずに、同ハンドラから復帰するやり方である。この時 ICE 接続は「bad IO」状態となり、同接続に対する以後の読書き全てが無視される。次回 IceProcessMessages が呼び出された時、IceProcessMessagesIOError という状態が返ってくる。その時になって、アプリケーションから IceCloseConnection を呼び出す。

  • 二つ目は、入出力エラー・ハンドラの中で IceCloseConnection を呼び出し、次いで longjmp 命令を用いてアプリケーションのメイン・イベント・ループに戻るやり方である。setjmp 命令と longjmp 命令は全ての環境で適切に機能するとは限らない。特にメモり漏れ(memory leaks)が起こらないように注意しなければならない。したがって、この二つ目の方式は、一つ目のものに比べて好ましくない。

  入出力エラーの通知を受け取るように設定されているプロトコル・ライブラリでは、アプリケーションの入出力エラー・ハンドラが呼び出される前に、独自の IceIOErrorProc 型ハンドラが呼び出される。このハンドラは、プロトコル登録関数にて設定され(IceRegisterForProtocolSetup 及び IceRegisterForProtocolReply を見よ)、そのプロトコルだけに関わる異状の始末をつける。

typedef void (*IceIOErrorProc)(IceConn ice_conn);

ice_conn

ICE 接続オブジェクト。

  全ての IceIOErrorProc 型コールバックは必ず返って来なければならない(must return)ということに注意する。これは、有効なプロトコルの各々が接続破断の通知を必要としているためである。アプリケーションの入出力エラー・ハンドラは、その後に呼び出されなければならない。

第十四章 マルチ・スレッドで使用する

  アプリケーションにて複数のスレッドが ICE ライブラリを使用することを宣言するには、IceInitThreads を用いる。

Status IceInitThreads(void);

  マルチ・スレッドを利用するプログラムで最初に呼び出される ICElib 関数は、IceInitThreads でなければならない。この関数の呼出しは、他の ICElib 呼出しが行われる前に完了しなければならない。IceInitThreads が 0 でない Status を返すのは、この関数でスレッド・パッケージ(threads package)の初期化に成功した時であり、且つその時に限られる。IceInitThreads を複数回呼び出しても問題はない。そのようにしても、スレッド・パッケージ(threads package)は一度しか初期化されない。

  ICElib を基層とするプロトコル・ライブラリでは、ICE 接続とやり取りする、コード中の急所部分(critical sections)に排他錠を掛けなければならない(例えば、メッセージを生成する時)。大抵はマクロとして実装される関数を二つ用意している。

void IceLockConn(IceConn ice_conn);

void IceUnlockConn(IceConn ice_conn);

ice_conn

ICE 接続オブジェクト。

  複数回の ICElib の呼出しを跨いで ICE 接続の排他錠を維持するには、アプリケーションにて IceAppLockConn 及び IceAppUnlockConn を用いる。

void IceAppLockConn(IceConn ice_conn);

ice_conn

ICE 接続オブジェクト。

  関数 IceAppLockConn は、IceAppUnlockConn が呼び出されるまでの間、引数で指定された接続から他のスレッド群を完全に閉め出す。同接続に対して ICElib 関数を呼び出そうとする他のスレッド群は待機させられる(block)。プログラム中で前以って IceInitThreads を呼び出していない場合、IceAppLockConn は何もしない。

void IceAppUnlockConn(IceConn ice_conn);

ice_conn

ICE 接続オブジェクト。

  IceAppLockConn を呼び出したスレッドが関数 IceAppUnlockConn を呼び出すことで、前者の関数のために待機させられていた他のスレッド群は、操作対象となった接続に対する ICElib 関数の呼出しを完遂できるようになる。プログラム中で前以って IceInitThreads を呼び出していない場合、IceAppUnlockConn は何もしない。

第十五章 補助関数

  一時的な作業領域(scratch space)を確保するには(例えば可変長データ付きのメッセージを生成する時)、IceAllocScratch を用いる。各 ICE 接続には、この一時作業領域が一つづつ備わっている。一時作業領域は空の状態から始まり、必要に応じて増えていく。何らかの ICElib 関数が呼び出された後には、一時作業領域の中身が保たれている保証はない。

char *IceAllocScratch(IceConn ice_conn, unsigned long size);

ice_conn

ICE 接続オブジェクト。

size

要求するバイト数。

  IceAllocScratch の戻り値として取得した記憶領域は、同関数の呼出者が解放してはいけないという点に注意する。この領域は、領域を保持する ICE 接続が閉じられた時に、ICE ライブラリによって解放される。

第十六章 謝辞

  ICE ライブラリの設計は、Bob Scheifler 氏の助言に負うところが大きいので、ここでお礼を申し上げる。また、Jordan Brown 氏、Larry Cable 氏、Donna Converse 氏、Clive Feather 氏、Stephen Gildea 氏、Vania Joloboff 氏、Kaleb Keithley 氏、Stuart Marks 氏、Hiro Miyamoto 氏、Ralph Swick 氏、Jim VanGilder 氏、及び Mike Wexler 氏にもお礼を申し上げる。

附録 A 認証作業のための用役関数

  本文書で既に述べたように、ICE ライブラリが認証データ(ConnectionSetup メッセージや ProtocolSetup メッセージで使用するもの)を取得する方法は、実装によって異なる。†[2]

  この附録では、ICE 許認可ファイル(ICE authority file)を操作する用役関数(utility functions)について説明する。許認可ファイルは、クライアント間での認証データの受け渡しに用いることができる。

  .ICEauthority ファイルに対する基本的な操作としては、以下のものがある。

  • ファイル名を取得する

  • 排他錠を掛ける

  • 排他錠を外す

  • 項目(entry)を読み込む

  • 項目(entry)を書き込む

  • 項目(entry)を検索する

  これらは比較的低水準な操作であり、ファイル中の項目を加え、削り、表示する「iceauth」のような名前のプログラムが存在することを想定している。

  これらの用役関数を用いるには、ヘッダ・ファイル <X11/ICE/ICEutil.h> を取り込まなければならない(include)。

  .ICEauthority ファイル中の項目(entry)一つは、次のデータ構造を以って定義されている。

typedef struct {
     char *protocol_name;
     unsigned short protocol_data_length;
     char *protocol_data;
     char *network_id;
     char *auth_name;
     unsigned short auth_data_length;
     char *auth_data;
} IceAuthFileEntry;

  protocol_name 部には、接続設定時の認証であれば「ICE」が、そうでなければ下位プロトコルの名前(例えば「XSMP」)が入る。それぞれの項目(entry)において、protocol_data 部にプロトコル固有のデータを記載することができる。このデータは、ファイルから削除する必要のある古い項目を探すのに役立つ。

  network_id 部には、認証を受理する側のクライアントのネットワーク ID が入る(例えばセッション・マネージャのネットワーク ID)。ネットワーク ID は次の書式で表される。

tcp/<hostname>:<portnumber>もしくは
decnet/<hostname>::<objname>もしくは
local/<hostname>:<path>

  auth_name 部には認証方式の名前が入る。auth_data 部には実際の認証データが入り、auth_data_length 部にはそのデータのバイト数が入る。

  標準の許認可ファイル名を取得するには、IceAuthFileName を用いる。

char *IceAuthFileName(void);

  環境変数 ICEAUTHORITY が設定されていれば、その値が返る。さもなければ、$HOME/.ICEauthority が標準の許認可ファイル名となる。この名前を保持する領域は静的に割り当てられているので、解放してはいけない。

  同期をとって許認可ファイルを更新するには、IceLockAuthFile を呼び出してファイルに排他錠を掛けなければならない。この関数はシステム・コール link の仕組みを利用している。即ち、新しいリンクの名前が既に存在するものと被った場合に、link の呼出しが蹉跌するという現象を利用している。

int IceLockAuthFile(char *file_name, int retries, int timeout, long dead);

file_name

排他錠を掛ける許認可ファイル。

retries

再試行の回数。

timeout

再試行と再試行との間の秒数。

dead

dead で指定された秒数を超えて存続している排他錠が既にあれば、これを破棄する。無条件に先行の排他錠を破棄するには、dead に 0 を渡す。

  下記の三つの値のうち一つが返る。

  • IceAuthLockSuccess - 排他錠を掛けるのに成功した。

  • IceAuthLockError - システム・エラーが発生。errno の出番である。

  • IceAuthLockTimeout - 指定された回数分の試行が全て失敗に終わった。

  許認可ファイルに掛かった排他錠を外すには、IceUnlockAuthFile を用いる。

void IceUnlockAuthFile(char *file_name);

file_name

排他錠を外す許認可ファイル。

  許認可ファイル中の次の項目(entry)を読み込むには、IceReadAuthFileEntry を用いる。

IceAuthFileEntry *IceReadAuthFileEntry(FILE *auth_file);

auth_file

許認可ファイル(authorization file)。

  この関数を呼び出す前に、読み込むべきファイルを開いておくのは、アプリケーションの仕事である。エラーが起きるか、読み込むべき項目(entry)がなくなれば、NULL が返る。

  取得した項目(entries)は IceFreeAuthFileEntry を呼び出して解放するものとする。

  許認可ファイル中に項目(entry)を一つ書き込むには、IceWriteAuthFileEntry を用いる。

Status IceWriteAuthFileEntry(FILE *auth_file, IceAuthFileEntry *entry);

auth_file

許認可ファイル(authorization file)。

entry

書き込む項目(entry)。

  この関数を呼び出す前に、書き込むべきファイルを開いておくのは、アプリケーションの仕事である。関数が成功裡に終われば、0 でない Status が返る。

  標準(default)の許認可ファイルの中から、指定された protocol_name/network_id/auth_name の組に一致する項目を探し出すには、IceGetAuthFileEntry を用いる。

IceAuthFileEntry *IceGetAuthFileEntry(const char *protocol_name, const char *network_id, const char *auth_name);

protocol_name

項目検索に用いるプロトコル名。

network_id

項目検索に用いるネットワーク ID。

auth_name

項目検索に用いる認証方式名。

  IceGetAuthFileEntry の結果、指定したような項目が見つからなかった場合、NULL が返る。

   IceReadAuthFileEntry もしくは IceGetAuthFileEntry で取得した項目(entry)を解放するには、IceFreeAuthFileEntry を用いる。

void IceFreeAuthFileEntry(IceAuthFileEntry *entry);

entry

解放する項目(entry)。



  [2] X Consortium(X 協会)の ICElib は、ICE 許認可ファイルが存在するものと想定して実装されている。

附録 B MIT-MAGIC-COOKIE-1 による認証

  X 協会の ICElib の実装には、MIT-MAGIC-COOKIE-1 を利用した簡易な認証機構が備わっている。この機構は附録 A で述べた、許認可ファイル利用関数を用いている。

  この方式において、セッションマネージャのような位地にあるアプリケーションは、まず IceGenerateMagicCookie を呼び出してマジック・クッキーを取得し、次いで利用者の手元の(local) .ICEauthority ファイル中にそのマジック・クッキーを記録する。これによって、地局の(local)クライアントは先のアプリケーションに接続できるようになる。遠隔のクライアントが接続できるようにするには、遠隔機上にある利用者の .ICEauthority ファイル中にマジック・クッキーを記録するための、何らかの遠隔実行の仕組みを用いる。

  アプリケーションでは、「.ICEauthority」ファイルにマジック・クッキーを書き込むに止まらず、同クッキーをメモリにも書き込むため、関数 IceSetPaAuthData を呼び出す必要がある。MIT-MAGIC-COOKIE-1 認証手続きにおいて接続を受理・拒否する段になると、同手続きでは、申請者(requestor)の提示するマジック・クッキーとメモリにあるマジック・クッキーとの比較が行われる。

char *IceGenerateMagicCookie(int length);

length

マジック・クッキーの長さを指定。

  戻り値たるマジック・クッキーは null 文字終端である。マジック・クッキーのためにメモリ(一時記憶領域)を割り当てられなかった時は、上の関数は NULL を返す。さもなければ、取得したマジック・クッキーは free を呼び出して解放する。

  認証データを一時記憶領域(memory)に写すには、IceSetPaAuthData を用いる。この関数は、今のところ MIT-MAGIC-COOKIE-1を用いた認証にしか使用されていないが、将来は他の認証方式で利用されることもあろう。

void IceSetPaAuthData(int num_entries, IceAuthDataEntry *entries);

num_entries

認証データの項目(entry)数。

entries

認証データの項目(entry)の配列(訳註:将来、連結リストにしたいらしい)。

  各項目(entry)には、プロトコルの名前(例えば、ICE 接続設定の認証であれば「ICE」、セッション管理の認証であれば「XSMP」)、受理方クライアントのネットワーク ID、認証方式の名前(例えば MIT-MAGIC-COOKIE-1)、そして認証データが結び付けられている。ICE ライブラリでは、渡された項目群と前から設定されていた項目群とを、「protocol_name、network_id、auth_name」の三値一組を鍵として、混ぜ合わせる(merge)。(訳註:libICE-1.0.8/src/setauth.c では、三値同一の項目があれば、新しく渡された項目で上書きする。その他の新項目は配列の後ろに足していく。)

typedef struct {
	char *protocol_name;
	char *network_id;
	char *auth_name;
	unsigned short auth_data_length;
	char *auth_data;
} IceAuthDataEntry;

入り口に戻る