getaddrinfo()

Получить информацию об адресе сокета

Прототип:

#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo( const char *nodename,
const char *servname,
const struct addrinfo *hints,
struct addrinfo **res );

Аргументы:

nodename
Имя узла. Значение, не равное NULL может быть либо именем узла либо строкой, содержащей числовой адрес хоста (т.е. разделенный точками IPv4 адрес или шестнадцатеричный IPv6 адрес.)
servname
Имя сервера. Значение, не равное NULL может быть либо именем сервера либо десятичным номером порта.
hints
Указатель на struct addrinfo, предоставляющую вспомогательную информацию о типе поддерживаемого сокета.
res
Адрес области памяти, где функция может хранить указатель на связанный список из одного или нескольких struct addrinfo.

Библиотека:

libsocket

Описание:

Функция getaddrinfo() представляет собой комбинацию gethostbyname() и getservbyname(), но в более усложненном исполнении.

Аргументы nodename и servname могут быть либо указателями на нуль-терминированные строки либо NULL. Один или оба этих аргумента должны быть не NULL. Обычно, со стороны клиента предоставляются и nodename и servname.

В случае успешного завершения, функция getaddrinfo() сохраняет в области памяти res указатель на связанный список из одной или нескольких struct addrinfo. Можно обрабатывать каждую struct addrinfo в списке при помощи указателя ai_next до достижения NULL указателя. Каждая struct addrinfo содержит соответствующие аргументы ai_family, ai_socktype, и ai_protocol для вызова функции socket(). Аргумент ai_addr в struct addrinfo указывает на заполненную структуру адреса сокета, размер которой указан в ai_addrlen.


Note: На случай, если сервер имен не отвечает, предусмотрен таймаут для каждого сервера имен, составляющий 1,5 минуты.

Использование аргумента hints

Опционально, можно передать struct addrinfo, на которую указывает аргумент hints, предоставляющую вспомогательную информацию по типу сокета, который поддерживает пользовательское приложение.

В данной структуре, все поля, кроме ai_flags, ai_family, ai_socktype, и ai_protocol — должны быть нулями либо NULL указателями. struct addrinfo из аргумента hints может обрабатывать несколько типов сокетов:

Обработать: Установить: В:
Любое семейство протоколов ai_family PF_UNSPEC
Любой тип сокета ai_socktype 0
Любой протокол ai_protocol 0
Все вышеуказанное (в т.ч. установка ai_flags в 0) hints NULL

Аргумент hints по умолчанию принимает все возможные варианты, но также воможно использовать его для ограниченного выбора:

Использование аргумента ai_flags в структуре hints

Можно установить аргумент ai_flags для последующей настройки структуры hints. Настройки для ai_flags включают в себя:

AI_PASSIVE Установите данный бит, если планируется использование возвращенной struct addrinfo из вызова bind(). В этом вызове, если аргумент nodename - NULL указатель, то часть IP адреса из структуры адреса сокета ai_addr устанавливается в INADDR_ANY для IPv4 адреса или IN6ADDR_ANY_INIT для IPv6 адреса. Если не устанавливать флаг AI_PASSIVE, то возможно использование возвращеннной struct addrinfo для вызовов: В данном случае, если аргумент nodename является NULL указателем, то часть IP адреса из структуры адреса сокета ai_addr устанавливается значением адреса обратной связи.
AI_CANONNAME Установите данный бит, если требуется, чтобы аргумент ai_canonname первой struct addrinfo указывал на нуль-терминированную строку, содержащую каноническое имя указанного nodename.
AI_NUMERICHOST Установите данный бит, если необходимо предотвратить любое разрешение имен (например, DNS). Непустая строка nodename должна представлять собой строку с числовым адресом хоста; в противном случае, getaddrinfo() вернет EAI_NONAME.

Возможные проблемы

Аргументы getaddrinfo() должны быть последовательны и однозначны, иначе данная функция вернет ошибку. Вот некоторые проблемы, с которыми можно столкнуться:


Note: Функция getaddrinfo() динамически выделяет память для следующей информации:
  • структуры addrinfo
  • структуры адресов сокетов
  • канонические строки имен узлов, на которые указывают структуры addrinfo.

Используйте freeaddrinfo() чтобы освободить память, выделенную под структуры addrinfo, и gai_strerror() чтобы расшифровать коды ошибок.


Возвращаемое значение:

0
Успешное завершение.
≠0
Возникла ошибка.

Коды ошибок:

Чтобы получить развернутое описание кода ошибки, используйте gai_strerror().

Примеры:

Следующий код пытается подключиться к сервису HTTP «www.kame.net» с помощью потокового сокета. Он перебирает все доступные адреса независимо от их семейства. Если узел назначения разрешается как адрес IPv4, то он использует сокет AF_INET. Точно так же он использует сокет AF_INET6, если он разрешается как IPv6. Обратите внимание, что здесь нет жестко запрограммированных ссылок на какое-либо конкретное семейство адресов; код работает, даже если getaddrinfo() возвращает адреса, не являющиеся IPv4/v6.

struct addrinfo hints, *res, *res0;
int error, s;
const char *cause = NULL;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo( "www.kame.net", "http", &hints, &res0 );
if ( error )
{
err1( 1, "%s", gai_strerror( error ) );
/*NOTREACHED*/
}
s = -1;
for ( res = res0; res; res = res->ai_next )
{
s = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
if ( s < 0 )
{
cause = "socket";
continue;
}
if ( connect( s, res->ai_addr, res->ai_addrlen ) < 0 )
{
cause = "connect";
close( s );
s = -1;
continue;
}
break; /* okay we got one */
}
if ( s < 0 )
{
err( 1, cause );
/*NOTREACHED*/
}
freeaddrinfo( res0 );

В следующем примере предпринимается попытка открыть сокет, ожидающий специальный символ, в службе HTTP для всех доступных семейств адресов:

struct addrinfo hints, *res, *res0;
int error, s[MAXSOCK], nsock;
const char *cause = NULL;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
error = getaddrinfo( NULL, "http", &hints, &res0 );
if ( error )
{
err1( 1, "%s", gai_strerror( error ) );
/*NOTREACHED*/
}
nsock = 0;
for ( res = res0; res && nsock < MAXSOCK; res = res->ai_next )
{
s[nsock] = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
if ( s[nsock] < 0 )
{
cause = "socket";
continue;
}
if ( connect( s[nsock], res->ai_addr, res->ai_addrlen ) < 0 )
{
cause = "connect";
close( s[nsock] );
continue;
}
nsock++;
}
if ( nsock == 0 )
{
err( 1, cause );
/*NOTREACHED*/
}
freeaddrinfo( res0 );

Файлы:

/etc/nsswitch.conf
Конфигурационный файл для выбора соответствующей службы имен

Классификация:

POSIX 1003.1

Точка остановки потока
Да
Обработчик прерываний
Нет
Обработчик сигналов
Нет
В потоке
Нет

Тематические ссылки:

struct addrinfo, freeaddrinfo(), gai_strerror()

/etc/nsswitch.conf в Справочнике по Утилитам




Предыдущий раздел: Описание API сетевой библиотеки