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 21static struct sockaddr_un unix_addr = { 22 .sun_family = AF_UNIX, 23 .sun_path = MAIN_SOCKET_FILE 24}; 25static struct sockaddr_un abstract_addr = { 26 .sun_family = AF_UNIX, 27 .sun_path = ABSTRACT_SOCKET_PATH 28}; 29static struct sockaddr_un peer_addr = { 30 .sun_family = AF_UNIX, 31 .sun_path = PEER_SOCKET_FILE 32}; 33static struct sockaddr_in ipv4_addr; 34static struct sockaddr_in ipv4_any_addr; 35static struct sockaddr_in6 ipv6_addr; 36static struct sockaddr_in6 ipv6_any_addr; 37 38static 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 74static 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 84static 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(SAFE_WRITE_ALL, 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(SAFE_WRITE_ALL, 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 119static 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 180static struct tst_test test = { 181 .test = test_bind, 182 .tcnt = ARRAY_SIZE(testcase_list), 183 .needs_tmpdir = 1, 184 .setup = setup, 185}; 186