1 /* 2 * Tests for util/qemu-sockets.c 3 * 4 * Copyright 2018 Red Hat, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu-common.h" 23 #include "qemu/sockets.h" 24 #include "qapi/error.h" 25 #include "socket-helpers.h" 26 #include "monitor/monitor.h" 27 28 static void test_fd_is_socket_bad(void) 29 { 30 char *tmp = g_strdup("qemu-test-util-sockets-XXXXXX"); 31 int fd = mkstemp(tmp); 32 if (fd != 0) { 33 unlink(tmp); 34 } 35 g_free(tmp); 36 37 g_assert(fd >= 0); 38 39 g_assert(!fd_is_socket(fd)); 40 close(fd); 41 } 42 43 static void test_fd_is_socket_good(void) 44 { 45 int fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 46 47 g_assert(fd >= 0); 48 49 g_assert(fd_is_socket(fd)); 50 close(fd); 51 } 52 53 static int mon_fd = -1; 54 static const char *mon_fdname; 55 __thread Monitor *cur_mon; 56 57 int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) 58 { 59 g_assert(cur_mon); 60 g_assert(mon == cur_mon); 61 if (mon_fd == -1 || !g_str_equal(mon_fdname, fdname)) { 62 error_setg(errp, "No fd named %s", fdname); 63 return -1; 64 } 65 return dup(mon_fd); 66 } 67 68 /* 69 * Syms of stubs in libqemuutil.a are discarded at .o file 70 * granularity. To replace monitor_get_fd() and monitor_cur(), we 71 * must ensure that we also replace any other symbol that is used in 72 * the binary and would be taken from the same stub object file, 73 * otherwise we get duplicate syms at link time. 74 */ 75 Monitor *monitor_cur(void) { return cur_mon; } 76 int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } 77 78 #ifndef _WIN32 79 static void test_socket_fd_pass_name_good(void) 80 { 81 SocketAddress addr; 82 int fd; 83 84 cur_mon = g_malloc(1); /* Fake a monitor */ 85 mon_fdname = "myfd"; 86 mon_fd = qemu_socket(AF_INET, SOCK_STREAM, 0); 87 g_assert_cmpint(mon_fd, >, STDERR_FILENO); 88 89 addr.type = SOCKET_ADDRESS_TYPE_FD; 90 addr.u.fd.str = g_strdup(mon_fdname); 91 92 fd = socket_connect(&addr, &error_abort); 93 g_assert_cmpint(fd, !=, -1); 94 g_assert_cmpint(fd, !=, mon_fd); 95 close(fd); 96 97 fd = socket_listen(&addr, 1, &error_abort); 98 g_assert_cmpint(fd, !=, -1); 99 g_assert_cmpint(fd, !=, mon_fd); 100 close(fd); 101 102 g_free(addr.u.fd.str); 103 mon_fdname = NULL; 104 close(mon_fd); 105 mon_fd = -1; 106 g_free(cur_mon); 107 cur_mon = NULL; 108 } 109 110 static void test_socket_fd_pass_name_bad(void) 111 { 112 SocketAddress addr; 113 Error *err = NULL; 114 int fd; 115 116 cur_mon = g_malloc(1); /* Fake a monitor */ 117 mon_fdname = "myfd"; 118 mon_fd = dup(STDOUT_FILENO); 119 g_assert_cmpint(mon_fd, >, STDERR_FILENO); 120 121 addr.type = SOCKET_ADDRESS_TYPE_FD; 122 addr.u.fd.str = g_strdup(mon_fdname); 123 124 fd = socket_connect(&addr, &err); 125 g_assert_cmpint(fd, ==, -1); 126 error_free_or_abort(&err); 127 128 fd = socket_listen(&addr, 1, &err); 129 g_assert_cmpint(fd, ==, -1); 130 error_free_or_abort(&err); 131 132 g_free(addr.u.fd.str); 133 mon_fdname = NULL; 134 close(mon_fd); 135 mon_fd = -1; 136 g_free(cur_mon); 137 cur_mon = NULL; 138 } 139 140 static void test_socket_fd_pass_name_nomon(void) 141 { 142 SocketAddress addr; 143 Error *err = NULL; 144 int fd; 145 146 g_assert(cur_mon == NULL); 147 148 addr.type = SOCKET_ADDRESS_TYPE_FD; 149 addr.u.fd.str = g_strdup("myfd"); 150 151 fd = socket_connect(&addr, &err); 152 g_assert_cmpint(fd, ==, -1); 153 error_free_or_abort(&err); 154 155 fd = socket_listen(&addr, 1, &err); 156 g_assert_cmpint(fd, ==, -1); 157 error_free_or_abort(&err); 158 159 g_free(addr.u.fd.str); 160 } 161 162 163 static void test_socket_fd_pass_num_good(void) 164 { 165 SocketAddress addr; 166 int fd, sfd; 167 168 g_assert(cur_mon == NULL); 169 sfd = qemu_socket(AF_INET, SOCK_STREAM, 0); 170 g_assert_cmpint(sfd, >, STDERR_FILENO); 171 172 addr.type = SOCKET_ADDRESS_TYPE_FD; 173 addr.u.fd.str = g_strdup_printf("%d", sfd); 174 175 fd = socket_connect(&addr, &error_abort); 176 g_assert_cmpint(fd, ==, sfd); 177 178 fd = socket_listen(&addr, 1, &error_abort); 179 g_assert_cmpint(fd, ==, sfd); 180 181 g_free(addr.u.fd.str); 182 close(sfd); 183 } 184 185 static void test_socket_fd_pass_num_bad(void) 186 { 187 SocketAddress addr; 188 Error *err = NULL; 189 int fd, sfd; 190 191 g_assert(cur_mon == NULL); 192 sfd = dup(STDOUT_FILENO); 193 194 addr.type = SOCKET_ADDRESS_TYPE_FD; 195 addr.u.fd.str = g_strdup_printf("%d", sfd); 196 197 fd = socket_connect(&addr, &err); 198 g_assert_cmpint(fd, ==, -1); 199 error_free_or_abort(&err); 200 201 fd = socket_listen(&addr, 1, &err); 202 g_assert_cmpint(fd, ==, -1); 203 error_free_or_abort(&err); 204 205 g_free(addr.u.fd.str); 206 close(sfd); 207 } 208 209 static void test_socket_fd_pass_num_nocli(void) 210 { 211 SocketAddress addr; 212 Error *err = NULL; 213 int fd; 214 215 cur_mon = g_malloc(1); /* Fake a monitor */ 216 217 addr.type = SOCKET_ADDRESS_TYPE_FD; 218 addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO); 219 220 fd = socket_connect(&addr, &err); 221 g_assert_cmpint(fd, ==, -1); 222 error_free_or_abort(&err); 223 224 fd = socket_listen(&addr, 1, &err); 225 g_assert_cmpint(fd, ==, -1); 226 error_free_or_abort(&err); 227 228 g_free(addr.u.fd.str); 229 } 230 #endif 231 232 #ifdef __linux__ 233 static gpointer unix_server_thread_func(gpointer user_data) 234 { 235 SocketAddress *addr = user_data; 236 int fd; 237 int connfd; 238 struct sockaddr_un un; 239 socklen_t len = sizeof(un); 240 241 fd = socket_listen(addr, 1, &error_abort); 242 g_assert_cmpint(fd, >=, 0); 243 g_assert(fd_is_socket(fd)); 244 245 connfd = accept(fd, (struct sockaddr *)&un, &len); 246 g_assert_cmpint(connfd, !=, -1); 247 close(connfd); 248 249 close(fd); 250 return NULL; 251 } 252 253 static gpointer unix_client_thread_func(gpointer user_data) 254 { 255 SocketAddress *addr = user_data; 256 int fd; 257 258 fd = socket_connect(addr, &error_abort); 259 g_assert_cmpint(fd, >=, 0); 260 close(fd); 261 return NULL; 262 } 263 264 static void test_socket_unix_abstract_good(void) 265 { 266 SocketAddress addr; 267 268 addr.type = SOCKET_ADDRESS_TYPE_UNIX; 269 addr.u.q_unix.path = g_strdup_printf("unix-%d-%u", 270 getpid(), g_random_int()); 271 addr.u.q_unix.has_abstract = true; 272 addr.u.q_unix.abstract = true; 273 274 /* non tight socklen serv and cli */ 275 276 addr.u.q_unix.has_tight = false; 277 addr.u.q_unix.tight = false; 278 279 GThread *serv = g_thread_new("abstract_unix_server", 280 unix_server_thread_func, 281 &addr); 282 283 sleep(1); 284 285 GThread *cli = g_thread_new("abstract_unix_client", 286 unix_client_thread_func, 287 &addr); 288 289 g_thread_join(cli); 290 g_thread_join(serv); 291 292 /* tight socklen serv and cli */ 293 294 addr.u.q_unix.has_tight = true; 295 addr.u.q_unix.tight = true; 296 297 serv = g_thread_new("abstract_unix_server", 298 unix_server_thread_func, 299 &addr); 300 301 sleep(1); 302 303 cli = g_thread_new("abstract_unix_client", 304 unix_client_thread_func, 305 &addr); 306 307 g_thread_join(cli); 308 g_thread_join(serv); 309 310 g_free(addr.u.q_unix.path); 311 } 312 #endif 313 314 int main(int argc, char **argv) 315 { 316 bool has_ipv4, has_ipv6; 317 318 qemu_init_main_loop(&error_abort); 319 socket_init(); 320 321 g_test_init(&argc, &argv, NULL); 322 323 /* We're creating actual IPv4/6 sockets, so we should 324 * check if the host running tests actually supports 325 * each protocol to avoid breaking tests on machines 326 * with either IPv4 or IPv6 disabled. 327 */ 328 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 329 g_printerr("socket_check_protocol_support() failed\n"); 330 goto end; 331 } 332 333 if (has_ipv4) { 334 g_test_add_func("/util/socket/is-socket/bad", 335 test_fd_is_socket_bad); 336 g_test_add_func("/util/socket/is-socket/good", 337 test_fd_is_socket_good); 338 #ifndef _WIN32 339 g_test_add_func("/socket/fd-pass/name/good", 340 test_socket_fd_pass_name_good); 341 g_test_add_func("/socket/fd-pass/name/bad", 342 test_socket_fd_pass_name_bad); 343 g_test_add_func("/socket/fd-pass/name/nomon", 344 test_socket_fd_pass_name_nomon); 345 g_test_add_func("/socket/fd-pass/num/good", 346 test_socket_fd_pass_num_good); 347 g_test_add_func("/socket/fd-pass/num/bad", 348 test_socket_fd_pass_num_bad); 349 g_test_add_func("/socket/fd-pass/num/nocli", 350 test_socket_fd_pass_num_nocli); 351 #endif 352 } 353 354 #ifdef __linux__ 355 g_test_add_func("/util/socket/unix-abstract/good", 356 test_socket_unix_abstract_good); 357 #endif 358 359 end: 360 return g_test_run(); 361 } 362