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
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);
}