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