Шрифт:
43 for (i = 0; i <= maxi; i++) {
44 if (client[i].connfd >= 0 &&
45 client[i].family == AF_INET &&
46 client[i].lport == sport) {
47 bzero(&dest, sizeof(dest));
48 dest.sin_family = AF_INET;
49 #ifdef HAVE_SOCKADDR_SA_LEN
50 dest.sin_len = sizeof(dest);
51 #endif
52 memcpy(&dest.sin_addr, &hip->ip_dst,
53 sizeof(struct in_addr));
54 dest.sin_port = udp->uh_dport;
55 icmpd_err.icmpd_type = icmp->icmp_type;
56 icmpd_err.icmpd_code = icmp->icmp_code;
57 icmpd_err.icmpd_len = sizeof(struct sockaddr_in);
58 memcpy(&icmpd_err.icmpd_dest, &dest, sizeof(dest));
59 /* преобразование кода и типа ICMP в значение errno */
60 icmpd_err.icmpd_errno = EHOSTUNREACH; /* по умолчанию */
61 if (icmp->icmp_type == ICMP_UNREACH) {
62 if (icmp->icmp_code == ICMP_UNREACH_PORT)
63 icmpd_err.icmpd_errno = ECONNREFUSED;
64 else if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG)
65 icmpd_err.icmpd_errno = EMSGSIZE;
66 }
67 Write(client[i].connfd, &icmpd_err, sizeof(icmpd_err));
68 }
69 }
70 }
71 }
72 return(--nready);
73 }
Проверка типа сообщения, уведомление приложения
29-31
ICMP-сообщения, которые посылаются приложениям, — это сообщения о недоступности порта, превышении времени и завершении клиента (см. табл. 28.1). Проверка ошибки UDP, поиск клиента
34-42
Указатель hip
указывает на IP-заголовок, который возвращается сразу после заголовка ICMP. Это IP-заголовок дейтаграммы, вызвавшей ICMP-ошибку. Мы убеждаемся, что эта IP-дейтаграмма является UDP-дейтаграммой, а затем извлекаем номер UDP-порта из UDP-заголовка, следующего за IP-заголовком.
43-55
По всем структурам client
осуществляется поиск подходящего семейства адресов и порта. Если соответствие найдено, строится структура адреса сокета IPv4, которая содержит IP-адрес получателя и порт из UDP-дейтаграммы, вызвавшей ошибку. Построение структуры icmpd_err
56-70
Строится структура icmpd_err
, посылаемая клиенту через доменный сокет Unix. Тип и код сообщения ICMP сначала отображаются в значение errno
, как показано в табл. 28.1. Ошибки ICMPv6 обрабатываются функцией
readable_v6
, первая часть которой приведена в листинге 28.31. Обработка ошибок ICMPv6 аналогична коду, приведенному в листингах 28.7 и 28.16. Листинг 28.31. Обработка полученной дейтаграммы ICMPv6, первая часть
//icmpd/readable_v6.c
1 #include "icmpd.h"
2 #include <netinet/in_systm.h>
3 #include <netinet/ip.h>
4 #include <netinet/ip_icmp.h>
5 #include <netinet/udp.h>
6 #ifdef IPV6
7 #include <netinet/ip6.h>
8 #include <netinet/icmp6.h>