名 前
getaddrinfo_a, gai_suspend, gai_error, gai_cancel − 非 同 期 の ネ ッ ト ワ ー ク ア ド レ ス と サ ー ビ ス の 変 換
書 式
#define
_GNU_SOURCE /* feature_test_macros(7) 参 照
*/
#include <netdb.h>
int
getaddrinfo_a(int mode, struct gaicb
*list[],
int nitems, struct sigevent
*sevp);
int
gai_suspend(const struct gaicb * const list[],
int nitems,
const struct timespec *timeout);
int gai_error(struct gaicb *req);
int gai_cancel(struct gaicb *req);
−lanl で リ ン ク す る 。
説 明
getaddrinfo_a() 関 数 は getaddrinfo(3) と 同 じ 処 理 を 実 行 す る が 、 複 数 の 名 前 検 索 を 非 同 期 で 実 行 で き 、 検 索 処 理 の 完 了 の 通 知 が で き る 点 が 異 な る 。
mode
引 き 数 は 以 下
の 値 の い ず れ
か を 指 定 す る
。
GAI_WAIT 検 索 を 同 期
で 実 行 す る 。
呼 び 出 し は 検
索 が 完 了 す る
ま で 停 止 (block) す
る 。
GAI_NOWAIT 検 索 を 非 同
期 で 実 行 す る
。 呼 び 出 し は
直 ち に 返 り 、
要 求 は バ ッ ク
グ ラ ウ ン ド で
処 理 さ れ る 。
以 下 の sevp 引 き
数 の 議 論 を 参
照 。 配 列 list は
処 理 す べ き 検
索 要 求 を 指 定
す る 。 nitems 引 き
数 は list の 要 素
数 を 指 定 す る
。 要 求 さ れ た
検 索 命 令 は 並
列 に 開 始 さ れ
る 。 list の NULL 要
素 は 無 視 さ れ
る 。 各 要 求 は
以 下 の よ う に
定 義 さ れ た gaicb
構 造 体 で 規 定
さ れ る 。
struct gaicb {
const char *ar_name;
const char *ar_service;
const struct addrinfo *ar_request;
struct addrinfo *ar_result; }; こ の 構
造 体 の 要 素 は
getaddrinfo(3) の 引 き 数
に 対 応 し て い
る 。 し た が っ
て 、 ar_name は イ ン
タ ー ネ ッ ト ホ
ス ト を 示 す node
引 き 数 に 、
ar_service は サ ー ビ
ス を 示 す service 引
き 数 に 対 応 す
る 。 ar_request 要 素
は 、 返 さ れ た
ソ ケ ッ ト ア ド
レ ス 構 造 体 を
選 択 す る 基 準
を 示 す hints 引 き
数 に 対 応 す る
。 最 後 の ar_request
は res 引 き 数 に
対 応 す る 。 こ
の 要 素 を 初 期
化 す る 必 要 は
な く 、 こ の 要
素 は 要 求 が 解
決 さ れ る と 自
動 的 に セ ッ ト
さ れ る 。 最 後
の 2 つ の 要 素 が
参 照 し て い る
addrinfo 構 造 体 に つ
い て は getaddrinfo(3) に
説 明 が あ る 。
mode
に GAI_NOWAIT が 指 定
さ れ た 場 合 、
解 決 し た 要 求
に 関 す る 通 知
を sevp 引 き 数 が
指 す sigevent 構 造 体
を 使 っ て 受 け
取 る こ と が で
き る 。 こ の 構
造 体 の 定 義 と
一 般 的 な 説 明
に つ い て は
sigevent(7) を 参 照 。
sevp−>sigev_notify フ ィ
ー ル ド に は 以
下 の 値 を 指 定
で き る 。
SIGEV_NONE 通 知 は 行 わ
な い 。
SIGEV_SIGNAL 検 索 が 完
了 し た 際 に 、
プ ロ セ ス に 対
し て シ グ ナ ル
sigev_signo を 生 成 す
る 。 一 般 的 な
説 明 は sigevent(7) を
参 照 。 siginfo_t 構
造 体 の si_code フ ィ
ー ル ド に は
SI_ASYNCNL が セ ッ ト
さ れ る 。
SIGEV_THREAD 検 索 が 完
了 し た 際 に 、
sigev_notify_function を 新 し
い ス レ ッ ド の
開 始 関 数 で あ
る か の よ う に
起 動 す る 。 詳
細 は sigevent(7) を 参
照 。
SIGEV_SIGNAL と SIGEV_THREAD で は 、 sevp−>sigev_value.sival_ptr が list を 指 す よ う に し て お く と 役 立 つ こ と が あ る 。
gai_suspend() 関 数 は 呼 び 出 し 元 の ス レ ッ ド の 実 行 を 中 断 し 、 配 列 list 内 の 一 つ 以 上 の 要 求 が 完 了 す る の を 待 つ 。 nitems 引 き 数 は 配 列 list の 大 き さ を 指 定 す る 。 呼 び 出 し は 以 下 の い ず れ か の 状 況 に な る ま で 停 止 す る 。
* |
list 内 の 一 つ 以 上 の 操 作 が 完 了 し た 。 |
|||
* |
呼 び 出 し が 補 足 さ れ た シ グ ナ ル に 割 り 込 ま れ た 。
* |
timeout で 指 定 さ れ た 期 間 が 経 過 し た 。 こ の 引 き 数 は 、 秒 と ナ ノ 秒 で タ イ ム ア ウ ト を 指 定 す る (timespec 構 造 体 の 詳 細 は nanosleep(2) を 参 照 )。 timeout が NULL の 場 合 、 (上 記 の イ ベ ン ト の い ず れ か が 発 生 す る ま で ) 呼 び 出 し は 無 限 に 停 止 す る 。 |
ど の 要 求 が 完 了 し た か は 明 示 的 な 通 知 は 行 わ れ な い 。 ど の 要 求 が 完 了 し た か を 知 る た め に は 、 要 求 の リ ス ト に 対 し て gai_error() を 繰 り 返 し 呼 び 出 す 必 要 が あ る 。
gai_error() 関 数 は 要 求 req の ス テ ー タ ス を 返 す 。 要 求 が ま だ 完 了 し て い な い 場 合 は EAI_INPROGRESS が 、 要 求 が 正 常 に 処 理 さ れ た 場 合 は 0 が 、 要 求 を 解 決 で き な か っ た 場 合 は エ ラ ー コ ー ド が 返 さ れ る 。
gai_cancel() 関 数 は 要 求 req を キ ャ ン セ ル す る 。 要 求 が 正 常 に キ ャ ン セ ル さ れ た 場 合 、 要 求 の エ ラ ー ス テ ー タ ス に EAI_CANCELLED が 設 定 さ れ 、 通 常 の 非 同 期 通 知 が 実 行 さ れ る 。 要 求 が 現 在 処 理 中 で キ ャ ン セ ル で き な い 場 合 も あ る 。 こ の 場 合 gai_cancel() が 呼 ば れ な か っ た か の よ う に 処 理 が 行 わ れ る 。 req が NULL の 場 合 、 そ の プ ロ セ ス が 行 っ た す べ て の 処 理 中 の 要 求 を キ ャ ン セ ル し よ う と す る 。
返 り 値
getaddrinfo_a()
関 数 は す べ て
の 要 求 が 正 常
に キ ュ ー に 追
加 さ れ る と 0 を
返 す 。 ま た は
、 以 下 の い ず
れ か の 0 で な い
エ ラ ー コ ー ド
を 返 す 。
EAI_AGAIN 検 索 要 求 を
キ ュ ー に 入 れ
る た め に 必 要
な リ ソ ー ス が
な か っ た 。 ア
プ リ ケ ー シ ョ
ン は 書 く 要 求
の エ ラ ー ス テ
ー タ ス を 確 認
し 、 ど の 要 求
が 失 敗 し た か
を 判 定 す る こ
と が で き る 。
EAI_MEMORY メ モ リ ー が
足 り な い 。
EAI_SYSTEM
mode が 無 効 で あ る 。
gai_suspend()
関 数 は リ ス ト
の 要 求 の 少 な
く と も ひ と つ
が 完 了 す る と 0
を 返 す 。 そ れ
以 外 の 場 合 、
以 下 の 0 で な い
エ ラ ー コ ー ド
の い ず れ か を
返 す 。
EAI_AGAIN い ず れ か の
要 求 が 完 了 す
る 前 に 指 定 さ
れ た タ イ ム ア
ウ ト 時 間 が 満
了 し た 。
EAI_ALLDONE 指 定 さ れ た
関 数 に は 実 際
に は 要 求 が な
か っ た 。
EAI_INTR シ グ ナ ル が
関 数 に 割 り 込
ん だ 。 こ の 割
り 込 み は 検 索
要 求 が 完 了 し
た こ と を 示 す
シ グ ナ ル 通 知
に よ り 起 こ る
場 合 も あ る 。
gai_error() 関 数 は 、 完 了 し て い な い 検 索 要 求 に 対 し て EAI_INPROGRESS を 返 し 、 成 功 で 完 了 し た 検 索 に 対 し て 0 を 返 す 。 getaddrinfo(3) が 返 す エ ラ ー コ ー ド の い ず れ か を 返 す 場 合 も あ る 。 要 求 の 完 了 前 に 明 示 的 に 要 求 が キ ャ ン セ ル さ れ た 場 合 は エ ラ ー コ ー ド EAI_CANCELLED を 返 す 。
gai_cancel()
関 数 は こ れ ら
の 値 の い ず れ
か を 返 す こ と
が あ る 。
EAI_CANCELLED 要 求 は 正
常 に キ ャ ン セ
ル さ れ た 。
EAI_NOTCANCELLED 要 求 は キ
ャ ン セ ル さ れ
て い な い 。
EAI_ALLDONE 要 求 は す で
に 完 了 し て い
る 。
gai_strerror(3) 関 数 を 使 う と 、 こ れ ら の エ ラ ー コ ー ド を 、 エ ラ ー レ ポ ー ト に 適 し た 人 間 が 読 み や す い 文 字 列 に 翻 訳 し て く れ る 。
準 拠
こ れ ら の 関 数 は GNU 拡 張 で あ る 。 バ ー ジ ョ ン 2.2.3 で 初 め て glibc に 登 場 し た 。
注 意
getaddrinfo_a() イ ン タ ー フ ェ ー ス は lio_listio(3) イ ン タ ー フ ェ ー ス の 後 に モ デ ル 化 さ れ た 。
例
こ こ で は 二 つ の 例 を 示 す 。 一 つ は 複 数 の 要 求 を 同 期 処 理 で 並 行 し て 解 決 す る 例 で 、 も う 一 つ は 非 同 期 機 能 を 使 っ た 複 雑 な 例 で あ る 。 同 期 型 の 例 以 下 の プ ロ グ ラ ム は 単 に 複 数 の ホ ス ト 名 の 解 決 を 並 行 で 行 う 。 getaddrinfo(3) を 使 っ て 順 番 に ホ ス ト 名 の 解 決 を 行 う の に 比 べ て 速 度 が 向 上 す る 。 こ の プ ロ グ ラ ム は 以 下 の よ う に 使 う 。
$ ./a.out
ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
ftp.us.kernel.org: 128.30.2.36
enoent.linuxfoundation.org: Name or service not known
gnu.cz: 87.236.197.13 プ ロ グ ラ
ム の ソ ー ス コ
ー ド は 以 下 の
と お り で あ る
。
#define
_GNU_SOURCE
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int i, ret;
struct gaicb *reqs[argc − 1];
char host[NI_MAXHOST];
struct addrinfo *res;
if (argc <
2) {
fprintf(stderr, "Usage: %s HOST...\n", argv[0]);
exit(EXIT_FAILURE); }
for (i = 0; i
< argc − 1; i++) {
reqs[i] = malloc(sizeof(*reqs[0]));
if (reqs[i] == NULL) {
perror("malloc");
exit(EXIT_FAILURE); }
memset(reqs[i], 0, sizeof(*reqs[0]));
reqs[i]−>ar_name = argv[i + 1]; }
ret =
getaddrinfo_a(GAI_WAIT, reqs, argc − 1, NULL);
if (ret != 0) {
fprintf(stderr, "getaddrinfo_a() failed: %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE); }
for (i = 0; i
< argc − 1; i++) {
printf("%s: ", reqs[i]−>ar_name);
ret = gai_error(reqs[i]);
if (ret == 0) {
res = reqs[i]−>ar_result;
ret =
getnameinfo(res−>ai_addr, res−>ai_addrlen,
host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
if (ret != 0) {
fprintf(stderr, "getnameinfo() failed: %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE); }
puts(host); }
else {
puts(gai_strerror(ret)); } }
exit(EXIT_SUCCESS); } 非 同 期 型
の 例 こ の 例 は
getaddrinfo_a() の 簡 単 な
対 話 式 の フ ロ
ン ト エ ン ド で
あ る 。 通 知 機
能 は 使 っ て い
な い 。 セ ッ シ
ョ ン の 実 行 例
は 以 下 の よ う
に な る 。
$
./a.out >
a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz >
c 2
[2] gnu.cz: Request not canceled >
w 0 1
[00] ftp.us.kernel.org: Finished >
l
[00] ftp.us.kernel.org: 216.165.129.139
[01] enoent.linuxfoundation.org: Processing request in
progress
[02] gnu.cz: 87.236.197.13 >
l
[00] ftp.us.kernel.org: 216.165.129.139
[01] enoent.linuxfoundation.org: Name or service not known
[02] gnu.cz: 87.236.197.13 プ ロ グ
ラ ム の ソ ー ス
は 以 下 の と お
り で あ る 。
#define
_GNU_SOURCE
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct
gaicb **reqs = NULL;
static int nreqs = 0;
static char *
getcmd(void)
{
static char buf[256];
fputs(">
", stdout); fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
return NULL;
if
(buf[strlen(buf) − 1] == '\n')
buf[strlen(buf) − 1] = 0;
return buf; }
/* Add requests
for specified hostnames */
static void
add_requests(void)
{
int nreqs_base = nreqs;
char *host;
int ret;
while ((host =
strtok(NULL, " "))) {
nreqs++;
reqs = realloc(reqs, nreqs * sizeof(reqs[0]));
reqs[nreqs
− 1] = calloc(1, sizeof(*reqs[0]));
reqs[nreqs − 1]−>ar_name = strdup(host);
}
/* Queue nreqs_base..nreqs requests. */
ret =
getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
nreqs − nreqs_base, NULL);
if (ret) {
fprintf(stderr, "getaddrinfo_a() failed: %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE); } }
/* Wait until
at least one of specified requests completes */
static void
wait_requests(void)
{
char *id;
int i, ret, n;
struct gaicb const **wait_reqs = calloc(nreqs,
sizeof(*wait_reqs));
/* NULL elements are ignored by gai_suspend(). */
while ((id =
strtok(NULL, " ")) != NULL) {
n = atoi(id);
if (n >=
nreqs) {
printf("Bad request number: %s\n", id);
return; }
wait_reqs[n] = reqs[n]; }
ret =
gai_suspend(wait_reqs, nreqs, NULL);
if (ret) {
printf("gai_suspend(): %s\n", gai_strerror(ret));
return; }
for (i = 0; i
< nreqs; i++) {
if (wait_reqs[i] == NULL)
continue;
ret =
gai_error(reqs[i]);
if (ret == EAI_INPROGRESS)
continue;
printf("[%02d]
%s: %s\n", i, reqs[i]−>ar_name,
ret == 0 ? "Finished" : gai_strerror(ret)); }
}
/* Cancel
specified requests */
static void
cancel_requests(void)
{
char *id;
int ret, n;
while ((id =
strtok(NULL, " ")) != NULL) {
n = atoi(id);
if (n >=
nreqs) {
printf("Bad request number: %s\n", id);
return; }
ret =
gai_cancel(reqs[n]);
printf("[%s] %s: %s\n", id,
reqs[atoi(id)]−>ar_name,
gai_strerror(ret)); } }
/* List all
requests */
static void
list_requests(void)
{
int i, ret;
char host[NI_MAXHOST];
struct addrinfo *res;
for (i = 0; i
< nreqs; i++) {
printf("[%02d] %s: ", i,
reqs[i]−>ar_name);
ret = gai_error(reqs[i]);
if (!ret) {
res = reqs[i]−>ar_result;
ret =
getnameinfo(res−>ai_addr, res−>ai_addrlen,
host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
if (ret) {
fprintf(stderr, "getnameinfo() failed: %s\n",
gai_strerror(ret));
exit(EXIT_FAILURE); }
puts(host); }
else {
puts(gai_strerror(ret)); } } }
int
main(int argc, char *argv[])
{
char *cmdline;
char *cmd;
while ((cmdline
= getcmd()) != NULL) {
cmd = strtok(cmdline, " ");
if (cmd ==
NULL) {
list_requests(); }
else {
switch (cmd[0]) {
case 'a':
add_requests();
break;
case 'w':
wait_requests();
break;
case 'c':
cancel_requests();
break;
case 'l':
list_requests();
break;
default:
fprintf(stderr, "Bad command: %c\n", cmd[0]);
break; } } }
exit(EXIT_SUCCESS); }
関 連 項 目
getaddrinfo(3), inet(3), lio_listio(3), hostname(7), ip(7), sigevent(7)
こ の 文 書 に つ い て
こ の man ペ ー ジ は Linux man−pages プ ロ ジ ェ ク ト の リ リ ー ス 3.79 の 一 部 で あ る 。 プ ロ ジ ェ ク ト の 説 明 と バ グ 報 告 に 関 す る 情 報 は http://www.kernel.org/doc/man−pages/ に 書 か れ て い る 。