多言語ドメイン名変換 API
- 概要
-
初期化 (
mdn_nameinit
) -
エンコード (
mdn_encodename
) -
デコード (
mdn_decodename
) -
環境変数 MDN_DISABLE のオーバーライド
(
mdn_enable
) - プログラム作成方法
- プログラム例
概要
多言語ドメイン名の処理は次の2つの処理から構成されます。
- エンコーディング変換
- NAMEPREP
mDNkit では、これに加えて地域化のために
- デリミタマッピング
- トップレベルドメインに基づくローカルマッピング
の2つの処理を追加しています。
多言語ドメイン処理のアーキテクチャ
IDNA
では、これらの処理はすべてアプリケーションで行うことになっており、
例えば名前解決用の関数 gethostbyname
を呼び出して
多言語ドメイン名の名前解決を行う場合には、
すでにこれらの処理が行われた結果の文字列を渡すことになっています。
mDNkit はアプリケーションでこれらの処理を行うために 2種類の API を用意しています。
- 高レベル API
- 一般アプリケーションのためのシンプルで使いやすい API です。 この API を使用すれば、アプリケーションに簡単に多言語ドメイン処理機能を 追加することができます。ただし細かい設定などはできません。
- 低レベル API
- 高レベル API ではできないような細かい設定をする必要がある 一部の特殊なアプリケーションのための API です。 高レベル API はこの低レベル API の上に作られています。
低レベル API は特殊なアプリケーションのために用意された API ですので、
ここでは説明しません。もし低レベル API を使用したい場合には、
MDN ライブラリ仕様書の
resconf
モジュール
および
res
モジュール
をご覧ください。
高レベル API は次の3つの関数から構成されます。
- 初期化を行う
mdn_nameinit
- 名前解決などのために多言語ドメイン名をエンコードする
mdn_encodename
- DNS サーバなどから返ってきた多言語ドメイン名をデコードする
mdn_decodename
以下、それぞれの関数の説明をします。
MDN ライブラリ仕様書の
api
モジュール
も合わせてご覧ください。
初期化
多言語ドメイン名の処理のための初期化を行うためには
mdn_nameinit
を用います。
mdn_result_t mdn_nameinit(void)
この関数は MDN ライブラリ全体の初期化を行い、次に 多言語ドメイン名の処理のための各種の設定が記述されている 設定ファイル (mdn.conf) を読み込みます。
この関数は戻り値として実行結果を示す
mdn_result_t
型の値を返します。
本関数が返すコードとその意味は次の通りです。
mdn_success
- 初期化が正常に終了した。
mdn_nofile
- 設定ファイルがオープンできなかった。
mdn_invalid_syntax
- 設定ファイルにシンタックスエラーがある。
mdn_invalid_name
- 設定ファイルに指定されている名前 (エンコーディング名など) に誤りがある。
mdn_nomemory
- malloc に失敗した。
この関数を複数回呼び出すこともできますが、その場合 MDN ライブラリ全体の初期化が行われるのは最初の呼び出しの時だけで、 2回目以降は設定ファイルの再読み込みのみが行われます。 アプリケーションの実行中に設定ファイルの内容を変更した場合、 この関数を呼び出すことで最新の設定に合わせることができます。
この関数をあらかじめ呼び出さずにエンコードやデコード関数を 呼び出しても構いません。その場合には、エンコードやデコードの処理に先だち この関数で行われるような初期化の処理が暗黙的に行われます。
エンコード
多言語ドメイン名のエンコード処理、つまり名前解決関数などへ渡すための
文字列に変換するには mdn_encodename
を用います。
mdn_result_t mdn_encodename(int actions, const char *from, char *to, size_t tolen)
from で指定されるドメイン名に対して、actions で 指定される処理を行い、その結果を to の指す領域に書き込みます。 tolen は to の指す領域の大きさ (バイト数) で、 tolen を越えて書き込むことはありません。
この関数による多言語ドメイン名のエンコード処理は一般的には 次のような手順になります。
- エンコーディング変換
アプリケーションの使用しているローカルエンコーディング (SJIS 等) から UTF-8 への変換 - デリミタマッピング
特定の文字を、ドメイン名の区切りであるドットに変換 - トップレベルドメインに基づくローカルマッピング
入力されたドメイン名のトップレベルドメインに対応するマッピング - NAMEPREP
多言語ドメイン名の正規化、禁止文字の検出 - エンコーディング変換
UTF-8 から、多言語ドメイン名の標準エンコーディング (IDN エンコーディング) への変換
引数 actions で、これらのどの処理を実際に実行するかを以下に示す フラグで指定します。 実際に actions に指定するのはこれらのビット毎の論理和です。
MDN_LOCALCONV
- ローカルエンコーディングから UTF-8 への変換を行う
MDN_DELIMMAP
- デリミタマッピングを行う
MDN_LOCALMAP
- トップレベルドメインに基づくローカルマッピングを行う
MDN_NAMEPREP
- 多言語ドメイン名の正規化、禁止文字の検出を行う
MDN_UNASCHECK
- NAMEPREP の中のオプショナルな機能 (実行してもしなくてもよい) である 未割り当てコードポイントの検出を実行する
MDN_IDNCONV
- UTF-8 から IDN エンコーディングへの変換を行う
通常のアプリケーションは MDN_UNASCHECK
を除くすべての処理を
行えばよいはずです。そのために MDN_ENCODE_APP
というマクロが
定義されており、actions にこの値を指定すれば
未割り当てコードポイントの検出を除くすべての処理が行われます。
なお、上記の各処理でのパラメータはすべて mDNkit の 設定ファイル (mdn.conf) で設定されたものが使用されます。以下に使用されるパラメータを記します。
- デリミタマッピングにおいてドットにマッピングする文字
- ローカルマッピング規則
- NAMEPREP のバージョン
- IDN エンコーディングとして使用するエンコーディング名
この関数は戻り値として実行結果を示す
mdn_result_t
型の値を返します。
本関数が返すコードとその意味は次の通りです。
mdn_success
- 処理が正常に終了した。
mdn_invalid_action
- actions で誤ったフラグを指定している。
mdn_invalid_encoding
- from で指定された文字列のエンコーディングに誤りがある。
mdn_prohibited
-
入力文字列中に禁止文字が存在する。
フラグ
MDN_UNASCHECK
を指定した場合には 未割り当てコードポイントが存在した場合にもこのコードを返す。 mdn_buffer_overflow
- tolen の値が小さすぎて結果を格納できない。
mdn_nomemory
- malloc に失敗した。
なお、初期化関数 mdn_nameinit
を事前に呼び出さずに
本関数を呼び出した場合には、変換処理に先だって初期化が行われます。
この場合には本関数は上に示した他に次のような実行結果を返すことがあります。
mdn_nofile
- 設定ファイルがオープンできなかった。
mdn_invalid_syntax
- 設定ファイルにシンタックスエラーがある。
mdn_invalid_name
- 設定ファイルに指定されている名前 (エンコーディング名など) に誤りがある。
なお、 環境変数 MDN_DISABLE が設定されている場合は、この関数を使用しても 文字列の変換は行われず、元の文字列のままの結果が返されます。 MDN_DISABLE が設定されている環境で文字列の変換を強制的に行う方法は、 環境変数 MDN_DISABLE のオーバーライド に書かれています。
デコード
多言語ドメイン名のデコード処理、つまり名前解決関数などから返された
エンコード済のドメイン名文字列を、アプリケーションが使用している
エンコーディングの文字列に変換するには mdn_decodename
を用います。
mdn_result_t mdn_decodename(int actions, const char *from, char *to, size_t tolen)
from で指定されるドメイン名に対して、actions で 指定される処理を行い、その結果を to の指す領域に書き込みます。 tolen は to の指す領域の大きさ (バイト数) で、 tolen を越えて書き込むことはありません。
この関数による多言語ドメイン名のデコード処理は一般的には 次のような手順になります。
- エンコーディング変換
多言語ドメイン名の標準エンコーディング (IDN エンコーディング) から UTF-8 への変換 - NAMEPREP チェック
正しく NAMEPREP が行われた文字列であるかどうかのチェック - エンコーディング変換
UTF-8 からアプリケーションの使用しているローカルエンコーディング (SJIS 等) への変換
引数 actions で、これらのどの処理を実際に実行するかを以下に示す フラグで指定します。 実際に actions に指定するのはこれらのビット毎の論理和です。
MDN_IDNCONV
- IDN エンコーディングから UTF-8 への変換を行う
MDN_NAMEPREP
- 正しく NAMEPREP が行われた文字列であるかどうかのチェックを行う。 正しく行われていない場合は、文字列を再び IDN エンコーディングに戻す。
MDN_UNASCHECK
- 文字列が NAMEPREP の未割り当てコードポイントを含んでいるかどうかのチェック を行う。含んでいた場合は、文字列を再び IDN エンコーディングに戻す。
MDN_LOCALCONV
- UTF-8 からローカルエンコーディングへの変換を行う。 ただしローカルエンコーディングに対応する文字がないために 変換不可能な場合には、IDN エンコーディングへの変換を行う。
通常のアプリケーションは MDN_UNASCHECK
を除くすべての処理を
行えばよいはずです。そのために MDN_DECODE_APP
というマクロが
定義されており、actions にこの値を指定すれば
未割り当てコードポイントの検出を除くすべての処理が行われます。
なお、上記の各処理でのパラメータはすべて mDNkit の 設定ファイル (mdn.conf) で設定されたものが使用されます。以下に使用されるパラメータを記します。
- IDN エンコーディングとして使用するエンコーディング名
- NAMEPREP のバージョン
この関数は戻り値として実行結果を示す
mdn_result_t
型の値を返します。
本関数が返すコードとその意味は次の通りです。
mdn_success
- 処理が正常に終了した。
mdn_invalid_action
- actions で誤ったフラグを指定している。
mdn_invalid_encoding
- from で指定された文字列のエンコーディングに誤りがある。
mdn_buffer_overflow
- tolen の値が小さすぎて結果を格納できない。
mdn_nomemory
- malloc に失敗した。
なお、初期化関数 mdn_nameinit
を事前に呼び出さずに
本関数を呼び出した場合には、変換処理に先だって初期化が行われます。
この場合には本関数は上に示した他に次のような実行結果を返すことがあります。
mdn_nofile
- 設定ファイルがオープンできなかった。
mdn_invalid_syntax
- 設定ファイルにシンタックスエラーがある。
mdn_invalid_name
- 設定ファイルに指定されている名前 (エンコーディング名など) に誤りがある。
なお、 環境変数 MDN_DISABLE が設定されている場合は、この関数を使用しても 文字列の変換は行われず、元の文字列のままの結果が返されます。 MDN_DISABLE が設定されている環境で文字列の変換を強制的に行う方法は、 環境変数 MDN_DISABLE のオーバーライド に書かれています。
環境変数 MDN_DISABLE のオーバーライド
通常の場合、
環境変数 MDN_DISABLE
が設定されている環境でドメイン名を変換
するための API を使用しても変換処理は実行されず、元の文字列のまま結果が
返されます。ただし、この設定を明示的にオーバーライドするための API とし
て、mdn_enable
が用意されています。
void mdn_enable(int on_off)
環境変数 MDN_DISABLE が設定されているかどうかにかかわらず、 on_off が 0 の場合、これ以降のドメイン名変換は行われません。 また、on_off が 0 以外の値であれば、この関数の呼び出し以降は MDN_DISABLE 環境変数が設定されているかどうかにかかわらず、ドメイン名変換 処理が行われます。
プログラム作成方法
上記の API を使用したプログラムを作る方法、および注意点などについて まとめておきます。
- インクルードファイル
高レベル API を使用するプログラムでは、stddef.h
とmdn/api.h
の2つのヘッダファイルをインクルードしてください。#include <stddef.h> #include <mdn/api.h>
- ロケール設定
mDNkit はアプリケーションの使用しているローカルエンコーディングを ロケール情報、あるいは環境変数MDN_LOCAL_CODESET
から 取得します。ロケール情報から取得する場合にはアプリケーションの先頭でsetlocale
を行い、アプリケーションのロケールを正しく 設定してください。 - エラー表示
API はいずれもmdn_result_t
型の値を返します。この値から 対応するメッセージ文字列を得るための関数mdn_result_tostring
が用意されています。エラーメッセージを表示する際に使うことができます。 この関数については 仕様書の説明をご覧ください。 - コンパイルとリンク
コンパイルする際には、-I
オプションで mDNkit の ヘッダファイルのインストールディレクトリ (デフォルトでは/usr/local/include
) を指定してください。
またリンクの際は MDN ライブラリをリンクしてください。もし iconv が標準ライブラリにない場合には、iconv の ライブラリも合わせてリンクしてください。cc -I/usr/local/include example.c -L/usr/local/lib -lmdn -liconv
プログラム例
ここでは、上記の API を使用して多言語ドメイン名の名前解決を行うための 簡単なプログラムを紹介します。
#include <stdio.h> #include <stddef.h> #include <netdb.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <mdn/api.h> int main(int ac, char **av) { struct hostent *hp; char buf1[256]; char buf2[256]; char addrbuf[100]; mdn_result_t r; /* ロケールを設定する */ setlocale(LC_ALL, ""); if (ac != 2) { fprintf(stderr, "Usage: %s hostname\n", av[0]); return 1; } /* gethostbyname を呼ぶ前に名前を変換する */ if ((r = mdn_encodename(MDN_ENCODE_APP, av[1], buf1, sizeof(buf1))) != mdn_success) { fprintf(stderr, "mdn_encodename: %s\n", mdn_result_tostring(r)); return 1; } /* 名前解決を行う */ if ((hp = gethostbyname(buf1)) == NULL) { fprintf(stderr, "gethostbyname failed\n"); return 1; } /* 返された名前をローカルエンコーディングに変換する */ if ((r = mdn_decodename(MDN_DECODE_APP, hp->h_name, buf2, sizeof(buf2))) != mdn_success) { fprintf(stderr, "mdn_decodename: %s\n", mdn_result_tostring(r)); return 1; } printf("%s %s\n", inet_ntop(hp->h_addrtype, hp->h_addr, addrbuf, sizeof(addrbuf)), buf2); return 0; }