62 printf("(undefined)\n");
63 else {
64 switch(ptr->opt_level) {
65 case SOL_SOCKET:
66 case IPPROTO_IP:
67 case IPPROTO_TCP:
68 fd = Socket(AF_INET, SOCK_STREAM, 0);
69 break;
70 #ifdef IPV6
71 case IPPROTO_IPV6:
72 fd = Socket(AF_INET6, SOCK_STREAM, 0);
73 break;
74 #endif
75 #ifdef IPPROTO_SCTP
76 case IPPROTO_SCTP:
77 fd = Socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
78 break;
79 #endif
80 default:
81 err_quit("Can't create fd for level %d\n", ptr->opt_level);
82 }
83 len = sizeof(val);
84 if (getsockopt(fd, ptr->opt_level, ptr->opt_name,
85 &val, &len) == -1) {
86 err_ret("getsockopt error");
87 } else {
88 printf("default = %s\n", (*ptr->opt_val_str)(&val, len));
89 }
90 close(fd);
91 }
92 }
93 exit(0);
94 }
Перебор всех параметров59-63 Мы перебираем все элементы нашего массива. Если указатель opt_val_str пустой, то параметр не определен реализацией (что, как мы показали, возможно для SO_REUSEPORT).
Создание сокета63-82 Мы создаем сокет, на котором проверяем действие параметров. Для проверки параметров сокета и уровней IPv4 и TCP мы используем сокет IPv4 TCP. Для проверки параметров сокетов уровня IPv6 мы используем сокет IPv6 TCP, а для проверки параметров SCTP — сокет IPv4 SCTP.
Вызов функции getsockopt83-87 Мы вызываем функцию getsockopt, но не завершаем ее выполнение, если возвращается ошибка. Многие реализации определяют имена некоторых параметров сокетов, даже если не поддерживают эти параметры. Неподдерживаемые параметры выдают ошибку ENOPROTOOPT.
Вывод значения параметра по умолчанию88-89 Если функция getsockopt успешно завершается, мы вызываем нашу функцию для преобразования значения параметра в строку и выводим эту строку.
В листинге 7.1 мы показали четыре прототипа функций, по одному для каждого типа возвращаемого значения параметра. В листинге 7.3 показана одна из этих функций, sock_str_flag, которая выводит значение параметра, являющегося флагом. Другие три функции аналогичны этой.
Листинг 7.3. Функция sock_str_flag: преобразование флага в строку
//sockopt/checkopts.с
95 static char strres[128];
96 static char *
97 sock_str_flag(union val *ptr, int len)
98 {
99 if (len != sizeof(int))
100 snprint(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
101 else
102 snprintf(strres, sizeof(strres),
103 "%s", (ptr->i_val == 0) ? "off" : "on");
104 return(strres);
105 }
99-104 Вспомните, что последний аргумент функции getsockopt — это аргумент типа «значение-результат». Первое, что мы проверяем, — это то, что размер значения, возвращаемого функцией getsockopt, совпадает с предполагаемым. В зависимости от того, является ли значение флага нулевым или нет, возвращается строка off или on.
Выполнение этой программы под FreeBSD 4.8 с пакетами обновлений KAME SCTP дает следующий вывод:
freebsd % <b>checkopts</b>
SO_BROADCAST: default = off
SO_DEBUG: default = off
SO_DONTROUTE: default = off
SO_ERROR: default = 0
SO_KEEPALIVE: default = off
SO_LINGER: default = l_onoff = 0, l_linger = 0
SO_OOBINLINE: default = off
SO_RCVBUF: default = 57344
SO_SNDBUF: default = 32768
SO_RCVLOWAT: default = 1
SO_SNDLOWAT: default = 2048
SO_RCVTIMEO: default = 0 sec, 0 usec
SO_SNDTIMEO: default = 0 sec, 0 usec
SO_REUSEADDR: default = off
SO_REUSEPORT: default = off
SO_TYPE: default = 1
SO_USELOOPBACK: default = off
IP_TOS: default = 0
IP_TTL: default = 64
IPV6_DONTFRAG: default = off
IPV6_UNICAST_HOPS: default = -1
IPV6_V6ONLY: default = off
TCP_MAXSEG: default = 512
TCP_NODELAY: default = off
SCTP_AUTOCLOSE: default = 0