Provided by: manpages-ja-dev_0.5.0.0.20221215+dfsg-1_all bug

名前

       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()   は、(インターネットのホストとサービスを識別する)   nodeservice を渡す
       と、一つ以上の  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 でない場合、 hintsaddrinfo 構造体を指し示し、その構造体のフィールド ai_family, ai_socktype,  ai_protocolgetaddrinfo()  が返すソケットアドレス集合に対する基準を指定する。

       ai_family
              このフィールドは返されるアドレスの希望のアドレスファミリーを指定する。 このフィール
              ドに指定できる有効な値としては AF_INETAF_INET6 がある。 また、値 AF_UNSPEC を指
              定すると、  getaddrinfo()   は nodeservice で使用できるいずれかのアドレスファミ
              リー (例えば IPv4 か IPv6) の ソケットアドレスを返すことを求められる。

       ai_socktype
              このフィールドは推奨のソケット型 (例えば SOCK_STREAMSOCK_DGRAM)   を指定する。
              このフィールドに 0 を指定すると、任意のソケット型のソケットアドレスを getaddrinfo()
              が返してよいことを意味する。

       ai_protocol
              このフィールドは返されるソケットアドレスのプロトコルを指定する。 このフィールドに 0
              を指定すると、任意のプロトコルののソケットアドレスを  getaddrinfo()  が返してよいこ
              とを意味する。

       ai_flags
              このフィールドは、追加のオプション (下記)  を指定する。  複数のフラグを指定する際に
              は、それらのビット単位の OR をとって指定する。

       hints  が指し示す構造体の他のすべてのフィールドには 0 かヌルポインターを適切に入れなければ
       ならない。

       hints に NULL を指定するのは、 ai_socktypeai_protocol に 0 を、 ai_familyAF_UNSPEC
       を、   ai_flags(AI_V4MAPPED | AI_ADDRCONFIG)  を設定するのと等価である  (POSIX  では
       ai_flags には別のデフォルト値が規定されている; 「備考」を参照)。 node には、数値形式のネッ
       トワークアドレス (IPv4 の場合は inet_aton(3)  でサポートされているドット区切りの数字による
       表記、 IPv6 の場合は inet_pton(3)  でサポートされている 16 進数の文字列形式) もしくは ネッ
       トワークホスト名を指定する。  ネットワークホスト名を指定した場合には、そのネットワークアド
       レスが検索され、 名前解決が行なわれる。 hints.ai_flagsAI_NUMERICHOST  フラグが含まれて
       いる場合は、 node は数値形式のネットワークアドレスでなければならない。 AI_NUMERICHOST フラ
       グを使うと、時間の掛かる可能性のあるネットワークホストアドレスの検索は すべて抑制される。

       hints.ai_flagsAI_PASSIVE フラグが指定され、かつ node が NULL の場合、 返されるソケット
       アドレスは  コネクションを accept(2)  するためのソケットを bind(2)  するのに適したものとな
       る。   返されるソケットアドレスには「ワイルドカードアドレス」    (IPv4    アドレスの場合は
       INADDR_ANY、  IPv6  アドレスの場合は  IN6ADDR_ANY_INIT)   が入る。  ワイルドカードアドレス
       は、任意のホストのネットワークアドレスで接続を 受け付けようとするアプリケーション  (通常は
       サーバー) で用いられる。 node が NULL でない場合、 AI_PASSIVE フラグは無視される。

       hints.ai_flagsAI_PASSIVE フラグがセットされていない場合、 返されるソケットアドレスは
       connect(2), sendto(2), sendmsg(2)  での使用に適したものとなる。 node が NULL  の場合、ネッ
       トワークアドレスにはループバックインターフェイスの    アドレス    (IPv4   アドレスの場合は
       INADDR_LOOPBACK IPv6 アドレスの場合は IN6ADDR_LOOPBACK_INIT)が設定される。  これは同じホス
       ト上で動作している接続相手と通信するような アプリケーションで用いられる。

       service     により、返される各アドレス構造体のポート番号が決まる。    この引数がサービス名
       (services(5)  参照) の場合、対応するポート番号に翻訳される。 この引数には 10  進数も指定す
       ることができ、 この場合にはバイナリへの変換だけが行われる。 service が NULL の場合、返され
       るソケットアドレスのポート番号は     初期化されないままとなる。     hints.ai_flagsAI_NUMERICSERV  が指定され、かつ service が NULL でない場合、 service は数値のポート番号を
       含む文字列を指し示さなければならない。  このフラグは、名前解決サービスが不要であることが分
       かっている場合に、 サービスの起動を抑制するために用いられる。

       nodeservice のどちらかは NULL にしてよいが、両方同時に NULL にしてはならない。

       getaddrinfo()   関数は、 addrinfo 構造体のメモリー確保を行い、 addrinfo 構造体のリンクリス
       トを初期化し、 res  にリストの先頭へのポインターを入れて返す。  このとき、各構造体のネット
       ワークアドレスは  nodeservice に一致し、 hints で課されたすべての制限を満たすものとな
       る。 リンクリストの要素は ai_next フィールドにより連結される。

       リンクリストの  addrinfo  構造体は複数個になることもあり、その理由はいくつかある。  ネット
       ワークホストがマルチホームである、  複数のプロトコルでアクセスできる  (例えば  AF_INETAF_INET6   の両方)   、   複数のソケット種別で同じサービスが利用できる   (例えば、ひとつが
       SOCK_STREM  アドレスで、もうひとつが  SOCK_DGRAM  アドレスである)、がある。 通常は、アプリ
       ケーションは返された順序でアドレスを試すべきである。 getaddrinfo()  の中で使用される並べ替
       え関数は  RFC 3484  で定義されている。  特殊なシステムでは、  /etc/gai.conf を編集すること
       で、この順序を微調整することができる (/etc/gai.conf は glibc 2.5 以降で利用できる)。

       hints.ai_flagsAI_CANONNAME  フラグが含まれている場合、返されるリストの最初の  addrinfo
       構造体の ai_canonname フィールドはホストの公式な名前を指すように設定される。

       返される各々の addrinfo 構造体の残りのフィールドは以下のように初期化される。

       * ai_family, ai_socktype, ai_protocol フィールドはソケット生成パラメーターを返す (これらの
         フィールドの意味は  socket(2)   の同じ名前の引数と同じである)。  例えば、  ai_familyAF_INETAF_INET6  を返し、  ai_socktypeSOCK_DGRAMSOCK_STREAM  を返し、
         ai_protocol はそのソケットのプロトコルを返す。

       * ai_addr フィールドにはソケットアドレスへのポインターが書き込まれ、 ai_addrlen フィールド
         にはソケットアドレスの長さがバイト単位で書き込まれる。

       hints.ai_flagsAI_ADDRCONFIG を含む場合、 res が指すリストには、ローカルシステムに最低
       一つの IPv4 アドレスが設定されている場合のみ IPv4 アドレスが返され、  ローカルシステムに最
       低一つの  IPv6 アドレスが設定されている場合にのみ IPv6 アドレスが返される。 なお、この場合
       には、ループバックアドレスは有効に設定されたアドレスとはみなされない。  このフラグは、例え
       ば、IPv4 だけのシステムで、 getaddrinfo() が必ず IPv6 ソケットアドレスを返さないことを保証
       するのに役立つ。 IPv4 だけのシステムでは、IPv6 アドレスは connect(2) や bind(2) で必ず失敗
       することになる。

       hints.ai_flagsAI_V4MAPPED が指定されていて、 hints.ai_familyAF_INET6 が指定され、
       マッチする IPv6 アドレスが見つからなかった場合、 res が指すリストには IPv4-mapped IPv6  ア
       ドレスが返される。  hints.ai_flagsAI_V4MAPPEDAI_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_flagsAI_CANONNAME が含まれていて、かつ name が NULL であった。

       EAI_FAIL
              ネームサーバーから恒久的な失敗 (permanent failure)  を意味する返事が返された。

       EAI_FAMILY
              要求されたアドレスファミリーがサポートされていない。

       EAI_MEMORY
              メモリーが足りない。

       EAI_NODATA
              指定されたネットワークホストは存在するが、 ネットワークアドレスがひとつも定義されて
              いない。

       EAI_NONAME
              nodeservice のどちらかが不明、または nodeservice  の両方が  NULL  だった場
              合、または  AI_NUMERICSERVhints.ai_flags に指定されていて、 hints.ai_flagsservice が数値のポート番号の文字列でない。

       EAI_SERVICE
              要求されたサービスは、要求されたソケットタイプでは利用できない。 他のソケットタイプ
              でなら利用可能かもしれない。  このエラーが発生する例としては、  service  が "shell"
              (ストリームソケットでのみ利用できるサービス) で、 hints.ai_protocolIPPROTO_UDP
              が指定されたり、  hints.ai_socktypeSOCK_DGRAM が指定されたりした場合がある。 ま
              た、 service が NULL 以外で、 hints.ai_socktypeSOCK_RAW  (サービスの考え方をサ
              ポートしていないソケット種別)  が指定された場合にも、このエラーが発生する。

       EAI_SOCKTYPE
              要求されたソケットタイプがサポートされていない。   このエラーが発生する例としては、
              hints.ai_socktypehints.ai_protocol が矛盾している場合 (例えば hints.ai_socktypeSOCK_DGRAMhints.ai_protocolIPPROTO_TCP)  がある。

       EAI_SYSTEM
              その他のシステムエラー。詳しくは errno を調べること。

       gai_strerror()  関数を用いると、これらのエラーコードを人間に可読な文字列に変換できるので、
       エラー報告に適するだろう。

ファイル

       /etc/gai.conf

属性

       この節で使用されている用語の説明は attributes(7) を参照のこと。

       ┌────────────────┬───────────────┬────────────────────┐
       │InterfaceAttributeValue              │
       ├────────────────┼───────────────┼────────────────────┤
       │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/ に書かれている。