1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2019 Martin Doucha <mdoucha@suse.cz>
4 */
5
6 /*
7 * Create and bind socket for various standard stream protocols.
8 * Then connect to it and send some test data.
9 */
10
11 #include <string.h>
12 #include <stdlib.h>
13 #include <time.h>
14 #include <pthread.h>
15
16 #include "tst_test.h"
17 #include "tst_net.h"
18 #include "tst_safe_pthread.h"
19 #include "libbind.h"
20
21 static struct sockaddr_un unix_addr = {
22 .sun_family = AF_UNIX,
23 .sun_path = MAIN_SOCKET_FILE
24 };
25 static struct sockaddr_un abstract_addr = {
26 .sun_family = AF_UNIX,
27 .sun_path = ABSTRACT_SOCKET_PATH
28 };
29 static struct sockaddr_in ipv4_addr;
30 static struct sockaddr_in ipv4_any_addr;
31 static struct sockaddr_in6 ipv6_addr;
32 static struct sockaddr_in6 ipv6_any_addr;
33
34 static struct test_case testcase_list[] = {
35 /* UNIX sockets */
36 {SOCK_STREAM, 0, (struct sockaddr *)&unix_addr, sizeof(unix_addr),
37 "AF_UNIX pathname stream"},
38 {SOCK_SEQPACKET, 0, (struct sockaddr *)&unix_addr, sizeof(unix_addr),
39 "AF_UNIX pathname seqpacket"},
40 {SOCK_STREAM, 0, (struct sockaddr *)&abstract_addr,
41 sizeof(abstract_addr), "AF_UNIX abstract stream"},
42 {SOCK_SEQPACKET, 0, (struct sockaddr *)&abstract_addr,
43 sizeof(abstract_addr), "AF_UNIX abstract seqpacket"},
44
45 /* IPv4 sockets */
46 {SOCK_STREAM, 0, (struct sockaddr *)&ipv4_addr, sizeof(ipv4_addr),
47 "IPv4 loop TCP variant 1"},
48 {SOCK_STREAM, IPPROTO_TCP, (struct sockaddr *)&ipv4_addr,
49 sizeof(ipv4_addr), "IPv4 loop TCP variant 2"},
50 {SOCK_STREAM, IPPROTO_SCTP, (struct sockaddr *)&ipv4_addr,
51 sizeof(ipv4_addr), "IPv4 loop SCTP"},
52 {SOCK_STREAM, 0, (struct sockaddr *)&ipv4_any_addr,
53 sizeof(ipv4_any_addr), "IPv4 any TCP variant 1"},
54 {SOCK_STREAM, IPPROTO_TCP, (struct sockaddr *)&ipv4_any_addr,
55 sizeof(ipv4_any_addr), "IPv4 any TCP variant 2"},
56 {SOCK_STREAM, IPPROTO_SCTP, (struct sockaddr *)&ipv4_any_addr,
57 sizeof(ipv4_any_addr), "IPv4 any SCTP"},
58
59 /* IPv6 sockets */
60 {SOCK_STREAM, 0, (struct sockaddr *)&ipv6_addr, sizeof(ipv6_addr),
61 "IPv6 loop TCP variant 1"},
62 {SOCK_STREAM, IPPROTO_TCP, (struct sockaddr *)&ipv6_addr,
63 sizeof(ipv6_addr), "IPv6 loop TCP variant 2"},
64 {SOCK_STREAM, IPPROTO_SCTP, (struct sockaddr *)&ipv6_addr,
65 sizeof(ipv6_addr), "IPv6 loop SCTP"},
66 {SOCK_STREAM, 0, (struct sockaddr *)&ipv6_any_addr,
67 sizeof(ipv6_any_addr), "IPv6 any TCP variant 1"},
68 {SOCK_STREAM, IPPROTO_TCP, (struct sockaddr *)&ipv6_any_addr,
69 sizeof(ipv6_any_addr), "IPv6 any TCP variant 2"},
70 {SOCK_STREAM, IPPROTO_SCTP, (struct sockaddr *)&ipv6_any_addr,
71 sizeof(ipv6_any_addr), "IPv6 any SCTP"}
72 };
73
setup(void)74 static void setup(void)
75 {
76 srand(time(0));
77
78 tst_init_sockaddr_inet(&ipv4_addr, IPV4_ADDRESS, 0);
79 tst_init_sockaddr_inet_bin(&ipv4_any_addr, INADDR_ANY, 0);
80 tst_init_sockaddr_inet6_bin(&ipv6_addr, &in6addr_loopback, 0);
81 tst_init_sockaddr_inet6_bin(&ipv6_any_addr, &in6addr_any, 0);
82 }
83
peer_thread(void * tc_ptr)84 static void *peer_thread(void *tc_ptr)
85 {
86 const struct test_case *tc = tc_ptr;
87 int sock;
88 unsigned int request;
89 const char *response;
90
91 sock = SAFE_SOCKET(tc->address->sa_family, tc->type, tc->protocol);
92 SAFE_CONNECT(sock, tc->address, tc->addrlen);
93 SAFE_READ(1, sock, &request, sizeof(request));
94
95 if (request < ARRAY_SIZE(testcase_list))
96 response = testcase_list[request].description;
97 else
98 response = "Invalid request value";
99
100 SAFE_WRITE(1, sock, response, strlen(response) + 1);
101 SAFE_CLOSE(sock);
102 return NULL;
103 }
104
test_bind(unsigned int n)105 static void test_bind(unsigned int n)
106 {
107 struct test_case tc_copy, *tc = testcase_list + n;
108 struct sockaddr_storage listen_addr, remote_addr;
109 struct sockaddr_un *tmp_addr;
110 socklen_t remote_len = sizeof(struct sockaddr_storage);
111 int listen_sock, sock, size;
112 unsigned int rand_index;
113 pthread_t thread_id;
114 char buffer[BUFFER_SIZE];
115 const char *exp_data;
116
117 tst_res(TINFO, "Testing %s", tc->description);
118 listen_sock = SAFE_SOCKET(tc->address->sa_family, tc->type,
119 tc->protocol);
120
121 TST_EXP_PASS_SILENT(bind(listen_sock, tc->address, tc->addrlen), "bind()");
122
123 if (!TST_PASS) {
124 SAFE_CLOSE(listen_sock);
125 return;
126 }
127
128 /*
129 * IPv4/IPv6 tests use wildcard addresses, resolve a valid connection
130 * address for peer thread
131 */
132 memcpy(&tc_copy, tc, sizeof(struct test_case));
133 tc_copy.addrlen = tst_get_connect_address(listen_sock, &listen_addr);
134 tc_copy.address = (struct sockaddr *)&listen_addr;
135
136 SAFE_LISTEN(listen_sock, 1);
137 SAFE_PTHREAD_CREATE(&thread_id, NULL, peer_thread, &tc_copy);
138 sock = SAFE_ACCEPT(listen_sock, (struct sockaddr *)&remote_addr,
139 &remote_len);
140
141 rand_index = rand() % ARRAY_SIZE(testcase_list);
142 SAFE_WRITE(1, sock, &rand_index, sizeof(rand_index));
143
144 size = SAFE_READ(0, sock, buffer, BUFFER_SIZE - 1);
145 buffer[size] = '\0';
146 exp_data = testcase_list[rand_index].description;
147
148 if (!strcmp(buffer, exp_data))
149 tst_res(TPASS, "Communication successful");
150 else
151 tst_res(TFAIL, "Received invalid data. Expected: \"%s\". "
152 "Received: \"%s\"", exp_data, buffer);
153
154 SAFE_CLOSE(sock);
155 SAFE_CLOSE(listen_sock);
156 pthread_join(thread_id, NULL);
157 tmp_addr = (struct sockaddr_un *)tc->address;
158
159 if (tc->address->sa_family == AF_UNIX && tmp_addr->sun_path[0])
160 SAFE_UNLINK(tmp_addr->sun_path);
161 }
162
163 static struct tst_test test = {
164 .test = test_bind,
165 .tcnt = ARRAY_SIZE(testcase_list),
166 .needs_tmpdir = 1,
167 .setup = setup,
168 };
169