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