other versions
| GETADDRINFO(3) | Linux Programmer's Manual | GETADDRINFO(3) | 
名前¶
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) 参照):
_POSIX_C_SOURCE >= 1 ||
  _XOPEN_SOURCE || _POSIX_SOURCE
説明¶
getaddrinfo() は、(インターネットのホストとサービスを識別する) node と service を渡すと、一つ以上の addrinfo 構造体を返す。それぞれの addrinfo 構造体には、 bind(2) や connect(2) を呼び出す際に指定できるインターネットアドレスが格納されている。 getaddrinfo() 関数は、 getservbyname(3) と getservbyport(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 をとって指定する。
 
- *
 - 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 フィールドにはソケットアドレスの長さがバイト単位で書き込まれる。
 
国際化ドメイン名のための 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 を調べること。
 
ファイル¶
/etc/gai.conf準拠¶
POSIX.1-2001. getaddrinfo() 関数は RFC 2553 に記載されている。注意¶
getaddrinfo() は、IPv6 scope-ID を指定するために address %scope-id 記法をサポートしている。例¶
以下のプログラムは、 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), hostname(7), ip(7)この文書について¶
この man ページは Linux man-pages プロジェクトのリリース 3.41 の一部 である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。| 2012-04-29 | GNU |