swrap: let swrap_sendmsg_before_unix() create a copy of msg_tmp.msg_control
[socket_wrapper.git] / tests / test_echo_tcp_socket_options.c
1 #include <stdarg.h>
2 #include <stddef.h>
3 #include <setjmp.h>
4 #include <cmocka.h>
5
6 #include "config.h"
7 #include "torture.h"
8
9 #include <errno.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <netinet/tcp.h>
14 #ifdef HAVE_NETINET_TCP_FSM_H
15 #include <netinet/tcp_fsm.h>
16 #endif
17 #include <arpa/inet.h>
18 #include <netdb.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22
23 #ifdef HAVE_NETINET_TCP_FSM_H
24 /* This is FreeBSD */
25 # define __TCP_ESTABLISHED TCPS_ESTABLISHED
26 # define __TCP_CLOSE TCPS_CLOSED
27 #else
28 /* This is Linux */
29 # define __TCP_ESTABLISHED TCP_ESTABLISHED
30 # define __TCP_CLOSE TCP_CLOSE
31 #endif
32
33 #ifndef ZERO_STRUCT
34 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
35 #endif
36
37 static int setup_echo_srv_tcp_ipv4(void **state)
38 {
39         torture_setup_echo_srv_tcp_ipv4(state);
40
41         return 0;
42 }
43
44 #ifdef HAVE_IPV6
45 static int setup_echo_srv_tcp_ipv6(void **state)
46 {
47         torture_setup_echo_srv_tcp_ipv6(state);
48
49         return 0;
50 }
51
52 static int setup_ipv6(void **state)
53 {
54         torture_setup_socket_dir(state);
55
56         return 0;
57 }
58 #endif
59
60 static int teardown(void **state)
61 {
62         torture_teardown_echo_srv(state);
63
64         return 0;
65 }
66
67 static void test_sockopt_sndbuf(void **state)
68 {
69         struct torture_address addr = {
70                 .sa_socklen = sizeof(struct sockaddr_in),
71         };
72         int obufsize = 0;
73         socklen_t olen = sizeof(obufsize);
74         int gbufsize = 0;
75         socklen_t glen = sizeof(gbufsize);
76         int sbufsize = 0;
77         int rc;
78         int s;
79
80         (void) state; /* unused */
81
82         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
83         assert_int_not_equal(s, -1);
84
85         addr.sa.in.sin_family = AF_INET;
86         addr.sa.in.sin_port = htons(torture_server_port());
87
88         rc = inet_pton(addr.sa.in.sin_family,
89                        torture_server_address(AF_INET),
90                        &addr.sa.in.sin_addr);
91         assert_int_equal(rc, 1);
92
93         rc = connect(s, &addr.sa.s, addr.sa_socklen);
94         assert_int_equal(rc, 0);
95
96         rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, &obufsize, &olen);
97         assert_int_equal(rc, 0);
98
99         /* request 4k, on Linux the kernel doubles the value */
100         sbufsize = 4096;
101         rc = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sbufsize, sizeof(sbufsize));
102         assert_int_equal(rc, 0);
103
104         rc = getsockopt(s, SOL_SOCKET, SO_SNDBUF, &gbufsize, &glen);
105         assert_int_equal(rc, 0);
106
107         assert_true(sbufsize == gbufsize || sbufsize == gbufsize/2);
108
109         close(s);
110 }
111
112 #ifndef SO_PROTOCOL
113 # ifdef SO_PROTOTYPE /* The Solaris name */
114 #  define SO_PROTOCOL SO_PROTOTYPE
115 # endif /* SO_PROTOTYPE */
116 #endif /* SO_PROTOCOL */
117
118 static void test_sockopt_so(void **state)
119 {
120         struct torture_address addr = {
121                 .sa_socklen = sizeof(struct sockaddr_in),
122         };
123         socklen_t so_len;
124 #ifdef SO_DOMAIN
125         int so_domain = -1;
126 #endif /* SO_DOMAIN */
127 #ifdef SO_PROTOCOL
128         int so_protocol = -1;
129         int so_type = -1;
130 #endif /* SO_PROTOCOL */
131         int rc;
132         int s;
133
134         (void) state; /* unused */
135
136         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
137         assert_int_not_equal(s, -1);
138
139         addr.sa.in.sin_family = AF_INET;
140         addr.sa.in.sin_port = htons(torture_server_port());
141
142         rc = inet_pton(addr.sa.in.sin_family,
143                        torture_server_address(AF_INET),
144                        &addr.sa.in.sin_addr);
145         assert_int_equal(rc, 1);
146
147         rc = connect(s, &addr.sa.s, addr.sa_socklen);
148         assert_int_equal(rc, 0);
149
150 #ifdef SO_DOMAIN
151         so_len = sizeof(so_domain);
152         rc = getsockopt(s,
153                         SOL_SOCKET,
154                         SO_DOMAIN,
155                         &so_domain,
156                         &so_len);
157         assert_return_code(rc, errno);
158         assert_int_equal(so_domain, AF_INET);
159         assert_int_equal(so_len, sizeof(int));
160 #endif /* SO_DOMAIN */
161
162 #ifdef SO_PROTOCOL
163         so_len = sizeof(so_protocol);
164         rc = getsockopt(s,
165                         SOL_SOCKET,
166                         SO_PROTOCOL,
167                         &so_protocol,
168                         &so_len);
169         assert_return_code(rc, errno);
170         assert_int_equal(so_protocol, IPPROTO_TCP);
171         assert_int_equal(so_len, sizeof(int));
172
173         so_len = sizeof(so_type);
174         rc = getsockopt(s,
175                         SOL_SOCKET,
176                         SO_TYPE,
177                         &so_type,
178                         &so_len);
179         assert_return_code(rc, errno);
180         assert_int_equal(so_type, SOCK_STREAM);
181         assert_int_equal(so_len, sizeof(int));
182 #endif /* SO_PROTOCOL */
183
184         close(s);
185 }
186
187 #ifdef HAVE_IPV6
188 static void test_sockopt_so6(void **state)
189 {
190         struct torture_address addr = {
191                 .sa_socklen = sizeof(struct sockaddr_in),
192         };
193 #ifdef SO_DOMAIN
194         int so_domain = -1;
195 #endif /* SO_DOMAIN */
196 #ifdef SO_PROTOCOL
197         socklen_t so_len;
198         int so_protocol = -1;
199         int so_type = -1;
200 #endif /* SO_PROTOCOL */
201         int rc;
202         int s;
203
204         (void) state; /* unused */
205
206         s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
207         assert_int_not_equal(s, -1);
208
209         addr.sa.in6.sin6_family = AF_INET6;
210         addr.sa.in6.sin6_port = htons(torture_server_port());
211
212         rc = inet_pton(addr.sa.in6.sin6_family,
213                        torture_server_address(AF_INET6),
214                        &addr.sa.in6.sin6_addr);
215         assert_int_equal(rc, 1);
216
217         rc = connect(s, &addr.sa.s, addr.sa_socklen);
218         assert_int_equal(rc, 0);
219
220 #ifdef SO_DOMAIN
221         so_len = sizeof(so_domain);
222         rc = getsockopt(s,
223                         SOL_SOCKET,
224                         SO_DOMAIN,
225                         &so_domain,
226                         &so_len);
227         assert_return_code(rc, errno);
228         assert_int_equal(so_domain, AF_INET6);
229         assert_int_equal(so_len, sizeof(int));
230 #endif /* SO_DOMAIN */
231
232 #ifdef SO_PROTOCOL
233         so_len = sizeof(so_protocol);
234         rc = getsockopt(s,
235                         SOL_SOCKET,
236                         SO_PROTOCOL,
237                         &so_protocol,
238                         &so_len);
239         assert_return_code(rc, errno);
240         assert_int_equal(so_protocol, IPPROTO_TCP);
241         assert_int_equal(so_len, sizeof(int));
242
243         so_len = sizeof(so_type);
244         rc = getsockopt(s,
245                         SOL_SOCKET,
246                         SO_TYPE,
247                         &so_type,
248                         &so_len);
249         assert_return_code(rc, errno);
250         assert_int_equal(so_type, SOCK_STREAM);
251         assert_int_equal(so_len, sizeof(int));
252 #endif /* SO_PROTOCOL */
253
254         close(s);
255 }
256
257 static void test_bind_ipv6_only(void **state)
258 {
259         struct addrinfo hints;
260         struct addrinfo *res, *ri;
261         char svc[] = "7777";
262         int rc;
263         int s;
264
265         (void) state; /* unused */
266
267         ZERO_STRUCT(hints);
268         hints.ai_family = AF_UNSPEC;
269         hints.ai_socktype = SOCK_STREAM;
270         hints.ai_flags = AI_PASSIVE;
271
272         rc = getaddrinfo(torture_server_address(AF_INET6), svc, &hints, &res);
273         assert_int_equal(rc, 0);
274
275         for (ri = res; ri != NULL; ri = ri->ai_next) {
276                 int one = 1;
277
278                 s = socket(ri->ai_family,
279                            ri->ai_socktype,
280                            ri->ai_protocol);
281                 assert_int_not_equal(rc, -1);
282
283                 rc = setsockopt(s,
284                                 IPPROTO_IPV6,
285                                 IPV6_V6ONLY,
286                                 (const void *)&one,
287                                 sizeof(one));
288                 switch(ri->ai_family) {
289                 case AF_INET:
290                         assert_int_equal(rc, -1);
291
292                         break;
293                 case AF_INET6:
294                         assert_int_equal(rc, 0);
295
296                         rc = bind(s, ri->ai_addr, ri->ai_addrlen);
297                         assert_int_equal(rc, 0);
298
299                         break;
300                 default:
301                         break;
302                 }
303
304                 close(s);
305         }
306         freeaddrinfo(res);
307 }
308 #endif
309
310 static void test_sockopt_tcp(void **state)
311 {
312         struct torture_address addr = {
313                 .sa_socklen = sizeof(struct sockaddr_in),
314         };
315         int opt = -1;
316 #ifdef TCP_INFO
317         struct tcp_info info;
318 #endif
319         socklen_t optlen = sizeof(int);
320         int rc;
321
322         int s;
323
324         (void) state; /* unused */
325
326         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
327         assert_int_not_equal(s, -1);
328
329         addr.sa.in.sin_family = AF_INET;
330         addr.sa.in.sin_port = htons(torture_server_port());
331
332         rc = inet_pton(addr.sa.in.sin_family,
333                        torture_server_address(AF_INET),
334                        &addr.sa.in.sin_addr);
335         assert_int_equal(rc, 1);
336
337 #ifdef TCP_INFO
338         ZERO_STRUCT(info);
339         optlen = sizeof(info);
340         rc = getsockopt(s, IPPROTO_TCP, TCP_INFO, &info, &optlen);
341         assert_return_code(rc, errno);
342         assert_int_equal(optlen, sizeof(info));
343         printf("info.tcpi_state=0x%x\n", info.tcpi_state);
344         printf("info.tcpi_rto=%u\n", info.tcpi_rto);
345         printf("info.tcpi_rtt=%u\n", info.tcpi_rtt);
346         printf("info.tcpi_rttvar=%u\n", info.tcpi_rttvar);
347         assert_int_equal(info.tcpi_state, __TCP_CLOSE);
348         assert_int_not_equal(info.tcpi_rto, 0);
349         assert_int_equal(info.tcpi_rtt, 0);
350         assert_int_not_equal(info.tcpi_rttvar, 0);
351 #endif /* TCP_INFO */
352
353         rc = connect(s, &addr.sa.s, addr.sa_socklen);
354         assert_int_equal(rc, 0);
355
356         opt = -1;
357         optlen = sizeof(int);
358         rc = getsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen);
359         assert_return_code(rc, errno);
360         assert_int_equal(opt, 0);
361
362         opt = 1; /* Turn on TCP_NODELAY */
363         optlen = sizeof(int);
364         rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, optlen);
365         assert_return_code(rc, errno);
366
367         opt = -1;
368         optlen = sizeof(int);
369         rc = getsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen);
370         assert_return_code(rc, errno);
371         assert_int_equal(opt, 1);
372
373 #ifdef TCP_INFO
374         ZERO_STRUCT(info);
375         optlen = sizeof(info);
376         rc = getsockopt(s, IPPROTO_TCP, TCP_INFO, &info, &optlen);
377         assert_return_code(rc, errno);
378         assert_int_equal(optlen, sizeof(info));
379         printf("info.tcpi_state=0x%x\n", info.tcpi_state);
380         printf("info.tcpi_rto=%u\n", info.tcpi_rto);
381         printf("info.tcpi_rtt=%u\n", info.tcpi_rtt);
382         printf("info.tcpi_rttvar=%u\n", info.tcpi_rttvar);
383         assert_int_equal(info.tcpi_state, __TCP_ESTABLISHED);
384         assert_int_not_equal(info.tcpi_rto, 0);
385         assert_int_not_equal(info.tcpi_rtt, 0);
386         assert_int_not_equal(info.tcpi_rttvar, 0);
387 #endif /* TCP_INFO */
388
389         close(s);
390 }
391
392 int main(void) {
393         int rc;
394
395         const struct CMUnitTest sockopt_tests[] = {
396                 cmocka_unit_test_setup_teardown(test_sockopt_sndbuf,
397                                                 setup_echo_srv_tcp_ipv4,
398                                                 teardown),
399                 cmocka_unit_test_setup_teardown(test_sockopt_so,
400                                                 setup_echo_srv_tcp_ipv4,
401                                                 teardown),
402 #ifdef HAVE_IPV6
403                 cmocka_unit_test_setup_teardown(test_sockopt_so6,
404                                                 setup_echo_srv_tcp_ipv6,
405                                                 teardown),
406                 cmocka_unit_test_setup_teardown(test_bind_ipv6_only,
407                                                 setup_ipv6,
408                                                 teardown),
409 #endif
410                 cmocka_unit_test_setup_teardown(test_sockopt_tcp,
411                                                 setup_echo_srv_tcp_ipv4,
412                                                 teardown),
413         };
414
415         rc = cmocka_run_group_tests(sockopt_tests, NULL, NULL);
416
417         return rc;
418 }