146: printf("\tname%s", addr->ai_canonname);
147:
148: printf("\n");
149:
150: addr = addr->ai_next;
151: }
152:
153: /* очистить результаты getaddrinfo() */
154: freeaddrinfo(result);
155:
156: return 0;
157: }
В отличие от большинства библиотечных функций, getaddrinfo() возвращает целое число, которое равно нулю в случае успеха, и описывает ошибку в случае неудачи. Такие функции, как правило, не используют errno. В табл. 17.3 описаны различные коды ошибок, которые могут возвращать подобные функции.
Таблица 17.3. Ошибки поиска соответствия адреса и имени
| Ошибка | Описание |
|---|---|
EAI_AGAIN |
Имя не может быть найдено. Повторный поиск может оказаться успешным. |
EAI_BADFLAGS |
В функцию переданы недействительные флаги. |
EAI_FAIL |
В процессе поиска соответствия возникла постоянная ошибка. |
EAI_FAMILY |
Семейство адресов не распознано. |
EAI_MEMORY |
Запрос на выделение памяти не выполнен. |
EAI_NONAME |
Имя или адрес невозможно преобразовать. |
EAI_OVERFLOW |
Переданный буфер слишком мал. |
EAI_SERVICE |
Для данного типа сокета служба не существует. |
EAI_SOCKTYPE |
Был передан недействительный тип сокета. |
EAI_SYSTEM |
Произошла системная ошибка; сама ошибка содержится в переменной errno. |
Коды ошибок можно преобразовать в строки, описывающие проблему, с помощью функции gai_strerror().
#include <netdb.h>
const char * gai_strerror(int error);
Здесь параметр error должен быть ненулевым значением, возвращенным функцией getaddrinfo(). Если произошла ошибка EAI_SYSTEM, то для получения более точного описания программа должна использовать strerror(errno).
17.5.6. Преобразование адресов в имена
К счастью, переводить IP-адреса и номера портов в имена хостов и служб гораздо проще, чем наоборот.
#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(struct sockaddr * addr, socklen_t addrlen,
char * hostname, size_t hostlen,
char * servicename, size_tservicelen, intflags);
Здесь параметр addr указывает либо на struct sockaddr_in, либо на struct sockaddr_in6, член addrlen содержит размер структуры, на которую указывает addr. IP-адрес и номер порта, определенные addr, преобразуются в имя хоста, сохраняющееся в ячейке, на которую указывает hostname, и в имя службы, сохраняющееся в servicename.
Один из параметров может равняться NULL, при этом функция getnameinfo() не ищет соответствие имени для данного параметра.
Параметры hostlen и servicelen определяют, сколько байт доступно в буферах, на которые указывают hostname и servicename соответственно. Если ни одно имя не умещается в доступном пространстве, буфера переполняются и возвращается ошибка (EAI_OVERFLOW).
Последний аргумент flags изменяет способ, которым функция getnameinfo() производит поиск имен. Параметр должен быть равен нулю или принимать одно или несколько (объединенных логическим "ИЛИ") из описанных ниже значений.
NI_DGRAM |
Отыскивается имя службы UDP для указанного порта (вместо имени службы TCP). Примечание. Эти два имени почти всегда идентичны, однако существует несколько портов, определенных только для UDP-портов (протокол прерывания SNMP — один из них), и несколько случаев, когда один и тот же номер порта используется для различных TCP и UDP служб (например, порт 512 применяется и для TCP-службы exec, и для UDP-службы biff). |
NI_NAMEREQD |
Если преобразование IP-адреса в имя хоста завершается неудачей и установлен данный флаг, то функция getnameinfo() возвращает ошибку. В противном случае она возвращает IP-адрес в формате с разделительными точками или двоеточиями. |
NI_NOFQDN |
Имена хостов обычно возвращаются как полностью уточненные имена доменов. Это означает, что возвращается полное имя хоста, а не локальное сокращение. Если, к примеру, установлен данный флаг, вашим хостом является digit.iana.org, и вы ищете IP-адрес, соответствующий www.iana.org, тогда будет возвращено имя хоста www. Поиск имен хостов для остальных машин при этом не затрагивается (в предыдущем примере поиск адреса для www.ietf.org предоставит полное имя хоста www.ietf.org. |
NI_NUMERICHOST |
Вместо выполнения поиска имен хостов функция getnameinfo() преобразует IP-адрес в IP-адрес по аналогии с inet_ntop(). |
NI_NUMERICSERV |
Номер порта размещается в servicename в виде форматированной числовой строки (а не преобразуется в имя службы). |
Возвращаемые коды для getnameinfo() — те же самые, что и для gethostinfо(); в случае успеха возвращается нуль, в случае неудачи — код ошибки. Полный перечень возможных ошибок приведен в табл. 17.3. Для преобразования этих ошибок в описательные строки служит функция gai_strerror().
Ниже приведен пример, показывающий использование getnameinfo() для выполнения обратного поиска имени для адресов IPv4 и IPv6.
$ ./reverselookup --host ::1