Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

43-45
Первый IP-адрес в буфере сохраняется, а все следующие за ним параметры NOP мы пропускаем.

Проверяем параметр маршрута от отправителя

46-62
Мы выводим информацию о маршруте и проверяем значение поля
code
, содержащегося в 3-байтовом заголовке, получаем значение поля
len
и пропускаем указатель
ptr
. Затем мы выводим все IP-адреса, следующие за 3-байтовым заголовком, кроме IP-адреса получателя.

Пример

Теперь мы модифицируем наш

эхо-сервер TCP таким образом, чтобы выводить полученный маршрут от отправителя, а эхо-клиент TCP — так, чтобы маршрут от отправителя можно было задавать. В листинге 27.4 показан код эхо-клиента TCP.

Листинг 27.4. Эхо-клиент TCP, задающий маршрут от отправителя

//ipopts/tcpcli01.c

1 #include "unp.h"

2 int

3 main(int argc, char **argv)

4 {

5 int c, sockfd, len = 0;

6 u_char *ptr = NULL;

7 struct addrinfo *ai;

8 if (argc < 2)

9 err_quit("usage: tcpcli01 [ -[gG] <hostname> ... ] <hostname>");

10 opterr = 0; /* отключаем запись сообщений getopt в stderr */

11 while ((с = getopt(argc, argv, "gG")) != -1) {

12 switch (c) {

13 case 'g': /* свободный маршрут от отправителя */

14 if (ptr)

15 err_quit("can't use both -g and -G");

16 ptr = inet_srcrt_init(0);

17 break;

18 case 'G': /* жесткий маршрут от отправителя */

19 if (ptr)

20 err_qint("can't use both -g and -G");

21 ptr = inet_srcrt_init(1);

22 break;

23 case '?':

24 err_quit("unrecognized option: %c", c);

25 }

26 }

27 if (ptr)

28 while (optind < argc-1)

29 len = inet_srcrt_add(argv[optind++]);

30 else if (optind < argc-1)

31 err_quit("need -g or -G to specify route");

32 if (optind != argc-1)

33 err_quit("missing <hostname>");

34 ai = Host_serv(argv[optind], SERV_PORT_STR, AF_INET, SOCK_STREAM);

35 sockfd = Socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);

36 if (ptr) {

37 len = inet_srcrt_add(argv[optind]); /*
получатель в конце */

38 Setsockopt(sockfd, IPPROTO_IP, IP_OPTIONS, ptr, len);

39 free(ptr);

40 }

41 Connect(sockfd, ai->ai_addr, ai->ai_addrlen);

42 str_cli(stdin, sockfd); /* вызов рабочей функции */

43 exit(0);

44 }

Обработка аргументов командной строки

12-26
Мы вызываем нашу функцию
inet_srcrt_init
, чтобы инициализировать маршрут от отправителя. Тип маршрутизации указывается при помощи параметра
– g
(свободная) или
– G
(жесткая).

27-33
Если указатель
ptr
установлен, значит, был указан параметр маршрутизации от отправителя, и все указанные промежуточные узлы добавляются к маршруту, подготовленному на предыдущем этапе функцией
inet_srcrt_add
. Если же
ptr
не установлен, но в командной строке еще есть аргументы, значит, пользователь задал маршрут, но не указал его тип. В этом случае программа завершает работу с сообщением об ошибке.

Обработка адреса получателя и создание сокета

34-35
Последний аргумент командной строки — это имя узла или адрес сервера в точечно-десятичной записи, который обрабатывается нашей функцией
host_serv
. Мы не можем вызвать функцию
tcp_connect
, так как должны задать маршрут от отправителя между вызовом функций
socket
и
connect
. Последняя инициирует трехэтапное рукопожатие, а нам нужно, чтобы сегмент SYN отправителя и все последующие пакеты проходили по одному и тому же маршруту.

36-42
Если маршрут от отправителя задан, следует добавить IP-адрес сервера в конец списка адресов (см. рис. 27.1). Функция
setsockopt
устанавливает маршрут от отправителя для данного сокета. Затем мы вызываем функцию connect, а потом — нашу функцию
str_cli
(см. листинг 5.4).

Наш TCP-сервер имеет много общего с кодом, показанным в листинге 5.9, но содержит следующие изменения.

Во-первых, мы выделяем место для параметров:

int len;

u_char *opts;

opts = Malloc(44);

Во-вторых, мы получаем параметры IP после вызова функции

accept
, но перед вызовом функции
fork
:

len = 44;

Getsockopt(connfd, IPPROTO_IP, IP_OPTIONS, opts, &len);

if (len > 0) {

printf("received IP options, len = %d\n", len);

inet_srcrt_print(opts, len);

Поделиться с друзьями: