• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 datagram 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_un peer_addr = {
30 	.sun_family = AF_UNIX,
31 	.sun_path = PEER_SOCKET_FILE
32 };
33 static struct sockaddr_in ipv4_addr;
34 static struct sockaddr_in ipv4_any_addr;
35 static struct sockaddr_in6 ipv6_addr;
36 static struct sockaddr_in6 ipv6_any_addr;
37 
38 static struct test_case testcase_list[] = {
39 	/* UNIX sockets */
40 	{SOCK_DGRAM, 0, (struct sockaddr *)&unix_addr, sizeof(unix_addr),
41 		"AF_UNIX pathname datagram"},
42 	{SOCK_DGRAM, 0, (struct sockaddr *)&abstract_addr,
43 		sizeof(abstract_addr), "AF_UNIX abstract datagram"},
44 
45 	/* IPv4 sockets */
46 	{SOCK_DGRAM, 0, (struct sockaddr *)&ipv4_addr, sizeof(ipv4_addr),
47 		"IPv4 loop UDP variant 1"},
48 	{SOCK_DGRAM, IPPROTO_UDP, (struct sockaddr *)&ipv4_addr,
49 		sizeof(ipv4_addr), "IPv4 loop UDP variant 2"},
50 	{SOCK_DGRAM, IPPROTO_UDPLITE, (struct sockaddr *)&ipv4_addr,
51 		sizeof(ipv4_addr), "IPv4 loop UDP-Lite"},
52 	{SOCK_DGRAM, 0, (struct sockaddr *)&ipv4_any_addr,
53 		sizeof(ipv4_any_addr), "IPv4 any UDP variant 1"},
54 	{SOCK_DGRAM, IPPROTO_UDP, (struct sockaddr *)&ipv4_any_addr,
55 		sizeof(ipv4_any_addr), "IPv4 any UDP variant 2"},
56 	{SOCK_DGRAM, IPPROTO_UDPLITE, (struct sockaddr *)&ipv4_any_addr,
57 		sizeof(ipv4_any_addr), "IPv4 any UDP-Lite"},
58 
59 	/* IPv6 sockets */
60 	{SOCK_DGRAM, 0, (struct sockaddr *)&ipv6_addr, sizeof(ipv6_addr),
61 		"IPv6 loop UDP variant 1"},
62 	{SOCK_DGRAM, IPPROTO_UDP, (struct sockaddr *)&ipv6_addr,
63 		sizeof(ipv6_addr), "IPv6 loop UDP variant 2"},
64 	{SOCK_DGRAM, IPPROTO_UDPLITE, (struct sockaddr *)&ipv6_addr,
65 		sizeof(ipv6_addr), "IPv6 loop UDP-Lite"},
66 	{SOCK_DGRAM, 0, (struct sockaddr *)&ipv6_any_addr,
67 		sizeof(ipv6_any_addr), "IPv6 any UDP variant 1"},
68 	{SOCK_DGRAM, IPPROTO_UDP, (struct sockaddr *)&ipv6_any_addr,
69 		sizeof(ipv6_any_addr), "IPv6 any UDP variant 2"},
70 	{SOCK_DGRAM, IPPROTO_UDPLITE, (struct sockaddr *)&ipv6_any_addr,
71 		sizeof(ipv6_any_addr), "IPv6 any UDP-Lite"}
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 = 0;
89 	const char *response;
90 
91 	sock = SAFE_SOCKET(tc->address->sa_family, tc->type, tc->protocol);
92 
93 	/*
94 	 * Both sides of AF_UNIX/SOCK_DGRAM socket must be bound for
95 	 * bidirectional communication
96 	 */
97 	if (tc->address->sa_family == AF_UNIX)
98 		SAFE_BIND(sock, (struct sockaddr *)&peer_addr,
99 			sizeof(struct sockaddr_un));
100 
101 	SAFE_CONNECT(sock, tc->address, tc->addrlen);
102 	SAFE_WRITE(1, sock, &request, sizeof(request));
103 	SAFE_READ(1, sock, &request, sizeof(request));
104 
105 	if (request < ARRAY_SIZE(testcase_list))
106 		response = testcase_list[request].description;
107 	else
108 		response = "Invalid request value";
109 
110 	SAFE_WRITE(1, sock, response, strlen(response) + 1);
111 	SAFE_CLOSE(sock);
112 
113 	if (tc->address->sa_family == AF_UNIX)
114 		SAFE_UNLINK(PEER_SOCKET_FILE);
115 
116 	return NULL;
117 }
118 
test_bind(unsigned int n)119 static void test_bind(unsigned int n)
120 {
121 	struct test_case tc_copy, *tc = testcase_list + n;
122 	struct sockaddr_storage listen_addr, remote_addr;
123 	struct sockaddr_un *tmp_addr;
124 	socklen_t remote_len = sizeof(struct sockaddr_storage);
125 	int sock, size;
126 	unsigned int rand_index;
127 	pthread_t thread_id;
128 	char buffer[BUFFER_SIZE];
129 	const char *exp_data;
130 
131 	tst_res(TINFO, "Testing %s", tc->description);
132 	sock = SAFE_SOCKET(tc->address->sa_family, tc->type, tc->protocol);
133 
134 	TST_EXP_PASS_SILENT(bind(sock, tc->address, tc->addrlen), "bind()");
135 
136 	if (!TST_PASS) {
137 		SAFE_CLOSE(sock);
138 		return;
139 	}
140 
141 	/*
142 	 * IPv4/IPv6 tests use wildcard addresses, resolve a valid connection
143 	 * address for peer thread
144 	 */
145 	memcpy(&tc_copy, tc, sizeof(struct test_case));
146 	tc_copy.addrlen = tst_get_connect_address(sock, &listen_addr);
147 	tc_copy.address = (struct sockaddr *)&listen_addr;
148 
149 	SAFE_PTHREAD_CREATE(&thread_id, NULL, peer_thread, &tc_copy);
150 	size = recvfrom(sock, &rand_index, sizeof(rand_index), 0,
151 		(struct sockaddr *)&remote_addr, &remote_len);
152 
153 	if (size != sizeof(rand_index)) {
154 		SAFE_CLOSE(sock);
155 		tst_brk(TBROK | TERRNO, "Error while waiting for connection");
156 	}
157 
158 	rand_index = rand() % ARRAY_SIZE(testcase_list);
159 	SAFE_SENDTO(1, sock, &rand_index, sizeof(rand_index), 0,
160 		(struct sockaddr *)&remote_addr, remote_len);
161 
162 	size = SAFE_READ(0, sock, buffer, BUFFER_SIZE - 1);
163 	buffer[size] = '\0';
164 	exp_data = testcase_list[rand_index].description;
165 
166 	if (!strcmp(buffer, exp_data))
167 		tst_res(TPASS, "Communication successful");
168 	else
169 		tst_res(TFAIL, "Received invalid data. Expected: \"%s\". "
170 			"Received: \"%s\"", exp_data, buffer);
171 
172 	SAFE_CLOSE(sock);
173 	pthread_join(thread_id, NULL);
174 	tmp_addr = (struct sockaddr_un *)tc->address;
175 
176 	if (tc->address->sa_family == AF_UNIX && tmp_addr->sun_path[0])
177 		SAFE_UNLINK(tmp_addr->sun_path);
178 }
179 
180 static struct tst_test test = {
181 	.test = test_bind,
182 	.tcnt = ARRAY_SIZE(testcase_list),
183 	.needs_tmpdir = 1,
184 	.setup = setup,
185 };
186