Manpages

名 前

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_requestres 引 き 数 に 対 応 す る 。 こ の 要 素 を 初 期 化 す る 必 要 は な く 、 こ の 要 素 は 要 求 が 解 決 さ れ る と 自 動 的 に セ ッ ト さ れ る 。 最 後 の 2 つ の 要 素 が 参 照 し て い る addrinfo 構 造 体 に つ い て は getaddrinfo(3) に 説 明 が あ る 。

modeGAI_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_SIGNALSIGEV_THREAD で は 、 sevp−>sigev_value.sival_ptrlist を 指 す よ う に し て お く と 役 立 つ こ と が あ る 。

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/ に 書 か れ て い る 。