socket_wrapper.c: make FIONREAD handling more robust in swrap_vioctl()
[socket_wrapper.git] / tests / test_echo_tcp_bind.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 <sys/un.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #ifdef HAVE_RPC_RPC_H
19 #include <rpc/rpc.h>
20 #endif
21
22 static int setup_echo_srv_tcp_ipv4(void **state)
23 {
24         torture_setup_echo_srv_tcp_ipv4(state);
25
26         return 0;
27 }
28
29 #ifdef HAVE_IPV6
30 static int setup_echo_srv_tcp_ipv6(void **state)
31 {
32         torture_setup_echo_srv_tcp_ipv6(state);
33
34         return 0;
35 }
36 #endif
37
38 static int teardown(void **state)
39 {
40         torture_teardown_echo_srv(state);
41
42         return 0;
43 }
44
45 static void test_bind_ipv4(void **state)
46 {
47         struct torture_address addr = {
48                 .sa_socklen = sizeof(struct sockaddr_storage),
49         };
50         struct torture_address addr_in = {
51                 .sa_socklen = sizeof(struct sockaddr_in),
52         };
53         struct torture_address addr_un = {
54                 .sa_socklen = sizeof(struct sockaddr_un),
55         };
56         int rc;
57         int s;
58
59         (void) state; /* unused */
60
61         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
62         assert_return_code(s, errno);
63
64         /*
65          * Test various cases with family AF_UNSPEC
66          */
67
68         /* UNSPEC, len == 1: EINVAL */
69
70         addr_in.sa.in = (struct sockaddr_in) {
71                 .sin_family = AF_UNSPEC,
72         };
73         rc = bind(s, &addr.sa.s, 1);
74         assert_int_equal(rc, -1);
75         assert_int_equal(errno, EINVAL);
76
77         /* UNSPEC: EAFNOSUPPORT */
78
79         addr_in.sa.in = (struct sockaddr_in) {
80                 .sin_family = AF_UNSPEC,
81         };
82         rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr);
83         assert_int_equal(rc, 1);
84
85         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
86         assert_int_equal(rc, -1);
87         /* FreeBSD uses EADDRNOTAVAIL here ... */
88         assert_true(errno == EAFNOSUPPORT || errno == EADDRNOTAVAIL);
89
90         /* special case: AF_UNSPEC with INADDR_ANY: success mapped to AF_INET */
91
92         addr_in.sa.in = (struct sockaddr_in) {
93                 .sin_family = AF_UNSPEC,
94         };
95         assert_int_equal(addr_in.sa.in.sin_addr.s_addr, htonl(INADDR_ANY));
96
97         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
98         assert_return_code(rc, errno);
99
100         close(s);
101
102         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
103         assert_return_code(s, errno);
104
105         /*
106          * Test various cases with family AF_UNIX
107          * all fail with EAFNOSUPPORT
108          */
109
110         addr.sa.ss = (struct sockaddr_storage) {
111                 .ss_family = AF_UNIX,
112         };
113         rc = bind(s, &addr.sa.s, addr.sa_socklen);
114         assert_int_equal(rc, -1);
115         assert_int_equal(errno, EAFNOSUPPORT);
116
117         addr_in.sa.in = (struct sockaddr_in) {
118                 .sin_family = AF_UNIX,
119         };
120         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
121         assert_int_equal(rc, -1);
122         assert_int_equal(errno, EAFNOSUPPORT);
123
124         addr_un.sa.un = (struct sockaddr_un) {
125                 .sun_family = AF_UNIX,
126         };
127         rc = bind(s, &addr_un.sa.s, addr_un.sa_socklen);
128         assert_int_equal(rc, -1);
129         assert_int_equal(errno, EAFNOSUPPORT);
130
131 #ifdef HAVE_IPV6
132         /*
133          * Test with family AF_INET6 - fail
134          */
135
136         addr_in.sa.in = (struct sockaddr_in) {
137                 .sin_family = AF_INET6,
138         };
139         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
140         assert_int_equal(rc, -1);
141         assert_int_equal(errno, EAFNOSUPPORT);
142 #endif
143
144         /*
145          * Finally, success binding a new IPv4 address.
146          */
147         addr_in = (struct torture_address) {
148                 .sa_socklen = sizeof(struct sockaddr_in),
149                 .sa.in = (struct sockaddr_in) {
150                         .sin_family = AF_INET,
151                 },
152         };
153
154         rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr);
155         assert_int_equal(rc, 1);
156
157         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
158         assert_return_code(rc, errno);
159
160         addr_in = (struct torture_address) {
161                 .sa_socklen = sizeof(struct sockaddr_in),
162                 .sa.in = (struct sockaddr_in) {
163                         .sin_family = AF_INET,
164                         .sin_port = htons(torture_server_port()),
165                 },
166         };
167
168         rc = inet_pton(AF_INET,
169                        torture_server_address(AF_INET),
170                        &addr_in.sa.in.sin_addr);
171         assert_int_equal(rc, 1);
172
173         rc = connect(s, &addr_in.sa.s, addr_in.sa_socklen);
174         assert_return_code(rc, errno);
175
176         close(s);
177 }
178
179 #if 0 /* TODO */
180 static void test_bind_ipv4_addr_in_use(void **state)
181 {
182         struct sockaddr_in sin, sin2;
183         socklen_t slen = sizeof(struct sockaddr_in);
184         int rc;
185         int s, s2;
186
187         (void) state; /* unused */
188
189         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
190         assert_return_code(s, errno);
191
192         /*
193          * Try to bind to the same address as already bound by a
194          * different process.
195          */
196
197         /* Without specifying the port - success */
198
199         ZERO_STRUCT(sin);
200         sin.sin_family = AF_INET;
201         rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr);
202         assert_int_equal(rc, 1);
203         rc = bind(s, (struct sockaddr *)&sin, slen);
204         assert_return_code(rc, errno);
205
206         close(s);
207
208         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
209         assert_return_code(s, errno);
210
211 #if 0
212         /* specify the same port - fail with EADDRINUSE. */
213
214         /* Not supported by socket_wrapper yet. ==> TODO! */
215
216         ZERO_STRUCT(sin);
217         sin.sin_family = AF_INET,
218         sin.sin_port = htons(torture_server_port());
219         rc = inet_pton(AF_INET, torture_server_address(AF_INET), &sin.sin_addr);
220         assert_int_equal(rc, 1);
221
222         rc = bind(s, (struct sockaddr *)&sin, slen);
223         assert_int_equal(rc, -1);
224         assert_int_equal(errno, EADDRINUSE);
225 #endif
226
227         /*
228          * Try double binding when the firs bind is with port == 0
229          */
230
231         ZERO_STRUCT(sin);
232         sin.sin_family = AF_INET;
233
234         rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr);
235         assert_int_equal(rc, 1);
236
237         rc = bind(s, (struct sockaddr *)&sin, slen);
238         assert_return_code(rc, errno);
239
240         /*
241          * Open a second socket locally and try to bind to the same address.
242          */
243
244          /* Succeeds with port == 0 */
245
246         s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
247         assert_return_code(s, errno);
248
249         ZERO_STRUCT(sin2);
250         sin2.sin_family = AF_INET;
251
252         rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr);
253         assert_int_equal(rc, 1);
254
255         rc = bind(s2, (struct sockaddr *)&sin2, slen);
256         assert_return_code(rc, errno);
257
258         close(s2);
259
260         /* second bind with port != 0  - succeeds */
261
262         s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
263         assert_return_code(s, errno);
264
265         ZERO_STRUCT(sin2);
266         sin2.sin_family = AF_INET;
267         sin2.sin_port = htons(12345);
268
269         rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr);
270         assert_int_equal(rc, 1);
271
272         rc = bind(s2, (struct sockaddr *)&sin2, slen);
273         assert_return_code(rc, errno);
274
275         close(s2);
276         close(s);
277
278         /*
279          * Try double binding when the first bind is with port != 0
280          */
281
282         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
283         assert_return_code(s, errno);
284
285         ZERO_STRUCT(sin);
286         sin.sin_family = AF_INET;
287         sin.sin_port = htons(12345);
288
289         rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr);
290         assert_int_equal(rc, 1);
291
292         rc = bind(s, (struct sockaddr *)&sin, slen);
293         assert_return_code(rc, errno);
294
295         /*
296          * Open a second socket locally and try to bind to the same address.
297          */
298
299          /* Succeeds with port == 0 */
300
301         s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
302         assert_return_code(s, errno);
303
304         ZERO_STRUCT(sin2);
305         sin2.sin_family = AF_INET;
306
307         rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr);
308         assert_int_equal(rc, 1);
309
310         rc = bind(s2, (struct sockaddr *)&sin2, slen);
311         assert_return_code(rc, errno);
312
313         close(s2);
314
315         /* with same port as above - fail with EADDRINUSE */
316
317         s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
318         assert_return_code(s, errno);
319
320         ZERO_STRUCT(sin2);
321         sin2.sin_family = AF_INET;
322         sin2.sin_port = htons(12345);
323
324         rc = inet_pton(AF_INET, "127.0.0.20", &sin2.sin_addr);
325         assert_int_equal(rc, 1);
326
327         rc = bind(s2, (struct sockaddr *)&sin2, slen);
328         assert_int_equal(rc, -1);
329         assert_int_equal(errno, EADDRINUSE);
330
331         close(s);
332 }
333 #endif
334
335 #ifdef HAVE_BINDRESVPORT
336 static void test_bindresvport_ipv4(void **state)
337 {
338         struct torture_address addr = {
339                 .sa_socklen = sizeof(struct sockaddr_storage),
340         };
341         int rc;
342         int s;
343
344         (void) state; /* unused */
345
346         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
347         assert_return_code(s, errno);
348
349         addr.sa.in.sin_family = AF_INET;
350
351         rc = inet_pton(AF_INET, "127.0.0.20", &addr.sa.in.sin_addr);
352         assert_int_equal(rc, 1);
353
354         rc = bindresvport(s, &addr.sa.in);
355         assert_return_code(rc, errno);
356
357         addr = (struct torture_address) {
358                 .sa_socklen = sizeof(struct sockaddr_storage),
359                 .sa.in = (struct sockaddr_in) {
360                         .sin_family = AF_INET,
361                         .sin_port = htons(torture_server_port()),
362                 },
363         };
364
365         rc = inet_pton(AF_INET,
366                        torture_server_address(AF_INET),
367                        &addr.sa.in.sin_addr);
368         assert_int_equal(rc, 1);
369
370         rc = connect(s, &addr.sa.s, addr.sa_socklen);
371         assert_return_code(rc, errno);
372
373         close(s);
374 }
375
376 static void test_bindresvport_ipv4_null(void **state)
377 {
378         struct torture_address addr = {
379                 .sa_socklen = sizeof(struct sockaddr_in),
380         };
381         int rc;
382         int s;
383
384         (void) state; /* unused */
385
386         s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
387         assert_return_code(s, errno);
388
389         rc = bindresvport(s, NULL);
390         assert_return_code(rc, errno);
391
392         addr.sa.in.sin_family = AF_INET;
393         addr.sa.in.sin_port = htons(torture_server_port());
394         rc = inet_pton(AF_INET, torture_server_address(AF_INET), &addr.sa.in.sin_addr);
395         assert_int_equal(rc, 1);
396
397         rc = connect(s, &addr.sa.s, addr.sa_socklen);
398         assert_return_code(rc, errno);
399
400         close(s);
401 }
402 #endif /* HAVE_BINDRESVPORT */
403
404 #ifdef HAVE_IPV6
405 static void test_bind_on_ipv6_sock(void **state)
406 {
407         struct torture_address addr_in = {
408                 .sa_socklen = sizeof(struct sockaddr_in),
409         };
410         struct torture_address addr_un = {
411                 .sa_socklen = sizeof(struct sockaddr_un),
412         };
413         int rc;
414         int s;
415
416         (void) state; /* unused */
417
418         s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
419         assert_return_code(s, errno);
420
421         addr_un.sa.un.sun_family = AF_UNIX;
422         rc = bind(s, &addr_un.sa.s, addr_un.sa_socklen);
423         assert_int_equal(rc, -1);
424         /* FreeBSD uses EINVAL here... */
425         assert_true(errno == EAFNOSUPPORT || errno == EINVAL);
426
427         addr_in.sa.in.sin_family = AF_INET;
428         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
429         assert_int_equal(rc, -1);
430         assert_int_equal(errno, EINVAL);
431
432         addr_in.sa.in = (struct sockaddr_in) {
433                 .sin_family = AF_INET,
434         };
435
436         rc = inet_pton(AF_INET, "127.0.0.20", &addr_in.sa.in.sin_addr);
437         assert_int_equal(rc, 1);
438
439         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
440         assert_int_equal(rc, -1);
441         assert_int_equal(errno, EINVAL);
442
443         addr_in = (struct torture_address) {
444                 .sa_socklen = sizeof(struct sockaddr_in6),
445                 .sa.in = (struct sockaddr_in) {
446                         .sin_family = AF_INET,
447                 },
448         };
449
450         rc = bind(s, &addr_in.sa.s, addr_in.sa_socklen);
451         assert_int_equal(rc, -1);
452         assert_int_equal(errno, EAFNOSUPPORT);
453
454         close(s);
455 }
456
457 #ifdef HAVE_BINDRESVPORT
458 static void test_bindresvport_on_ipv6_sock(void **state)
459 {
460         struct sockaddr_in sin;
461         int rc;
462         int s;
463
464         (void) state; /* unused */
465
466         s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
467         assert_return_code(s, errno);
468
469         ZERO_STRUCT(sin);
470         sin.sin_family = AF_INET;
471
472         rc = inet_pton(AF_INET, "127.0.0.20", &sin.sin_addr);
473         assert_int_equal(rc, 1);
474
475         rc = bindresvport(s, &sin);
476         assert_int_equal(rc, -1);
477         assert_int_equal(errno, EINVAL);
478
479         close(s);
480 }
481
482 static void test_bindresvport_on_ipv6_sock_null(void **state)
483 {
484         int rc;
485         int s;
486
487         (void) state; /* unused */
488
489         s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
490         assert_return_code(s, errno);
491
492         rc = bindresvport(s, NULL);
493         assert_return_code(rc, errno);
494
495         close(s);
496 }
497 #endif /* HAVE_BINDRESVPORT */
498 #endif /* HAVE_IPV6 */
499
500 int main(void) {
501         int rc;
502
503         const struct CMUnitTest tcp_bind_tests[] = {
504                 cmocka_unit_test_setup_teardown(test_bind_ipv4,
505                                          setup_echo_srv_tcp_ipv4,
506                                          teardown),
507 #if 0 /* TODO */
508                 cmocka_unit_test_setup_teardown(test_bind_ipv4_addr_in_use,
509                                          setup_echo_srv_tcp_ipv4,
510                                          teardown),
511 #endif
512 #ifdef HAVE_BINDRESVPORT
513                 cmocka_unit_test_setup_teardown(test_bindresvport_ipv4,
514                                          setup_echo_srv_tcp_ipv4,
515                                          teardown),
516                 cmocka_unit_test_setup_teardown(test_bindresvport_ipv4_null,
517                                          setup_echo_srv_tcp_ipv4,
518                                          teardown),
519 #endif /* HAVE_BINDRESVPORT */
520 #ifdef HAVE_IPV6
521                 cmocka_unit_test_setup_teardown(test_bind_on_ipv6_sock,
522                                          setup_echo_srv_tcp_ipv6,
523                                          teardown),
524 #ifdef HAVE_BINDRESVPORT
525                 cmocka_unit_test_setup_teardown(test_bindresvport_on_ipv6_sock,
526                                          setup_echo_srv_tcp_ipv6,
527                                          teardown),
528                 cmocka_unit_test_setup_teardown(test_bindresvport_on_ipv6_sock_null,
529                                          setup_echo_srv_tcp_ipv6,
530                                          teardown),
531 #endif /* HAVE_BINDRESVPORT */
532 #endif /* HAVE_IPV6 */
533         };
534
535         rc = cmocka_run_group_tests(tcp_bind_tests, NULL, NULL);
536
537         return rc;
538 }