UNIX: разработка сетевых приложений
На рис. 27.1 показано, что маршрут состоит из 10 адресов, но первый приведенный адрес удаляется из параметра маршрута от отправителя и становится адресом получателя, когда дейтаграмма IP покидает узел отправителя. Хотя в 40-байтовом пространстве, отведенном под данный параметр IP, хватает места только для 9 адресов (не забудьте о 3-байтовом заголовке параметра, который мы вскоре опишем), фактически в заголовке IPv4 у нас имеется 10 IP-адресов, так как к 9 адресам узлов добавляется адрес получателя.
Поле
— это либоcodeдля параметра LSRR, либо0x83для параметра SSRR. Задаваемое нами значение поля0x89— это размер параметра в байтах, включая 3-байтовый заголовок и дополнительный адрес получателя, приведенный в конце списка. Для маршрута, состоящего из одного IP-адреса, это значение будет равно 11, для двух адресов — 15, и т.д. вплоть до максимального значения 43. Параметр NOP не является частью обсуждаемого параметра, и его длина не включается в значение поля len, но она входит в размер буфера, который мы сообщаем функцииlen. Когда первый адрес в списке удаляется из параметра маршрута от отправителя и добавляется в поле адреса получателя в заголовок IP, значение поляsetsockoptуменьшается на 4 (см. рис. 9.32 и 9.33 [128]). Полеlen— это указатель, или сдвиг, задающий положение следующего IP-адреса из списка, который должен быть обработан. Мы инициализируем это поле значением 4, что соответствует первому адресу IP. Значение этого поля увеличивается на 4 каждый раз, когда дейтаграмма обрабатывается одним из перечисленных в маршруте узлов.ptrТеперь мы переходим к определению трех функций, с помощью которых мы инициализируем, создаем и обрабатываем параметр маршрута от отправителя. Наши функции предназначены для работы только с этим параметром. Хотя в принципе возможно объединить параметр маршрута от отправителя с другими параметрами IP (такими как параметр извещения маршрутизатора), но на практике параметры редко комбинируются. В листинге 27.1 [1] приведена функция
, а также некоторые статические переменные, используемые при составлении параметра.inet_srcrt_initЛистинг 27.1. Функция inet_srcrt_init: инициализация перед записью маршрута от отправителя
//ipopts/sourceroute.с1 #include "unp.h"2 #include <netinet/in_systm.h>3 #include <netinet/ip.h>4 static u_char *optr; /* указатель на формируемые параметры */5 static u_char *lenptr; /* указатель на длину параметра SRR */6 static int ocnt; /* количество адресов */7 u_char*8 inet_srcrt_init(int type)9 {10 optr = Malloc(44); /* NOP, код параметра. len, указатель + до 10адресов */11 bzero(optr, 44); /* гарантирует наличие EOL на конце */12 ocnt = 0;13 *optr++ = IPOPT_NOP; /* выравнивающие NOP */14 *optr++ = type ? IPOPT_SSRR : IPOPT_LSRR;15 lenptr = optr++; /* поле длины заполняется позже */16 *optr++ = 4; /* сдвиг на первый адрес */17 return(optr - 4); /* указатель для setsockopt() */18 }ИнициализацияМы выделяем в памяти буфер, максимальный размер которого — 44 байт, и обнуляем его содержимое. Значение параметра EOL равно нулю, так что тем самым параметр инициализируется байтами EOL. Затем мы подготавливаем заголовок для маршрутизации от источника. Как показано на рис. 27.1, сначала мы обеспечиваем выравнивание при помощи параметра NOP, после чего указываем тип маршрута (гибкий, жесткий), длину и значение указателя. Мы сохраняем указатель в поле10-17. Это значение мы будем записывать при поочередном добавлении адресов к списку. Указатель на параметр возвращается вызывающему процессу, а затем передается как четвертый аргумент функцииlen.setsockoptСледующая функция,
, добавляет один IPv4-адрес к создаваемому маршруту от отправителя.inet_srcrt_addЛистинг 27.2. Функция inet_srcrt_add: добавление одного IPv4-адреса к маршруту от отправителя
//ipopts/sourceroute.с19 int20 inet_srcrt_add(char *hostptr)21 {22 int len;23 struct addrinfo *ai;24 struct sockaddr_in *sin;25 if (ocnt > 9)26 err_quit("too many source routes with: %s", hostptr);27 ai = Host_serv(hostptr, NULL, AF_INET, 0);28 sin = (struct sockaddr_in*)ai->ai_addr;29 memcpy(optr, &sin->sin_addr, sizeof(struct in_addr));30 freeaddrinfo(ai);31 optr += sizeof(struct in_addr);32 ocnt++;33 len = 3 + (ocnt * sizeof(struct in_addr));34 *lenptr = len;35 return(len + 1); /* размер для setsockopt() */36 }АргументАргумент функции указывает либо на имя узла, либо на адрес IP в точечно- десятичной записи.19-20Проверка переполненияМы проверяем количество переданных адресов и выполняем инициализацию, если обрабатывается первый адрес.25-26Получение двоичного IP-адреса и запись маршрутаФункция29-37обрабатывает имя узла или его IP-адрес, а возвращаемый ей адрес в двоичной форме мы помещаем в список. Мы обновляем полеhost_servи возвращаем полный размер буфера (с учетом параметров NOP), который вызывающий процесс затем передаст функцииlen.setsockopt