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