и считывает клиентский запрос. Затем он с помощью функции
fork
порождает собственный дочерний процесс, и этот дочерний процесс будет обрабатывать клиентский запрос. Затем сервер TFTP вызывает функцию
exit
, отправляя демону
inetd
сигнал
SIGCHLD
, который, как мы сказали, указывает демону
inetd
снова вызвать функцию
select
на сокете, связанном с портом UDP 69.
22.8. Информация о пакетах IPv6
IPv6
позволяет приложению определять до пяти характеристик исходящей дейтаграммы:
IPv6-адрес отправителя;
индекс интерфейса для исходящих дейтаграмм;
предельное количество транзитных узлов для исходящих дейтаграмм;
адрес следующего транзитного узла;
класс исходящего трафика.
Эта информация отправляется в виде вспомогательных данных с функцией
sendmsg
. Для сокета можно задать постоянные параметры, которые будут действовать на все отправляемые пакеты (раздел 27.7).
Для полученного пакета могут быть возвращены четыре аналогичных характеристики. Они возвращаются в виде вспомогательных данных с функцией
recvmsg
:
IPv6-адрес получателя;
индекс интерфейса для входящих дейтаграмм;
предельное количество транзитных узлов для входящих дейтаграмм.
класс входящего трафика.
На рис. 22.5 показано содержимое вспомогательных данных, о которых рассказывается далее.
Рис. 22.5. Вспомогательные данные для информации о пакете IPv6
Структура
in6_pktinfo
содержит либо IPv6-адрес отправителя и индекс интерфейса для исходящей дейтаграммы, либо IPv6-адрес получателя и индекс интерфейса для получаемой дейтаграммы:
int ipi6_ifindex; /* индекс интерфейса для исходящей/получаемой дейтаграммы */
};
Эта структура определяется в заголовочном файле
<netinet/in.h>
, подключение которого позволяет ее использовать. В структуре
cmsghdr
, содержащей вспомогательные данные, элемент
cmsg_level
будет иметь значение
IPPROTO_IPV6
, элемент
cmsg_type
будет равен
IPV6_PKTINFO
и первый байт данных будет первым байтом структуры
in6_pktinfo
. В примере, приведенном на рис. 22.5, мы считаем, что между структурой
cmsghdr
и данными нет заполнения и целое число занимает 4 байта.
Чтобы отправить эту информацию, никаких специальных действий не требуется — нужно только задать управляющую информацию во вспомогательных данных функции
sendmsg
. Чтобы информация добавлялась ко всем отправляемым через сокет пакетам, необходимо установить параметр сокета
IPV6_PKTINFO
со значением
in6_pktinfo
. Возвращать эту информацию функция
recvmsg
будет, только если приложение включит параметр сокета
IPV6_RECVPKTINFO
.
Исходящий и входящий интерфейсы
Интерфейсы на узле IPv6 идентифицируются небольшими целыми положительными числами, как мы сказали в разделе 18.6. Вспомните, что ни одному интерфейсу не может быть присвоен нулевой индекс. При задании исходящего интерфейса ядро само выберет исходящий интерфейс, если значение
ipi6_ifindex
нулевое. Если приложение задает исходящий интерфейс для пакета многоадресной передачи, то любой интерфейс, заданный параметром сокета
IPV6_MULTICAST_IF
, заменяется на интерфейс, заданный вспомогательными данными (но только для данной дейтаграммы).
Адрес отправителя и адрес получателя IPv6
IPv6-адрес отправителя обычно определяется при помощи функции
bind
. Но если адрес отправителя поставляется вместе с данными, это может снизить непроизводительные затраты. Этот параметр также позволяет серверу гарантировать, что адрес отправителя ответа совпадает с адресом получателя клиентского запроса — некоторым клиентам требуется такое условие, которое сложно выполнить в случае IPv4 (см. упражнение 22.4).
Когда IPv6-адрес отправителя задан в качестве вспомогательных данных и элемент
ipi6_addr
структуры
in6_pktinfo
имеет значение
IN6ADDR_ANY_INIT
, возможны следующие
сценарии: если адрес в настоящий момент связан с сокетом, он используется в качестве адреса отправителя; если в настоящий момент никакой адрес не связан с сокетом, ядро выбирает адрес отправителя. Если же элемент
ipi6_addr
не является неопределенным адресом, но сокет уже связался с адресом отправителя, то значением элемента
ipi6_addr
перекрывается уже связанный адрес, но только для данной операции вывода. Затем ядро проверяет, действительно ли запрашиваемый адрес отправителя является адресом направленной передачи, присвоенным узлу.
Когда структура in6_
pktinfo
возвращается в качестве вспомогательных данных функцией
recvmsg
, элемент
ipi6_addr
содержит IPv6-адрес получателя из полученного пакета. По сути, это аналог параметра сокета
IP_RECVDSTADDR
для IPv4.
Задание и получение предельного количества транзитных узлов
Предельное количество транзитных узлов обычно задается параметром сокета
IPV6_UNICAST_HOPS
для дейтаграмм направленной передачи (см. раздел 7.8) или параметром сокета
IPV6_MULTICAST_HOPS
для дейтаграмм многоадресной передачи (см. раздел 21.6). Задавая предельное количество транзитных узлов в составе вспомогательных данных, мы можем заменить как значение этого предела, задаваемое ядром по умолчанию, так и ранее заданное значение — и для направленной, и для многоадресной передачи, но только для одной операции вывода. Предел количества транзитных узлов полученного пакета используется в таких программах, как
traceroute
, и в некоторых приложениях IPv6, которым нужно проверять, что полученное значение равно 255 (то есть что пакет не пересылался маршрутизаторами).
Полученное предельное количество транзитных узлов возвращается в виде вспомогательных данных функцией
recvmsg
, только если приложение включает параметр сокета
IPV6_RECVHOPLIMIT
. В структуре
cmsghdr
, содержащей эти вспомогательные данные, элемент
cmsg_level
будет иметь значение
IPPROTO_IPV6
, элемент
cmsg_type
— значение
IPV6_HOPLIMIT
, а первый байт данных будет первым байтом целочисленного предела повторных передач. Мы показали это на рис. 22.5. Нужно понимать, что значение, возвращаемое в качестве вспомогательных данных, — это действительное значение из полученной дейтаграммы, в то время как значение, возвращаемое функцией
getsockopt
с параметром
IPV6_UNICAST_HOPS
, является значением по умолчанию, которое ядро будет использовать для исходящих дейтаграмм на сокете.
Чтобы задать предельное количество транзитных узлов для исходящих пакетов, никаких специальных действий не требуется — нам нужно только указать управляющую информацию в виде вспомогательных данных для функции
sendmsg
. Обычные значения для предельного количества транзитных узлов лежат в диапазоне от 0 до 255 включительно, но если целочисленное значение равно -1, это указывает ядру, что следует использовать значение по умолчанию.
ПРИМЕЧАНИЕ
Предельное количество транзитных узлов не содержится в структуре in6_pktinfo — некоторые серверы UDP хотят отвечать на запросы клиентов, посылая ответы на том же интерфейсе, на котором был получен запрос, с совпадением IPv6-адреса отправителя ответа и IPv6-адреса получателя запроса. Для этого приложение может включить параметр сокета IPV6_RECVPKTINFO, а затем использовать полученную управляющую информацию из функции recvmsg в качестве управляющей информации для функции sendmsg при отправке ответа. Приложению вообще никак не нужно проверять или изменять структуру in6_pktinfo. Но если в этой структуре содержался бы предел количества транзитных узлов, приложение должно было бы проанализировать полученную управляющую информацию и изменить значение этого предела, поскольку полученный предел не является желательным значением для исходящего пакета.
Задание адреса следующего транзитного узла
Объект вспомогательных данных
IPV6_NEXTHOP
задает адрес следующего транзитного узла дейтаграммы в виде структуры адреса сокета. В структуре
cmsghdr
, содержащей эти вспомогательные данные, элемент
cmsg_level
будет иметь значение
IPPROTO_IPV6
, элемент
cmsg_type
— значение
IPV6_NEXTHOP
, а первый байт данных будет первым байтом структуры адреса сокета.