UNIX: разработка сетевых приложений
11.8. Функция freeaddrinfo
Вся память, занимаемая структурами
, структурамиaddrinfoи строкойai_addr, которые возвращаются функциейai_canonname, динамически выделяется функциейgetaddrinfo. Эта память освобождается при вызове функцииmalloc.freeaddrinfo#include <netdb.h>void freeaddrinfo(struct addrinfo *<i>ai</i>);Переменная
должна указывать на первую из структурai, возвращаемых функциейaddrinfo. Освобождается вся область памяти, занятая структурами из связного списка, вместе с динамически выделенной областью памяти, содержащей данные, на которые указывают эти структуры (например, структуры адресов сокетов и канонические имена узлов).getaddrinfoПредположим, что мы вызываем функцию
, проходим последовательно по всему связному списку структурgetaddrinfoи находим нужную структуру. Если далее мы попытаемся сохранить нужную нам информацию простым копированием структурыaddrinfo, а затем вызовем функциюaddrinfo, мы получим скрытую ошибку. Причина в том, что структураfreeaddrinfoсама указывает на динамически выделенный участок памяти (для структуры адреса сокета и, возможно, для канонического имени). Но эта область памяти, на которую указывает сохраненная нами структура, при вызове функцииaddrinfoосвобождается и может использоваться для хранения какой-либо иной информации.freeaddrinfoПРИМЕЧАНИЕСоздание копии только самой структуры addrinfo, а не структур, на которые она, в свою очередь, указывает, называется поверхностным копированием (shallow сору). Копирование структуры addrinfo и всех структур, на которые она указывает, называется детальным копированием (deep сору).
11.9. Функция getaddrinfo: IPv6
Стандарт POSIX определяет как
, так и возвращаемые этой функцией данные для протоколов IPv4 и IPv6. Отметим следующие моменты, прежде чем свести возвращаемые значения воедино в табл. 11.3.getaddrinfo■ Входные данные функции
могут относиться к двум различным типам, которые выбираются в зависимости от того, какой тип структуры адреса сокета вызывающий процесс хочет получить обратно и какой тип записей нужно искать в DNS или иной базе данных.getaddrinfo■ Семейством адресов, указанным вызывающим процессом в структуре
, задается тип структуры адреса сокета, который вызывающий процесс предполагает получить. Если вызывающий процесс задаетhints, функция не должна возвращать структурыAF_INET, а дляsockaddr_in6функция не должна возвращать структурAF_INET6.sockaddr_in■ POSIX утверждает, что при задании семейства
должны возвращаться адреса, которые могут использоваться с любым семейством протоколов, допускающим применение имени узла и имени службы. Это подразумевает, что если у узла имеются как записи типа AAAA, так и записи типа А, то записи типа AAAA возвращаются как структурыAF_UNSPEC, а записи типа A — как структурыsockaddr_in6. Нет смысла возвращать еще и записи типа А как адреса IPv4, преобразованные к виду IPv6, в структурахsockaddr_in, потому что при этом не возвращается никакой дополнительной информации — эти адреса уже возвращены в структурахsockaddr_in6.sockaddr_in■ Это утверждение POSIX также подразумевает, что если флаг
задан без имени узла, то должен быть возвращен универсальный адрес IPv6 (AI_PASSIVEили 0::0) в структуреIN6ADDR_ANY_INITвместе с универсальным адресом IPv4 (sockaddr_in6или 0.0.0.0) в структуреINADDR_ANY. Также нет смысла возвращать сначала универсальный адрес IPv4, поскольку мы увидим в разделе 12.2, что на узле с двойным стеком сокет сервера IPv6 может обрабатывать и клиенты IPv4, и клиенты IPv6.sockaddr_in■ Семейство адресов, указанное в поле
структурыai_familyвместе с флагамиhintиAI_V4MAPPEDполяAI_ALL, задают тип записей, поиск которых ведется в DNS (тип А или тип AAAA), и тип возвращаемых адресов (IPv4, IPv6 или IPv4, преобразованные к виду IPv6). Мы обобщили это в табл. 11.3.ai_flags■ Имя узла может также быть либо шестнадцатеричной строкой IPv6, либо строкой в точечно-десятичной записи IPv4. Допустимость этой строки зависит от семейства адресов, заданного вызывающим процессом. Шестнадцатеричная строка IPv6 неприемлема, если задано семейство
, а строка в точечно-десятичной записи IPv4 неприемлема, если задано семействоAF_INET. Но если задано семействоAF_INET6, то допустимы оба варианта, и при этом возвращается соответствующий тип структуры адреса сокета.AF_UNSPECПРИМЕЧАНИЕМожно возразить, что если в качестве семейства протоколов задано AF_INET6, строка в точечно-десятичной записи должна возвращаться как адрес IPv4, преобразованный к виду IPv6 в структуре sockaddr_in6. Но другим способом получения этого результата является установка префикса строки с десятичной точкой 0::ffff:.
В табл. 11.3 показано, как будут обрабатываться адреса IPv4 и IPv6 функцией
. Колонка «Результат» отражает то, что мы хотим возвратить вызывающему процессу, если входные переменные таковы, как показано в первых трех колонках. Колонка «Действия» — то, каким образом мы получаем этот результат.getaddrinfoТаблица 11.3. Функция getaddrinfo: ее действия и результаты
Имя узла, указанное вызывающим процессом Семейство адресов, указанное вызывающим процессом Строка с именем узла содержит Результат Действия Ненулевая строка с именем узла; активное или пассивное открытие AF_UNSPEC Имя узла Все записи AAAA возвращаются как структуры sockaddr_in6{} и все записи А возвращаются как структуры sockaddr_in{} Поиск по записям AAAA и поиск по записям A Шестнадцатеричная строка Одна структура sockaddr_in6{} inet_pton(AF_INET6) Строка в точечно- десятичной записи Одна структура sockaddr_in{} inet_pton(AF_INET) AF_INET6 Имя узла Все записи AAAA возвращаются как структуры sockaddr_in6{} либо все записи А возвращаются как структуры sockaddr_in6{} с адресами IPv4, преобразованными к виду IPv6 Поиск по записям AAAA Шестнадцатеричная строка Одна структура sockaddr_in6{} inet_pton(AF_INET6) Строка в точечно-десятичной записи Ищется как имя узла AF_INET Имя узла Все записи А возвращаются как структуры sockaddr_in{} Поиск по записям типа A Шестнадцатеричная строка Ошибка: EAI_ADDRFAMILY Строка в точечно-десятичной записи Одна структура sockaddr_in{} inet_pton(AF_INET) Пустая строка с именем узла; пассивное открытие AF_UNSPEC Неявный адрес 0::0 Неявный адрес 0.0.0.0 Одна структура sockaddr_in6{} и одна структура sockaddr_in{} inet_pton(AF_INET6) inet_pton(AF_INET) AF_INET6 Неявный адрес 0::0 Одна структура sockaddr_in6{} inet_pton(AF_INET6) AF_INET Неявный адрес 0.0.0.0 Одна структура sockaddr_in{} inet_pton(AF_INET) Пустая строка с именем узла; активное открытие AF_UNSPEC Неявный адрес 0::1 Неявный адрес 127.0.0.1 Одна структура sockaddr_in6{} и одна структура sockaddr_in{} inet_pton(AF_INET6) inet_pton(AF_INET) AF_INET6 Неявный адрес 0::1 Одна структура sockaddr_in6{} inet_pton(AF_INET6) AF_INET Неявный адрес 127.0.0.1 Одна структура sockaddr_in{} inet_pton(AF_INET)