Книга: UNIX: разработка сетевых приложений
7.3. Проверка наличия параметра и получение значения по умолчанию
Разделы на этой странице:
7.3. Проверка наличия параметра и получение значения по умолчанию
Напишем программу, которая проверяет, поддерживается ли большинство параметров, представленных в табл. 7.1 и 7.2, и если да, то выводит их значения, заданные по умолчанию. В листинге 7.1[1] содержатся объявления нашей программы.
Листинг 7.1. Объявления для нашей программы, проверяющей параметры сокетов
//sockopt/checkopts.с
1 #include "unp.h"
2 #include <netinet/tcp.h> /* определения констант TCP_xxx */
3 union val {
4 int i_val;
5 long l_val;
6 struct linger linger_val;
7 struct timeval timeval_val;
8 } val;
9 static char *sock_str_flag(union val*, int);
10 static char *sock_str_int(union val*, int);
11 static char *sock_str_linger(union val*, int);
12 static char *sock_str_timeval(union val*, int);
13 struct sock_opts {
14 const char *opt_str;
15 int opt_level;
16 int opt_name;
17 char *(*opt_val_str)(union val*, int);
18 } sock_opts[] = {
19 { "SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, sock_str_flag },
20 { "SO_DEBUG", SOL_SOCKET, SO_DEBUG, sock_str_flag },
21 { "SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE, sock_str_flag },
22 { "SO_ERROR", SOL_SOCKET, SO_ERROR, sock_str_int },
23 { "SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, sock_str_flag },
24 { "SO_LINGER", SOL_SOCKET, SO_LINGER, sock_str_linger },
25 { "SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE, sock_str_flag },
26 { "SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, sock_str_int },
27 { "SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, sock_str_int },
28 { "SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, sock_str_int },
29 { "SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, sock_str_int },
30 { "SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, sock_str_timeval },
31 { "SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, sock_str_timeval },
32 { "SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, sock_str_flag },
33 #ifdef SO_REUSEPORT
34 { "SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, sock_str_flag },
35 #else
36 { "SO_REUSEPORT", 0, 0, NULL },
37 #endif
38 { "SO_TYPE", SOL_SOCKET, SO_TYPE, sock_str_int },
39 { "SO_USELOOPBACK", SOL_SOCKET, SO_USELOOPBACK, sock_str_flag },
40 { "IP_TOS", IPPROTO_IP, IP_TOS, sock_str_int },
41 { "IP_TTL", IPPROTO_IP, IP_TTL, sock_str_int },
42 { "IPV6_DONTFRAG", IPPROTO_IPV6, IPV6_DONTFRAG, sock_str_flag },
43 { "IPV6_UNICAST_HOPS", IPPROTO_IPV6, IPV6_UNICAST_HOPS, sock_str_int },
44 { "IPV6_V6ONLY", IPPROTO_IPV6, IPV6_V6ONLY, sock_str_flag },
45 { "TCP_MAXSEG", IPPROTO_TCP, TCP_MAXSEG, sock_str_int },
46 { "TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, sock_str_flag },
47 { "SCTP_AUTOCLOSE", IPPROTO_SCTP, SCTP_AUTOCLOSE, sock_str_int },
48 { "SCTP_MAXBURST", IPPROTO_SCTP, SCTP_MAXBURST, sock_str_int },
49 { "SCTP_MAXSEG", IPPROTO_SCTP, SCTP_MAXSEG, sock_str_int },
50 { "SCTP_NODELAY", IPPROTO_SCTP, SCTP_NODELAY, sock_str_flag },
51 { NULL, 0, 0, NULL }
52 };
Объявление объединения возможных значений
3-9
Наше объединение val
содержит по одному элементу для каждого возможного возвращаемого значения из функции getsockopt
.
Задание прототипов функций
10-13
Мы определяем прототипы для четырех функций, которые вызываются для вывода значения данного параметра сокета.
Задание структуры и инициализация массива
14-46
Наша структура sock_opts
содержит всю информацию, которая необходима, чтобы вызвать функцию getsockopt
для каждого из параметров сокета и вывести его текущее значение. Последний элемент, opt_val_str
, является указателем на одну из четырех функций, которые выводят значение параметра. Мы размещаем в памяти и инициализируем массив этих структур, каждый элемент которого соответствует одному параметру сокета.
ПРИМЕЧАНИЕ
Не все реализации поддерживают полный набор параметров сокетов. Чтобы определить, поддерживается ли данный параметр, следует использовать #ifdef или #if defined, как показано для параметра SO_REUSEPORT. Для полноты картины требуется обработать подобным образом все параметры, но в книге мы пренебрегаем этим, потому что #ifdef только удлиняет показанный код и не влияет на суть дела.
В листинге 7.2 показана наша функция main
.
Листинг 7.2. Функция main для проверки параметров сокетов
//sockopt/checkopts.c
53 int
54 main(int argc, char **argv)
55 {
56 int fd;
57 socklen_t len;
58 struct sock_opts *ptr;
59 for (ptr = sock_opts; ptr->opt_str != NULL; ptr++) {
60 printf("%s: ptr->opt_str);
61 if (ptr->opt_val_str == NULL)
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 %dn", 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 = %sn", (*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.
Вызов функции getsockopt
83-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-104getsockopt
— это аргумент типа «значение-результат». Первое, что мы проверяем, — это то, что размер значения, возвращаемого функцией getsockopt
, совпадает с предполагаемым. В зависимости от того, является ли значение флага нулевым или нет, возвращается строка off
или on
.
Выполнение этой программы под FreeBSD 4.8 с пакетами обновлений KAME SCTP дает следующий вывод:
freebsd % checkopts
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
SCTP_MAXBURST: default = 4
SCTP_MAXSEG: default = 1408
SCTP_NODELAY: default = off
Значение 1, возвращаемое для параметра SO_TYPE
, для этой реализации соответствует SOCK_STREAM
.
- 7.1. Введение
- 7.2. Функции getsockopt и setsockopt
- 7.3. Проверка наличия параметра и получение значения по умолчанию
- 7.4. Состояния сокетов
- 7.5. Общие параметры сокетов
- 7.6. Параметры сокетов IPv4
- 7.7. Параметр сокета ICMPv6
- 7.8. Параметры сокетов IPv6
- 7.9. Параметры сокетов TCP
- 7.10. Параметры сокетов SCTP
- 7.11. Функция fcntl
- 7.12. Резюме
- Упражнения