GETNAMEINFO(3)

ИМЯ
getnameinfo - перевод адреса в имя не зависящим от протокола способом

ОБЗОР
#include <sys/socket.h>
#include <netdb.h>

int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
                char *host, socklen_t hostlen,
                char *serv, socklen_t servlen, int flags);

Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):

getnameinfo():
    начиная с glibc 2.22: _POSIX_C_SOURCE >= 201112L
    в glibc 2.21 и старее: _POSIX_C_SOURCE

ОПИСАНИЕ
Функция getnameinfo() выполняет операцию, обратную getaddrinfo(3); она преобразует адрес сокета в соответствующие узел и службу, способом, который не зависит от протокола. Она сочетает в себе действия функций gethostbyaddr(3) и getservbyport(3), но в отличии от этих функций getnameinfo() реентерабельна и позволяет программам не зависеть от типа IPv4 и IPv6.

Аргумент addr — это указатель на обобщённую структуру адреса сокета (типа sockaddr_in или sockaddr_in6) размером addrlen, которая содержит IP-адрес и номер порта. Аргументы host и serv указывают на выделенные вызывающим буферы (размером hostlen и servlen, соответственно), в которые getnameinfo() помещает строки (заканчивающееся null), содержащие имя узла и службы, соответственно.

Вызывающий может указать, что имя узла (или службы) не требуется, указав в аргументе host (или serv) NULL или в hostlen (или servlen) значение 0. Однако, по крайней мере один параметр, имя узла или службы, должно быть запрошено.

Аргумент flags меняет поведение функции getnameinfo() следующим образом:

NI_NAMEREQD
    Если этот флаг установлен, то возвращается ошибка, если имя машины не может быть определено.

NI_DGRAM
    Если этот флаг установлен, то сначала используется имя службы на основе дейтаграмм (UDP), а не потоков (TCP). Это требуется для немногих портов (512–514), которые имеют различные службы для UDP и TCP.

NI_NOFQDN
    Если этот флаг установлен, то возвращается только часть имени машины от полностью определённого доменного имени (FQDN) для локальных машин.

NI_NUMERICHOST
    Если этот флаг установлен, то имя узла возвращается в числовой форме (если этот флаг не установлен, то это также произойдёт в случае, когда имя узла невозможно определить).

NI_NUMERICSERV
    Если этот флаг установлен, тогда имя службы возвращается в числовой форме (если этот флаг не установлен, то это также произойдёт в случае, когда имя узла невозможно определить).

  Расширения getnameinfo() для интернациональных доменных имён

Начиная с glibc 2.3.4, getnameinfo() была расширена для выборочного прозрачного разрешения имён для формата интернациональных доменных имён (IDN) (смотрите RFC 3490, Internationalizing Domain Names in Applications (IDNA)). Было определено четыре новых флага:

NI_IDN
    Если этот флаг установлен, то при необходимости искомое имя преобразуется из формата IDN в кодировку локали. Имена из только ASCI-символов не меняются при преобразовании, из-за чего данный флаг можно использовать в существующих программах и средах.

NI_IDN_ALLOW_UNASSIGNED, NI_IDN_USE_STD3_ASCII_RULES
    Установка этих флагов включает IDNA_ALLOW_UNASSIGNED (разрешать не назначенные кодовые точки Юникода) и IDNA_USE_STD3_ASCII_RULES (проверять вывод на соответствие имени узла STD3) соответственно для возможности работы с IDNA.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении возвращается 0, а строки (оканчивающееся null) имени узла и службы (если запрашивались) записываются в соответствующий буфер заданной длины. При ошибке возвращается одно из следующих ненулевых значений ошибки:

EAI_AGAIN
    Имя не может быть определено в настоящий момент. Попробуйте повторить попытку позже.

EAI_BADFLAGS
    Параметр flags имеет неверное значение.

EAI_FAIL
    Произошла неисправимая ошибка.

EAI_FAMILY
    Не распознано семейство адресов, или для данного семейства была указана неверно длина адреса.

EAI_MEMORY
    Не хватает памяти.

EAI_NONAME
    Имя не может быть определено для указанных параметров. Установлен флаг NI_NAMEREQD и имя машины не может быть определено, или не было запрошено не имя машины и не имя службы.

EAI_OVERFLOW
    Размер буфера, на который указывает host или serv слишком мал.

EAI_SYSTEM
    Произошла системная ошибка. Код системной ошибки можно найти в переменной errno.

Функция gai_strerror(3) транслирует эти коды ошибок в читаемый формат, подходящий для сообщений об ошибке.

ФАЙЛЫ
/etc/hosts
/etc/nsswitch.conf
/etc/resolv.conf

ВЕРСИИ
Функция getnameinfo() появилась в glibc начиная с версии 2.1.

АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение
getnameinfo() | Безвредность в нитях | MT-Safe env locale

СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, RFC 2553.

ЗАМЕЧАНИЯ
Чтобы помочь программисту выбрать нужный размер буферов в <netdb.h> определены константы

    #define NI_MAXHOST      1025
    #define NI_MAXSERV      32

Начиная с glibc 2.8, эти определения доступны только, если определён подходящий макрос тестирования свойств: _GNU_SOURCE, _DEFAULT_SOURCE (начиная с glibc 2.19) или (в версиях glibc с 2.19 включительно) _BSD_SOURCE или _SVID_SOURCE.

Первая — это константа MAXDNAME из новых версий заголовочного файла <arpa/nameser.h> BIND. Последняя — вычислена на основе служб, перечисленных в текущем RFC «Assigned Numbers».

В glibc до версии 2.2 аргументы hostlen и servlen имели тип size_t.

ПРИМЕР
Следующий код пытается получить имя машины и службы в числовой форме для указанного адреса сокета. Обратите внимание, что здесь нет прямых упоминаний определённого семейства адресов.

    struct sockaddr *addr;     /* входные */
    socklen_t addrlen;         /* входные */
    char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
    if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), sbuf,
                sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0)
        printf("host=%s, serv=%s\n", hbuf, sbuf);

Следующая версия проверяет, имеет ли адрес сокета обратное отображение адреса.

    struct sockaddr *addr;     /* входные */
    socklen_t addrlen;         /* входные */
    char hbuf[NI_MAXHOST];
    if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf),
                NULL, 0, NI_NAMEREQD))
        printf("не удалось определить имя узла");
    else
        printf("host=%s\n", hbuf);

Пример программы, использующей getnameinfo(), можно найти в getaddrinfo(3).

СМОТРИТЕ ТАКЖЕ
accept(2), getpeername(2), getsockname(2), recvfrom(2), socket(2), getaddrinfo(3), gethostbyaddr(3), getservbyname(3), getservbyport(3), inet_ntop(3), hosts(5), services(5), hostname(7), named(8)

R. Gilligan, S. Thomson, J. Bound and W. Stevens, Basic Socket Interface Extensions for IPv6, RFC 2553, March 1999.

Tatsuya Jinmei and Atsushi Onoe, An Extension of Format for IPv6 Scoped Addresses, черновик ftp://ftp.ietf.org/internet-drafts/draft-ietf-ipngwg-scopedaddr-format-02.txt.

Craig Metz, Protocol Independence Using the Sockets API, Продолжение темы freenix: 2000 USENIX ежегодной технической конференции, июнь 2000 http://www.usenix.org/publications/library/proceedings/usenix2000/freenix/metzprotocol.html.