UNIX: разработка сетевых приложений
Шрифт:
В данном разделе предлагается решение, не требующее никаких изменений в ядре. Мы предлагаем демон ICMP-сообщений
Рис. 28.7.
Приложение UDP (являющееся клиентом для демона) сначала создает сокет UDP, для которого оно хочет получать асинхронные ошибки. Приложение должно связать (функция
Рис. 28.8. Приложение создает свой сокет UDP и доменный сокет Unix
Далее приложение «передает» свой UDP-сокет демону через соединение домена Unix, используя технологию передачи дескрипторов, как показано в разделе 15.7. Такой подход позволяет демону получить копию сокета, так что он может вызвать функцию
Рис. 28.9. Пересылка сокета UDP демону через доменный сокет Unix
После того как демон получает номер порта, связанный с UDP-сокетом, он закрывает свою копию сокета, и мы возвращаемся к схеме, приведенной на рис. 28.8.
Если узел поддерживает передачу данных, идентифицирующих отправителя (см. раздел 15.8), приложение также может послать эти данные демону. Затем демон может проверить, можно ли допускать данного пользователя к данному устройству.
В таком случае в результате любой ошибки ICMP, полученной демоном в ответ на UDP-дейтаграмму, посланную с порта, который связан с UDP-сокетом приложения, демон посылает приложению сообщение (о котором мы рассказываем чуть ниже) через доменный сокет Unix. Тогда приложение должно использовать функцию
Сначала рассмотрим исходный код приложения, использующего данный демон, а затем и сам демон. В листинге 28.20 приведен заголовочный файл, подключаемый и к приложению, и к демону.
Листинг 28.20. Заголовочный файл unpicmpd.h
Таблица 28.1. Значения переменной icmpd_errno, сопоставляющей ошибки ICMPv4 и ICMPv6
icmpd_errno | Ошибка ICMPv4 | Ошибка ICMPv6 |
---|---|---|
ECONNREFUSED | Port unreachable (Порт недоступен) | Port unreachable (Порт недоступен) |
EMSGSIZE | Fragmentation needed but DF bit set (Необходима фрагментация, но установлен бит DF) | Packet too big (Слишком большой пакет) |
EHOSTUNREACH | Time exceeded (Превышено время передачи) | Time exceeded (Превышено время передачи) |
EHOSTUNREACH | Source quench (Отключение отправителя) | |
EHOSTUNREACH | Все другие сообщения о недоступности получателя (Destination unreachable) | Все другие сообщения о недоступности получателя (Destination unreachable) |
Демон возвращает пять типов ошибок ICMP:
1. «Port unreachable» (Порт недоступен) означает, что сокет не связан с портом получателя на IP-адресе получателя.
2. «Packet too big» (Слишком большой пакет) используется при определении транспортной MTU. В настоящее время нет определенного API, позволяющего UDP-приложениям осуществлять определение транспортной MTU. Если ядро поддерживает определение транспортной MTU для UDP, то обычно получение данной ошибки ICMP заставляет ядро записать новое значение транспортной MTU в таблицу маршрутизации ядра, но UDP-приложение, пославшее дейтаграмму, не извещается. Вместо этого приложение должно дождаться истечения тайм-аута и повторно послать дейтаграмму, и тогда ядро найдет новое (меньшее) значение MTU в своей таблице маршрутизации и фрагментирует дейтаграмму. Передача этой ошибки приложению позволяет ему ускорить повторную передачу дейтаграммы, и возможно, приложение сможет уменьшить размер посылаемой дейтаграммы.
3. Ошибка «Time exceeded» (Превышено время передачи) обычно возникает с кодом 0 и означает, что либо значение поля TTL (в случае IPv4), либо предельное количество транзитных узлов (в случае IPv6) достигло нуля. Обычно это свидетельствует о зацикливании маршрута, что, возможно, является временной ошибкой.
4. Ошибка «Source quench» (Отключение отправителя) ICMPv4 хотя и рассматривается в RFC 1812 [6] как устаревшая, может быть послана маршрутизаторами (или неправильно сконфигурированными узлами, действующими как маршрутизаторы). Такие ошибки означают, что пакет отброшен, и поэтому обрабатываются как ошибки недоступности получателя. Следует отметить, что в версии IPv6 нет ошибки отключения отправителя.