UNIX: разработка сетевых приложений
Часть 311 из 399 Информация о книге
Определяется структура2-7для IPv4 и IPv6. Указатели структуры адреса сокета инициализируются как нулевые, поскольку еще не известно, какая из версий будет использоваться — IPv4 или IPv6.protoДлина дополнительных данныхУстанавливается количество дополнительных данных (56 байт), которые будут посылаться с эхо-запросом ICMP. При этом полная IPv4-дейтаграмма будет иметь размер 84 байта (20 байт на IPv4-заголовок и 8 байт на ICMP-заголовок), а IPv6-дейтаграмма будет иметь длину 104 байта. Все данные, посылаемые с эхо- запросом, должны быть возвращены в эхо-ответе. Время отправки эхо-запроса будет сохраняться в первых 8 байтах области данных, а затем, при получении эхо- ответа, будет использоваться для вычисления и вывода времени RTT.8Обработка параметров командной строкиЕдинственный параметр командной строки, поддерживаемый в нашей версии, это параметр15-24, в результате использования которого большинство ICMP-сообщений будут выводиться на консоль. (Мы не выводим эхо-ответы, принадлежащие другой запущенной копии программы-v.) Для сигналаpingустанавливается обработчик, и мы увидим, что этот сигнал генерируется один раз в секунду и вызывает отправку эхо-запросов ICMP.SIGALRMОбработка аргумента, содержащего имя узлаСтрока, содержащая имя узла или IP-адрес, является обязательным аргументом и обрабатывается функцией31-48. Возвращаемая структураhost_servсодержит семейство протоколов — либоaddrinfo, либоAF_INET. Глобальный указатель pr устанавливается на требуемую в конкретной ситуации структуруAF_INET6. Также с помощью вызова функцииprotoмы убеждаемся, что адрес IPv6 на самом деле не является адресом IPv4, преобразованным к виду IPv6, поскольку даже если возвращаемый адрес является адресом IPv6, узлу будет отправлен пакет IPv4. (Если такая ситуация возникнет, можно переключиться и использовать IPv4.) Структура адреса сокета, уже размещенная в памяти с помощью функцииIN6_IS_ADDR_V4MAPPED, используется для отправки, а другая структура адреса сокета того же размера размещается в памяти для получения.getaddrinfoОбработка ответов осуществляется функцией
, представленной в листинге 28.4.readlоорЛистинг 28.4. Функция readloop
//ping/readlоор.c1 #include "ping.h"2 void3 readloop(void)4 {5 int size;6 char recvbuf[BUFSIZE];7 char controlbuf[BUFSIZE];8 struct msghdr msg;9 struct iovec iov;10 ssize_t n;11 struct timeval tval;12 sockfd = Socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto);13 setuid(getuid()); /* права привилегированного пользователябольше не нужны */14 if (pr->finit)15 (*pr->finit)();16 size = 60 * 1024; /* setsockopt может завершиться с ошибкой */17 setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));18 sig_alrm(SIGALRM); /* отправка первого пакета */19 iov.iov_base = recvbuf;20 iov.iov_len = sizeof(recvbuf);21 msg.msg_name = pr->sarecv;22 msg.msg_iov = &iov;23 msg.msg_iovlen = 1;24 msg.msg_control = controlbuf;25 for (;;) {26 msg.msg_namelen = pr->salen;27 msg.msg_controllen = sizeof(controlbuf);28 n = recvmsg(sockfd, &msg, 0);29 if (n < 0) {30 if (errno == EINTR)31 continue;32 else33 err_sys("recvmsg error");24 }35 Gettimeofday(&tval, NULL);36 (*pr->fproc)(recvbuf, n, &msg, &tval);37 }38 }Создание сокетаСоздается символьный сокет, соответствующий выбранному протоколу. В вызове функции12-13нашему эффективному идентификатору пользователя присваивается фактический идентификатор пользователя. Для создания символьных сокетов программа должна иметь права привилегированного пользователя, но когда символьный сокет уже создан, от этих прав можно отказаться. Всегда разумнее отказаться от лишних прав, если в них нет необходимости, например на тот случай, если в программе есть скрытая ошибка, которой кто-либо может воспользоваться.setuidВыполнение инициализации для протоколаМы выполняем функцию инициализации для выбранного протокола. Для IPv6 такая функция представлена в листинге 28.7.14-15Установка размера приемного буфера сокетаПытаемся установить размер приемного буфера сокета, равный 61 440 байт (60×1024) — этот размер больше задаваемого по умолчанию. Это делается в расчете на случай, когда пользователь проверяет качество связи с помощью программы16-17, обращаясь либо к широковещательному адресу IPv4, либо к групповому адресу. В обоих случаях может быть получено большое количество ответов. Увеличивая размер буфера, мы уменьшаем вероятность того, что приемный буфер переполнится.pingОтправка первого пакетаЗапускаем обработчик сигнала, который, как мы увидим, посылает пакет и создает сигнал18один раз в секунду. Обычно обработчик сигналов не запускается напрямую, как у нас, но это можно делать. Обработчик сигналов является обычной функцией языка С, просто в нормальных условиях он асинхронно запускается ядром.SIGALRM