Provided by: manpages-ja-dev_0.5.0.0.20131015+dfsg-2_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():
           _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_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 か NULL ポインタを適切に入れなければならない。 hints
       に  NULL  を指定するのは、  ai_socktypeai_protocol に 0 を、 ai_familyAF_UNSPEC を、 ai_flags(AI_V4MAPPED | AI_ADDRCONFIG) を設定するのと等価である。

       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 アドレスが返される。なお、この場合には、 ループバックアドレスは有効に設定された
       アドレスとはみなされない。

       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

準拠

       POSIX.1-2001.  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-2001 によると、 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(struct addrinfo));
           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);
           }

           if (rp == NULL) {               /* No address succeeded */
               fprintf(stderr, "Could not bind\n");
               exit(EXIT_FAILURE);
           }

           freeaddrinfo(result);           /* No longer needed */

           /* Read datagrams and echo them back to sender */

           for (;;) {
               peer_addr_len = sizeof(struct sockaddr_storage);
               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 %ld bytes from %s:%s\n",
                           (long) 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, j;
           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(struct addrinfo));
           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);
           }

           if (rp == NULL) {               /* No address succeeded */
               fprintf(stderr, "Could not connect\n");
               exit(EXIT_FAILURE);
           }

           freeaddrinfo(result);           /* No longer needed */

           /* Send remaining command-line arguments as separate
              datagrams, and read responses from server */

           for (j = 3; j < argc; j++) {
               len = strlen(argv[j]) + 1;
                       /* +1 for terminating null byte */

               if (len + 1 > 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 %ld bytes: %s\n", (long) 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 プロジェクトのリリース 3.54 の一部 である。プロジェクトの説明とバグ報告
       に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。