Provided by: manpages-ja-dev_0.5.0.0.20221215+dfsg-1_all
名前
getaddrinfo, freeaddrinfo, gai_strerror - ネットワークのアドレスとサービスを変換する
書式
#include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); void freeaddrinfo(struct addrinfo *res); const char *gai_strerror(int errcode); glibc 向けの機能検査マクロの要件 (feature_test_macros(7) 参照): getaddrinfo(), freeaddrinfo(), gai_strerror(): Since glibc 2.22: _POSIX_C_SOURCE >= 200112L Glibc 2.21 and earlier: _POSIX_C_SOURCE
説明
getaddrinfo() は、(インターネットのホストとサービスを識別する) node と service を渡す と、一つ以上の addrinfo 構造体を返す。それぞれの addrinfo 構造体には、 bind(2) や connect(2) を呼び出す際に指定できるインターネットアドレスが格納されている。 getaddrinfo() 関数は、 gethostbyname(3) と getservbyname(3) の機能をまとめて一つのインターフェースにした ものであるが、 これらの関数と違い、 getaddrinfo() はリエントラントであり、 getaddrinfo() を使うことでプログラムは IPv4 と IPv6 の違いに関する依存関係を なくすことができる。 getaddrinfo() が用いる addrinfo 構造体は以下のフィールドを含む。 struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; socklen_t ai_addrlen; struct sockaddr *ai_addr; char *ai_canonname; struct addrinfo *ai_next; }; hints 引数は addrinfo 構造体を指し示し、この構造体を用いて res が指すリストに入れて返すソ ケットアドレス構造体を選択するための基準を指定する。 hints が NULL でない場合、 hints は addrinfo 構造体を指し示し、その構造体のフィールド ai_family, ai_socktype, ai_protocol で getaddrinfo() が返すソケットアドレス集合に対する基準を指定する。 ai_family このフィールドは返されるアドレスの希望のアドレスファミリーを指定する。 このフィール ドに指定できる有効な値としては AF_INET と AF_INET6 がある。 また、値 AF_UNSPEC を指 定すると、 getaddrinfo() は node と service で使用できるいずれかのアドレスファミ リー (例えば IPv4 か IPv6) の ソケットアドレスを返すことを求められる。 ai_socktype このフィールドは推奨のソケット型 (例えば SOCK_STREAM や SOCK_DGRAM) を指定する。 このフィールドに 0 を指定すると、任意のソケット型のソケットアドレスを getaddrinfo() が返してよいことを意味する。 ai_protocol このフィールドは返されるソケットアドレスのプロトコルを指定する。 このフィールドに 0 を指定すると、任意のプロトコルののソケットアドレスを getaddrinfo() が返してよいこ とを意味する。 ai_flags このフィールドは、追加のオプション (下記) を指定する。 複数のフラグを指定する際に は、それらのビット単位の OR をとって指定する。 hints が指し示す構造体の他のすべてのフィールドには 0 かヌルポインターを適切に入れなければ ならない。 hints に NULL を指定するのは、 ai_socktype と ai_protocol に 0 を、 ai_family に AF_UNSPEC を、 ai_flags に (AI_V4MAPPED | AI_ADDRCONFIG) を設定するのと等価である (POSIX では ai_flags には別のデフォルト値が規定されている; 「備考」を参照)。 node には、数値形式のネッ トワークアドレス (IPv4 の場合は inet_aton(3) でサポートされているドット区切りの数字による 表記、 IPv6 の場合は inet_pton(3) でサポートされている 16 進数の文字列形式) もしくは ネッ トワークホスト名を指定する。 ネットワークホスト名を指定した場合には、そのネットワークアド レスが検索され、 名前解決が行なわれる。 hints.ai_flags に AI_NUMERICHOST フラグが含まれて いる場合は、 node は数値形式のネットワークアドレスでなければならない。 AI_NUMERICHOST フラ グを使うと、時間の掛かる可能性のあるネットワークホストアドレスの検索は すべて抑制される。 hints.ai_flags に AI_PASSIVE フラグが指定され、かつ node が NULL の場合、 返されるソケット アドレスは コネクションを accept(2) するためのソケットを bind(2) するのに適したものとな る。 返されるソケットアドレスには「ワイルドカードアドレス」 (IPv4 アドレスの場合は INADDR_ANY、 IPv6 アドレスの場合は IN6ADDR_ANY_INIT) が入る。 ワイルドカードアドレス は、任意のホストのネットワークアドレスで接続を 受け付けようとするアプリケーション (通常は サーバー) で用いられる。 node が NULL でない場合、 AI_PASSIVE フラグは無視される。 hints.ai_flags に AI_PASSIVE フラグがセットされていない場合、 返されるソケットアドレスは connect(2), sendto(2), sendmsg(2) での使用に適したものとなる。 node が NULL の場合、ネッ トワークアドレスにはループバックインターフェイスの アドレス (IPv4 アドレスの場合は INADDR_LOOPBACK IPv6 アドレスの場合は IN6ADDR_LOOPBACK_INIT)が設定される。 これは同じホス ト上で動作している接続相手と通信するような アプリケーションで用いられる。 service により、返される各アドレス構造体のポート番号が決まる。 この引数がサービス名 (services(5) 参照) の場合、対応するポート番号に翻訳される。 この引数には 10 進数も指定す ることができ、 この場合にはバイナリへの変換だけが行われる。 service が NULL の場合、返され るソケットアドレスのポート番号は 初期化されないままとなる。 hints.ai_flags に AI_NUMERICSERV が指定され、かつ service が NULL でない場合、 service は数値のポート番号を 含む文字列を指し示さなければならない。 このフラグは、名前解決サービスが不要であることが分 かっている場合に、 サービスの起動を抑制するために用いられる。 node と service のどちらかは NULL にしてよいが、両方同時に NULL にしてはならない。 getaddrinfo() 関数は、 addrinfo 構造体のメモリー確保を行い、 addrinfo 構造体のリンクリス トを初期化し、 res にリストの先頭へのポインターを入れて返す。 このとき、各構造体のネット ワークアドレスは node と service に一致し、 hints で課されたすべての制限を満たすものとな る。 リンクリストの要素は ai_next フィールドにより連結される。 リンクリストの addrinfo 構造体は複数個になることもあり、その理由はいくつかある。 ネット ワークホストがマルチホームである、 複数のプロトコルでアクセスできる (例えば AF_INET と AF_INET6 の両方) 、 複数のソケット種別で同じサービスが利用できる (例えば、ひとつが SOCK_STREM アドレスで、もうひとつが SOCK_DGRAM アドレスである)、がある。 通常は、アプリ ケーションは返された順序でアドレスを試すべきである。 getaddrinfo() の中で使用される並べ替 え関数は RFC 3484 で定義されている。 特殊なシステムでは、 /etc/gai.conf を編集すること で、この順序を微調整することができる (/etc/gai.conf は glibc 2.5 以降で利用できる)。 hints.ai_flags に AI_CANONNAME フラグが含まれている場合、返されるリストの最初の addrinfo 構造体の ai_canonname フィールドはホストの公式な名前を指すように設定される。 返される各々の addrinfo 構造体の残りのフィールドは以下のように初期化される。 * ai_family, ai_socktype, ai_protocol フィールドはソケット生成パラメーターを返す (これらの フィールドの意味は socket(2) の同じ名前の引数と同じである)。 例えば、 ai_family は AF_INET や AF_INET6 を返し、 ai_socktype は SOCK_DGRAM や SOCK_STREAM を返し、 ai_protocol はそのソケットのプロトコルを返す。 * ai_addr フィールドにはソケットアドレスへのポインターが書き込まれ、 ai_addrlen フィールド にはソケットアドレスの長さがバイト単位で書き込まれる。 hints.ai_flags が AI_ADDRCONFIG を含む場合、 res が指すリストには、ローカルシステムに最低 一つの IPv4 アドレスが設定されている場合のみ IPv4 アドレスが返され、 ローカルシステムに最 低一つの IPv6 アドレスが設定されている場合にのみ IPv6 アドレスが返される。 なお、この場合 には、ループバックアドレスは有効に設定されたアドレスとはみなされない。 このフラグは、例え ば、IPv4 だけのシステムで、 getaddrinfo() が必ず IPv6 ソケットアドレスを返さないことを保証 するのに役立つ。 IPv4 だけのシステムでは、IPv6 アドレスは connect(2) や bind(2) で必ず失敗 することになる。 hints.ai_flags に AI_V4MAPPED が指定されていて、 hints.ai_family に AF_INET6 が指定され、 マッチする IPv6 アドレスが見つからなかった場合、 res が指すリストには IPv4-mapped IPv6 ア ドレスが返される。 hints.ai_flags に AI_V4MAPPED と AI_ALL の両方が指定されている場合、 res が指すリストには IPv6 アドレスと IPv4-mapped IPv6 アドレスの 両方が返される。 AI_V4MAPPED が指定されていない場合、 AI_ALL は無視される。 freeaddrinfo() 関数は、 リンクリスト res に対して動的に割り当てられたメモリーを解放する。 国際化ドメイン名のための getaddrinfo() の拡張 glibc 2.3.4 から、 getaddrinfo() は入出力するホスト名を透過的に国際化ドメイン名 (IDN) 形 式 (RFC 3490 の Internationalizing Domain Names in Applications (IDNA) を参照のこと) と変 換することを選択的に認めるように拡張されている。 4 つの新しいフラグが定義されている: AI_IDN このフラグが指定されると、 node で与えられたノード名は必要があれば IDN 形式に変換さ れる。 ソース符号化形式は現在のロケールのものである。 入力名に非 ASCII 文字が含まれている場合、 IDN 符号化形式が使われる。 非 ASCII 文字 が含まれている(ピリオドで区切られる)部分ノード名は、 名前解決機能に渡される前に ASCII 互換符号化形式 (ACE) を使って 符号化される。 AI_CANONIDN AI_CANONNAME が指定されている場合、 getaddrinfo() は名前の検索に成功した後、 返さ れた addrinfo 構造体に対応するノードの正規名を返す。 返り値は名前解決機能から返され た値の正確なコピーである。 AI_CANONIDN 名前が ACE で符号化されている場合、一つまたは複数の名前の構成要素の先頭 に xn-- を含んでいる。 これらの構成要素を読み込み可能な形に変換するために、 AI_CANONNAME と共に AI_CANONIDN フラグを渡すことも出来る。 返される文字列は現在のロ ケールの符号化形式で符号化されている。 AI_IDN_ALLOW_UNASSIGNED, AI_IDN_USE_STD3_ASCII_RULES これらのフラグをセットすると、IDNA 処理で使用されるフラグ IDNA_ALLOW_UNASSIGNED (未 割り当ての Unicode のコードポイントを許容) と IDNA_USE_STD3_ASCII_RULES (出力が STD3 準拠のホスト名かをチェックする) がそれぞれ有効になる。
返り値
getaddrinfo() は成功すると 0 を返し、失敗すると以下の非 0 のエラーコードのいずれかを返 す。 EAI_ADDRFAMILY 指定されたネットワークホストには、 要求されたアドレスファミリーのネットワークアドレ スがない。 EAI_AGAIN ネームサーバーから一時的な失敗 (temporary failure) を意味する返事が返された。後で もう一度試してみよ。 EAI_BADFLAGS hints.ai_flags のフラグに不正なフラグが含まれている。または、 hints.ai_flags に AI_CANONNAME が含まれていて、かつ name が NULL であった。 EAI_FAIL ネームサーバーから恒久的な失敗 (permanent failure) を意味する返事が返された。 EAI_FAMILY 要求されたアドレスファミリーがサポートされていない。 EAI_MEMORY メモリーが足りない。 EAI_NODATA 指定されたネットワークホストは存在するが、 ネットワークアドレスがひとつも定義されて いない。 EAI_NONAME node と service のどちらかが不明、または node と service の両方が NULL だった場 合、または AI_NUMERICSERV が hints.ai_flags に指定されていて、 hints.ai_flags と service が数値のポート番号の文字列でない。 EAI_SERVICE 要求されたサービスは、要求されたソケットタイプでは利用できない。 他のソケットタイプ でなら利用可能かもしれない。 このエラーが発生する例としては、 service が "shell" (ストリームソケットでのみ利用できるサービス) で、 hints.ai_protocol に IPPROTO_UDP が指定されたり、 hints.ai_socktype に SOCK_DGRAM が指定されたりした場合がある。 ま た、 service が NULL 以外で、 hints.ai_socktype に SOCK_RAW (サービスの考え方をサ ポートしていないソケット種別) が指定された場合にも、このエラーが発生する。 EAI_SOCKTYPE 要求されたソケットタイプがサポートされていない。 このエラーが発生する例としては、 hints.ai_socktype と hints.ai_protocol が矛盾している場合 (例えば hints.ai_socktype が SOCK_DGRAM で hints.ai_protocol が IPPROTO_TCP) がある。 EAI_SYSTEM その他のシステムエラー。詳しくは errno を調べること。 gai_strerror() 関数を用いると、これらのエラーコードを人間に可読な文字列に変換できるので、 エラー報告に適するだろう。
ファイル
/etc/gai.conf
属性
この節で使用されている用語の説明は attributes(7) を参照のこと。 ┌────────────────┬───────────────┬────────────────────┐ │Interface │ Attribute │ Value │ ├────────────────┼───────────────┼────────────────────┤ │getaddrinfo() │ Thread safety │ MT-Safe env locale │ ├────────────────┼───────────────┼────────────────────┤ │freeaddrinfo(), │ Thread safety │ MT-Safe │ │gai_strerror() │ │ │ └────────────────┴───────────────┴────────────────────┘
準拠
POSIX.1-2001, POSIX.1-2008. getaddrinfo() 関数は RFC 2553 に記載されている。
注意
getaddrinfo() は、IPv6 scope-ID を指定するために address%scope-id 記法をサポートしてい る。 AI_ADDRCONFIG, AI_ALL, AI_V4MAPPED は glibc 2.3.3 以降で利用可能である。 AI_NUMERICSERV は glibc 2.3.4 以降で利用可能である。 POSIX.1 によると、 hints に NULL が指定された場合、 ai_flags を 0 とみなすべきとされてい る。 GNU C ライブラリでは、この場合に、代わりに ai_flags を (AI_V4MAPPED | AI_ADDRCONFIG) とみなすようになっている。 この値の方が標準規格の改善になると考えられているからである。
例
以下のプログラムは、 getaddrinfo(), gai_strerror(), freeaddrinfo(), getnameinfo(3) の使い 方を示したものである。 プログラムは UDP データグラムの echo サーバとクライアントである。 サーバのプログラム #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <netdb.h> #define BUF_SIZE 500 int main(int argc, char *argv[]) { struct addrinfo hints; struct addrinfo *result, *rp; int sfd, s; struct sockaddr_storage peer_addr; socklen_t peer_addr_len; ssize_t nread; char buf[BUF_SIZE]; if (argc != 2) { fprintf(stderr, "Usage: %s port\n", argv[0]); exit(EXIT_FAILURE); } memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; s = getaddrinfo(NULL, argv[1], &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } /* getaddrinfo() returns a list of address structures. Try each address until we successfully bind(2). If socket(2) (or bind(2)) fails, we (close the socket and) try the next address. */ for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) break; /* Success */ close(sfd); } freeaddrinfo(result); /* No longer needed */ if (rp == NULL) { /* No address succeeded */ fprintf(stderr, "Could not bind\n"); exit(EXIT_FAILURE); } /* Read datagrams and echo them back to sender */ for (;;) { peer_addr_len = sizeof(peer_addr); nread = recvfrom(sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &peer_addr, &peer_addr_len); if (nread == -1) continue; /* Ignore failed request */ char host[NI_MAXHOST], service[NI_MAXSERV]; s = getnameinfo((struct sockaddr *) &peer_addr, peer_addr_len, host, NI_MAXHOST, service, NI_MAXSERV, NI_NUMERICSERV); if (s == 0) printf("Received %zd bytes from %s:%s\n", nread, host, service); else fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s)); if (sendto(sfd, buf, nread, 0, (struct sockaddr *) &peer_addr, peer_addr_len) != nread) fprintf(stderr, "Error sending response\n"); } } クライアントのプログラム #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #define BUF_SIZE 500 int main(int argc, char *argv[]) { struct addrinfo hints; struct addrinfo *result, *rp; int sfd, s; size_t len; ssize_t nread; char buf[BUF_SIZE]; if (argc < 3) { fprintf(stderr, "Usage: %s host port msg...\n", argv[0]); exit(EXIT_FAILURE); } /* Obtain address(es) matching host/port */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ s = getaddrinfo(argv[1], argv[2], &hints, &result); if (s != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); exit(EXIT_FAILURE); } /* getaddrinfo() returns a list of address structures. Try each address until we successfully connect(2). If socket(2) (or connect(2)) fails, we (close the socket and) try the next address. */ for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) continue; if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */ close(sfd); } freeaddrinfo(result); /* No longer needed */ if (rp == NULL) { /* No address succeeded */ fprintf(stderr, "Could not connect\n"); exit(EXIT_FAILURE); } /* Send remaining command-line arguments as separate datagrams, and read responses from server */ for (int j = 3; j < argc; j++) { len = strlen(argv[j]) + 1; /* +1 for terminating null byte */ if (len > BUF_SIZE) { fprintf(stderr, "Ignoring long message in argument %d\n", j); continue; } if (write(sfd, argv[j], len) != len) { fprintf(stderr, "partial/failed write\n"); exit(EXIT_FAILURE); } nread = read(sfd, buf, BUF_SIZE); if (nread == -1) { perror("read"); exit(EXIT_FAILURE); } printf("Received %zd bytes: %s\n", nread, buf); } exit(EXIT_SUCCESS); }
関連項目
getaddrinfo_a(3), gethostbyname(3), getnameinfo(3), inet(3), gai.conf(5), hostname(7), ip(7)
この文書について
この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの 説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。