idnkit ライブラリの API
idnkit ライブラリでは、アプリケーションを国際化ドメイン名に対応させる ために必要な処理を API として提供しています。 この文書は、ライブラリの提供する API について解説します。
- 概要
-
初期化 (
idn_nameinit
) -
エンコード (
idn_encodename
) -
デコード (
idn_decodename
) -
環境変数 IDN_DISABLE のオーバーライド
(
idn_enable
) - プログラム作成方法
- プログラム例
概要
国際化ドメイン名の処理は次の3つの処理から構成されます。
- エンコーディング変換
- デリミタマッピング
- NAMEPREP
idnkit では、これに加えて地域化のために
- トップレベルドメインに基づくローカルマッピング
という処理を追加しています。
国際化ドメイン処理のアーキテクチャ
IDNA
では、これらの処理はすべてアプリケーションで行うことになっており、
例えば名前解決用の関数 gethostbyname
を呼び出して
国際化ドメイン名の名前解決を行う場合には、
すでにこれらの処理が行われた結果の文字列を渡すことになっています。
idnkit はアプリケーションでこれらの処理を行うために 2種類の API を用意しています。
- 高レベル API
- 一般アプリケーションのためのシンプルで使いやすい API です。 この API を使用すれば、アプリケーションに簡単に国際化ドメイン処理機能を 追加することができます。ただし細かい設定などはできません。
- 低レベル API
- 高レベル API ではできないような細かい設定をする必要がある 一部の特殊なアプリケーションのための API です。 高レベル API はこの低レベル API の上に作られています。
低レベル API は特殊なアプリケーションのために用意された API ですので、
ここでは説明しません。もし低レベル API を使用したい場合には、
idnkit ライブラリ仕様書の
resconf
モジュール
および
res
モジュール
をご覧ください。
高レベル API は次の3つの関数から構成されます。
- 初期化を行う
idn_nameinit
- 名前解決などのために国際化ドメイン名をエンコードする
idn_encodename
- DNS サーバなどから返ってきた国際化ドメイン名をデコードする
idn_decodename
以下、それぞれの関数の説明をします。
idnkit ライブラリ仕様書の
api
モジュール
も合わせてご覧ください。
初期化
国際化ドメイン名の処理のための初期化を行うためには
idn_nameinit
を用います。
idn_result_t idn_nameinit(int load_file)
高レベル API モジュールの初期化を行います。
load_file
に 0 以外の値を指定すると、
設定ファイル を読み込みます。
load_file
に 0 を指定すると、設定ファイルを全く参照せず、
標準の設定 (IDN エンコーディングに Punycode、NAMEPREP に最新バージョン
を指定) を使って初期化が行われます。
この関数は戻り値として実行結果を示す
idn_result_t
型の値を返します。
本関数が返すコードとその意味は次の通りです。
-
idn_success
- 初期化が正常に終了した。
-
idn_nofile
- 設定ファイルがオープンできなかった。
-
idn_invalid_syntax
- 設定ファイルにシンタックスエラーがある。
-
idn_invalid_name
- 設定ファイルに指定されている名前 (エンコーディング名など) に誤りがある。
-
idn_nomemory
- malloc に失敗した。
この関数を複数回呼び出すこともできますが、初期化が行われるのは初回の 呼び出しの時だけで、2 回目以降は何も行われません。
この関数をあらかじめ呼び出さずにエンコードやデコード関数を
呼び出しても構いません。その場合には、エンコードやデコードの処理に
先立って、idn_nameinit(0)
による初期化が暗黙的に行われます。
エンコード
国際化ドメイン名のエンコード処理、つまり名前解決関数などへ渡すための
文字列に変換するには idn_encodename
を用います。
idn_result_t idn_encodename(idn_action_t actions, const char *from, char *to, size_t tolen)
引数 actions には、エンコード処理のどの工程を実行するかを
指定します。
通常のエンコード処理では、クエリー時に必要なすべての工程を行うことを示す
IDN_ENCODE_APP
というマクロの値を指定することになります。
特定の工程だけ処理したい場合は、各処理工程を表すマクロ値の論理和 (OR) を指定します。 用意されているマクロは次の通りです。 なお、各処理はここに挙げた順番で行われます。
-
IDN_LOCALCONV
- ローカルエンコーディングから UTF-8 への変換を行う
-
IDN_DELIMMAP
- デリミタマッピングを行う
-
IDN_LOCALMAP
- トップレベルドメインに基づくローカルマッピングを行う
-
IDN_NAMEPREP
- NAMEPREP (国際化ドメイン名の正規化、禁止文字の検出など) を行う
-
IDN_UNASCHECK
- 未割り当てコードポイントのチェックを行う。
-
IDN_ASCCHECK
- ASCII 文字に関するチェック (英数字やハイフン以外の文字の有無など) を行う。
-
IDN_IDNCONV
- UTF-8 から IDN エンコーディングへの変換を行う
-
IDN_LENCHECK
- ドメイン名の各ラベルの長さをチェックする。
from で指定されるドメイン名に対して、actions で 指定された処理を行い、その結果を to の指す領域に書き込みます。 tolen は to の指す領域の大きさ (バイト数、末尾の ナル文字を含む) で、tolen を越えて書き込むことはありません。
この関数は戻り値として実行結果を示す
idn_result_t
型の値を返します。
本関数が返すコードとその意味は次の通りです。
-
idn_success
- 処理が正常に終了した。
-
idn_invalid_action
- actions で誤ったフラグを指定している。
-
idn_invalid_encoding
- from で指定された文字列のエンコーディングに誤りがある。
-
idn_invalid_length
- 変換した結果、いずれかのラベルの長さが範囲外になった。
-
idn_prohibited
- 入力文字列中に禁止文字あるいは Unicode の未割り当てコードポイントが 存在する。
-
idn_buffer_overflow
- tolen の値が小さすぎて結果を格納できない。
-
idn_nomemory
- malloc に失敗した。
なお、初期化関数 idn_nameinit
を事前に呼び出さずに
本関数を呼び出した場合には、上に示した他に次のような実行結果を返す
ことがあります。
-
idn_nofile
- 設定ファイルがオープンできなかった。
-
idn_invalid_syntax
- 設定ファイルにシンタックスエラーがある。
-
idn_invalid_name
- 設定ファイルに指定されている名前 (エンコーディング名など) に 誤りがある。
なお、設定によっては、この関数を使用しても文字列の変換は行われず、 元の文字列のままの結果が返されることがあります。 詳しくは 環境変数 IDN_DISABLE のオーバーライド をご覧ください。
デコード
国際化ドメイン名のデコード処理、つまり名前解決関数などから返された
IDN エンコーディングのドメイン名文字列を、アプリケーションが使用
しているローカルエンコーディングに変換するには idn_decodename
を用います。
idn_result_t idn_decodename(idn_action_t actions, const char *from, char *to, size_t tolen)
引数 actions には、デコード処理のどの工程を実行するかを
指定します。
通常のデコード処理では、すべての工程を行うことを示す
IDN_DECODE_APP
というマクロの値を指定することになります。
特定の工程だけ処理したい場合は、各処理工程を表すマクロ値の論理和 (OR) を指定します。 用意されているマクロは次の通りです。 なお、各処理はここに挙げた順番で行われます。
-
IDN_DELIMMAP
- デリミタマッピングを行う
-
IDN_NAMEPREP
- NAMEPREP (国際化ドメイン名の正規化、禁止文字の検出など) を行う
-
IDN_UNASCHECK
- 未割り当てコードポイントのチェックを行う。
-
IDN_IDNCONV
- IDN エンコーディングから UTF-8 への変換を行う
-
IDN_RTCHECK
- 国際化ドメイン名が正しくエンコードされたものかどうかを調べるために、 再びエンコードして一致するかどうか確認する。 一致しなかった場合は IDN エンコーディングへ戻す。 一致した場合は UTF-8 のまま。
-
IDN_ASCCHECK
- ラウンドトリップチェック時に、ASCII 文字に関するチェック (英数字やハイフン以外の文字の有無など) を行う。
-
IDN_LOCALCONV
- UTF-8 からローカルエンコーディングへの変換を行う。 ただしローカルエンコーディングに対応する文字がないために 変換不可能な場合には、IDN エンコーディングへの変換を行う。
from で指定されるドメイン名に対して、actions で 指定される処理を行い、その結果を to の指す領域に書き込みます。 tolen は to の指す領域の大きさ (バイト数、末尾の ナル文字を含む) で、tolen を越えて書き込むことはありません。
なお、上記の各処理でのパラメータはすべて idnkit の 設定ファイル で設定されたものが使用されます。 以下に使用されるパラメータを記します。
- IDN エンコーディングとして使用するエンコーディング名
- NAMEPREP のバージョン
この関数は戻り値として実行結果を示す
idn_result_t
型の値を返します。
本関数が返すコードとその意味は次の通りです。
-
idn_success
- 処理が正常に終了した。
-
idn_invalid_action
- actions で誤ったフラグを指定している。
-
idn_invalid_encoding
- from で指定された文字列のエンコーディングに誤りがある。
-
idn_buffer_overflow
- tolen の値が小さすぎて結果を格納できない。
-
idn_nomemory
- malloc に失敗した。
なお、初期化関数 idn_nameinit
を事前に呼び出さずに
本関数を呼び出した場合には、上に示した他に次のような実行結果を返す
ことがあります。
-
idn_nofile
- 設定ファイルがオープンできなかった。
-
idn_invalid_syntax
- 設定ファイルにシンタックスエラーがある。
-
idn_invalid_name
- 設定ファイルに指定されている名前 (エンコーディング名など) に 誤りがある。
なお、設定によっては、この関数を使用しても文字列の変換は行われず、 元の文字列のままの結果が返されることがあります。 詳しくは 環境変数 IDN_DISABLE のオーバーライド をご覧ください。
環境変数 IDN_DISABLE のオーバーライド
通常の場合、
環境変数 IDN_DISABLE
が設定されている環境でドメイン名をエンコード、デコードしても変換処理は
実行されず、元の文字列のまま結果が返されます。
ただし、この設定を明示的にオーバーライドするための API として、
idn_enable
が用意されています。
void idn_enable(int on_off)
環境変数 IDN_DISABLE が設定されているかどうかにかかわらず、 on_off が 0 の場合、これ以降のドメイン名変換は行われません。 また、on_off が 0 以外の値であれば、この関数の呼び出し以降は IDN_DISABLE 環境変数が設定されているかどうかにかかわらず、ドメイン名変換 処理が行われます。
プログラム作成方法
上記の API を使用したプログラムを作る方法、および注意点などについて まとめておきます。
- インクルードファイル
高レベル API を使用するプログラムでは、stddef.h
とidn/api.h
の2つのヘッダファイルをインクルードしてください。#include <stddef.h> #include <idn/api.h>
- ロケール設定
idnkit はアプリケーションの使用しているローカルエンコーディングを ロケール情報、あるいは環境変数IDN_LOCAL_CODESET
から 取得します。ロケール情報から取得する場合にはアプリケーションの先頭でsetlocale
を行い、アプリケーションのロケールを正しく 設定してください。 - エラー表示
API はいずれもidn_result_t
型の値を返します。この値から 対応するメッセージ文字列を得るための関数idn_result_tostring
が用意されています。エラーメッセージを表示する際に使うことができます。 この関数については 仕様書の説明をご覧ください。 - コンパイルとリンク
コンパイルする際には、-I
オプションで idnkit の ヘッダファイルのインストールディレクトリ (デフォルトでは/usr/local/include
) を指定してください。
またリンクの際は idnkit ライブラリをリンクしてください。もし iconv が標準ライブラリにない場合には、iconv の ライブラリも合わせてリンクしてください。cc -I/usr/local/include example.c -L/usr/local/lib -lidn -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 <idn/api.h> int main(int ac, char **av) { struct hostent *hp; char buf1[256]; char buf2[256]; char addrbuf[100]; idn_result_t r; /* ロケールを設定する */ setlocale(LC_ALL, ""); if (ac != 2) { fprintf(stderr, "Usage: %s hostname\n", av[0]); return 1; } /* api モジュールを初期化する */ if ((r = idn_nameinit(1)) != != idn_success) { fprintf(stderr, "idn_nameinit: %s\n", idn_result_tostring(r)); return 1; } /* gethostbyname を呼ぶ前に名前を変換する */ if ((r = idn_encodename(IDN_ENCODE_APP, av[1], buf1, sizeof(buf1))) != idn_success) { fprintf(stderr, "idn_encodename: %s\n", idn_result_tostring(r)); return 1; } /* 名前解決を行う */ if ((hp = gethostbyname(buf1)) == NULL) { fprintf(stderr, "gethostbyname failed\n"); return 1; } /* 返された名前をローカルエンコーディングに変換する */ if ((r = idn_decodename(IDN_DECODE_APP, hp->h_name, buf2, sizeof(buf2))) != idn_success) { fprintf(stderr, "idn_decodename: %s\n", idn_result_tostring(r)); return 1; } printf("%s %s\n", inet_ntop(hp->h_addrtype, hp->h_addr, addrbuf, sizeof(addrbuf)), buf2); return 0; }