1 /* 2 * QEMU I/O channel sockets test 3 * 4 * Copyright (c) 2015-2016 Red Hat, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library 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 GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "io/channel-socket.h" 23 #include "io/channel-util.h" 24 #include "io-channel-helpers.h" 25 #include "socket-helpers.h" 26 #include "qapi/error.h" 27 #include "qemu/module.h" 28 #include "qemu/main-loop.h" 29 30 31 static void test_io_channel_set_socket_bufs(QIOChannel *src, 32 QIOChannel *dst) 33 { 34 int buflen = 64 * 1024; 35 36 /* 37 * Make the socket buffers small so that we see 38 * the effects of partial reads/writes 39 */ 40 setsockopt(((QIOChannelSocket *)src)->fd, 41 SOL_SOCKET, SO_SNDBUF, 42 (char *)&buflen, 43 sizeof(buflen)); 44 45 setsockopt(((QIOChannelSocket *)dst)->fd, 46 SOL_SOCKET, SO_SNDBUF, 47 (char *)&buflen, 48 sizeof(buflen)); 49 } 50 51 52 static void test_io_channel_setup_sync(SocketAddress *listen_addr, 53 SocketAddress *connect_addr, 54 QIOChannel **srv, 55 QIOChannel **src, 56 QIOChannel **dst) 57 { 58 QIOChannelSocket *lioc; 59 60 lioc = qio_channel_socket_new(); 61 qio_channel_socket_listen_sync(lioc, listen_addr, 1, &error_abort); 62 63 if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) { 64 SocketAddress *laddr = qio_channel_socket_get_local_address( 65 lioc, &error_abort); 66 67 g_free(connect_addr->u.inet.port); 68 connect_addr->u.inet.port = g_strdup(laddr->u.inet.port); 69 70 qapi_free_SocketAddress(laddr); 71 } 72 73 *src = QIO_CHANNEL(qio_channel_socket_new()); 74 qio_channel_socket_connect_sync( 75 QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort); 76 qio_channel_set_delay(*src, false); 77 78 qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); 79 *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); 80 g_assert(*dst); 81 82 test_io_channel_set_socket_bufs(*src, *dst); 83 84 *srv = QIO_CHANNEL(lioc); 85 } 86 87 88 struct TestIOChannelData { 89 bool err; 90 GMainLoop *loop; 91 }; 92 93 94 static void test_io_channel_complete(QIOTask *task, 95 gpointer opaque) 96 { 97 struct TestIOChannelData *data = opaque; 98 data->err = qio_task_propagate_error(task, NULL); 99 g_main_loop_quit(data->loop); 100 } 101 102 103 static void test_io_channel_setup_async(SocketAddress *listen_addr, 104 SocketAddress *connect_addr, 105 QIOChannel **srv, 106 QIOChannel **src, 107 QIOChannel **dst) 108 { 109 QIOChannelSocket *lioc; 110 struct TestIOChannelData data; 111 112 data.loop = g_main_loop_new(g_main_context_default(), 113 TRUE); 114 115 lioc = qio_channel_socket_new(); 116 qio_channel_socket_listen_async( 117 lioc, listen_addr, 1, 118 test_io_channel_complete, &data, NULL, NULL); 119 120 g_main_loop_run(data.loop); 121 g_main_context_iteration(g_main_context_default(), FALSE); 122 123 g_assert(!data.err); 124 125 if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) { 126 SocketAddress *laddr = qio_channel_socket_get_local_address( 127 lioc, &error_abort); 128 129 g_free(connect_addr->u.inet.port); 130 connect_addr->u.inet.port = g_strdup(laddr->u.inet.port); 131 132 qapi_free_SocketAddress(laddr); 133 } 134 135 *src = QIO_CHANNEL(qio_channel_socket_new()); 136 137 qio_channel_socket_connect_async( 138 QIO_CHANNEL_SOCKET(*src), connect_addr, 139 test_io_channel_complete, &data, NULL, NULL); 140 141 g_main_loop_run(data.loop); 142 g_main_context_iteration(g_main_context_default(), FALSE); 143 144 g_assert(!data.err); 145 146 qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); 147 *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); 148 g_assert(*dst); 149 150 qio_channel_set_delay(*src, false); 151 test_io_channel_set_socket_bufs(*src, *dst); 152 153 *srv = QIO_CHANNEL(lioc); 154 155 g_main_loop_unref(data.loop); 156 } 157 158 159 static void test_io_channel_socket_path_exists(SocketAddress *addr, 160 bool expectExists) 161 { 162 if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) { 163 return; 164 } 165 166 g_assert(g_file_test(addr->u.q_unix.path, 167 G_FILE_TEST_EXISTS) == expectExists); 168 } 169 170 171 static void test_io_channel(bool async, 172 SocketAddress *listen_addr, 173 SocketAddress *connect_addr, 174 bool passFD) 175 { 176 QIOChannel *src, *dst, *srv; 177 QIOChannelTest *test; 178 if (async) { 179 test_io_channel_setup_async(listen_addr, connect_addr, 180 &srv, &src, &dst); 181 182 #ifndef _WIN32 183 g_assert(!passFD || 184 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 185 g_assert(!passFD || 186 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 187 #endif 188 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 189 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 190 191 test_io_channel_socket_path_exists(listen_addr, true); 192 193 test = qio_channel_test_new(); 194 qio_channel_test_run_threads(test, true, src, dst); 195 qio_channel_test_validate(test); 196 197 test_io_channel_socket_path_exists(listen_addr, true); 198 199 /* unref without close, to ensure finalize() cleans up */ 200 201 object_unref(OBJECT(src)); 202 object_unref(OBJECT(dst)); 203 test_io_channel_socket_path_exists(listen_addr, true); 204 205 object_unref(OBJECT(srv)); 206 test_io_channel_socket_path_exists(listen_addr, false); 207 208 test_io_channel_setup_async(listen_addr, connect_addr, 209 &srv, &src, &dst); 210 211 #ifndef _WIN32 212 g_assert(!passFD || 213 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 214 g_assert(!passFD || 215 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 216 #endif 217 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 218 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 219 220 test = qio_channel_test_new(); 221 qio_channel_test_run_threads(test, false, src, dst); 222 qio_channel_test_validate(test); 223 224 /* close before unref, to ensure finalize copes with already closed */ 225 226 qio_channel_close(src, &error_abort); 227 qio_channel_close(dst, &error_abort); 228 test_io_channel_socket_path_exists(listen_addr, true); 229 230 object_unref(OBJECT(src)); 231 object_unref(OBJECT(dst)); 232 test_io_channel_socket_path_exists(listen_addr, true); 233 234 qio_channel_close(srv, &error_abort); 235 test_io_channel_socket_path_exists(listen_addr, false); 236 237 object_unref(OBJECT(srv)); 238 test_io_channel_socket_path_exists(listen_addr, false); 239 } else { 240 test_io_channel_setup_sync(listen_addr, connect_addr, 241 &srv, &src, &dst); 242 243 #ifndef _WIN32 244 g_assert(!passFD || 245 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 246 g_assert(!passFD || 247 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 248 #endif 249 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 250 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 251 252 test_io_channel_socket_path_exists(listen_addr, true); 253 254 test = qio_channel_test_new(); 255 qio_channel_test_run_threads(test, true, src, dst); 256 qio_channel_test_validate(test); 257 258 test_io_channel_socket_path_exists(listen_addr, true); 259 260 /* unref without close, to ensure finalize() cleans up */ 261 262 object_unref(OBJECT(src)); 263 object_unref(OBJECT(dst)); 264 test_io_channel_socket_path_exists(listen_addr, true); 265 266 object_unref(OBJECT(srv)); 267 test_io_channel_socket_path_exists(listen_addr, false); 268 269 test_io_channel_setup_sync(listen_addr, connect_addr, 270 &srv, &src, &dst); 271 272 #ifndef _WIN32 273 g_assert(!passFD || 274 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 275 g_assert(!passFD || 276 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 277 #endif 278 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 279 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 280 281 test = qio_channel_test_new(); 282 qio_channel_test_run_threads(test, false, src, dst); 283 qio_channel_test_validate(test); 284 285 test_io_channel_socket_path_exists(listen_addr, true); 286 287 /* close before unref, to ensure finalize copes with already closed */ 288 289 qio_channel_close(src, &error_abort); 290 qio_channel_close(dst, &error_abort); 291 test_io_channel_socket_path_exists(listen_addr, true); 292 293 object_unref(OBJECT(src)); 294 object_unref(OBJECT(dst)); 295 test_io_channel_socket_path_exists(listen_addr, true); 296 297 qio_channel_close(srv, &error_abort); 298 test_io_channel_socket_path_exists(listen_addr, false); 299 300 object_unref(OBJECT(srv)); 301 test_io_channel_socket_path_exists(listen_addr, false); 302 } 303 } 304 305 306 static void test_io_channel_ipv4(bool async) 307 { 308 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 309 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 310 311 listen_addr->type = SOCKET_ADDRESS_TYPE_INET; 312 listen_addr->u.inet = (InetSocketAddress) { 313 .host = g_strdup("127.0.0.1"), 314 .port = NULL, /* Auto-select */ 315 }; 316 317 connect_addr->type = SOCKET_ADDRESS_TYPE_INET; 318 connect_addr->u.inet = (InetSocketAddress) { 319 .host = g_strdup("127.0.0.1"), 320 .port = NULL, /* Filled in later */ 321 }; 322 323 test_io_channel(async, listen_addr, connect_addr, false); 324 325 qapi_free_SocketAddress(listen_addr); 326 qapi_free_SocketAddress(connect_addr); 327 } 328 329 330 static void test_io_channel_ipv4_sync(void) 331 { 332 return test_io_channel_ipv4(false); 333 } 334 335 336 static void test_io_channel_ipv4_async(void) 337 { 338 return test_io_channel_ipv4(true); 339 } 340 341 342 static void test_io_channel_ipv6(bool async) 343 { 344 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 345 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 346 347 listen_addr->type = SOCKET_ADDRESS_TYPE_INET; 348 listen_addr->u.inet = (InetSocketAddress) { 349 .host = g_strdup("::1"), 350 .port = NULL, /* Auto-select */ 351 }; 352 353 connect_addr->type = SOCKET_ADDRESS_TYPE_INET; 354 connect_addr->u.inet = (InetSocketAddress) { 355 .host = g_strdup("::1"), 356 .port = NULL, /* Filled in later */ 357 }; 358 359 test_io_channel(async, listen_addr, connect_addr, false); 360 361 qapi_free_SocketAddress(listen_addr); 362 qapi_free_SocketAddress(connect_addr); 363 } 364 365 366 static void test_io_channel_ipv6_sync(void) 367 { 368 return test_io_channel_ipv6(false); 369 } 370 371 372 static void test_io_channel_ipv6_async(void) 373 { 374 return test_io_channel_ipv6(true); 375 } 376 377 378 static void test_io_channel_unix(bool async) 379 { 380 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 381 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 382 383 #define TEST_SOCKET "test-io-channel-socket.sock" 384 listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 385 listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 386 387 connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 388 connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 389 390 test_io_channel(async, listen_addr, connect_addr, true); 391 392 qapi_free_SocketAddress(listen_addr); 393 qapi_free_SocketAddress(connect_addr); 394 } 395 396 397 static void test_io_channel_unix_sync(void) 398 { 399 return test_io_channel_unix(false); 400 } 401 402 403 static void test_io_channel_unix_async(void) 404 { 405 return test_io_channel_unix(true); 406 } 407 408 #ifndef _WIN32 409 static void test_io_channel_unix_fd_pass(void) 410 { 411 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 412 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 413 QIOChannel *src, *dst, *srv; 414 int testfd; 415 int fdsend[3]; 416 int *fdrecv = NULL; 417 size_t nfdrecv = 0; 418 size_t i; 419 char bufsend[12], bufrecv[12]; 420 struct iovec iosend[1], iorecv[1]; 421 422 #define TEST_SOCKET "test-io-channel-socket.sock" 423 #define TEST_FILE "test-io-channel-socket.txt" 424 425 testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700); 426 g_assert(testfd != -1); 427 fdsend[0] = testfd; 428 fdsend[1] = testfd; 429 fdsend[2] = testfd; 430 431 listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 432 listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 433 434 connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 435 connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 436 437 test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); 438 439 memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend)); 440 441 iosend[0].iov_base = bufsend; 442 iosend[0].iov_len = G_N_ELEMENTS(bufsend); 443 444 iorecv[0].iov_base = bufrecv; 445 iorecv[0].iov_len = G_N_ELEMENTS(bufrecv); 446 447 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 448 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 449 450 qio_channel_writev_full(src, 451 iosend, 452 G_N_ELEMENTS(iosend), 453 fdsend, 454 G_N_ELEMENTS(fdsend), 455 0, 456 &error_abort); 457 458 qio_channel_readv_full(dst, 459 iorecv, 460 G_N_ELEMENTS(iorecv), 461 &fdrecv, 462 &nfdrecv, 463 &error_abort); 464 465 g_assert(nfdrecv == G_N_ELEMENTS(fdsend)); 466 /* Each recvd FD should be different from sent FD */ 467 for (i = 0; i < nfdrecv; i++) { 468 g_assert_cmpint(fdrecv[i], !=, testfd); 469 } 470 /* Each recvd FD should be different from each other */ 471 g_assert_cmpint(fdrecv[0], !=, fdrecv[1]); 472 g_assert_cmpint(fdrecv[0], !=, fdrecv[2]); 473 g_assert_cmpint(fdrecv[1], !=, fdrecv[2]); 474 475 /* Check the I/O buf we sent at the same time matches */ 476 g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); 477 478 /* Write some data into the FD we received */ 479 g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) == 480 G_N_ELEMENTS(bufsend)); 481 482 /* Read data from the original FD and make sure it matches */ 483 memset(bufrecv, 0, G_N_ELEMENTS(bufrecv)); 484 g_assert(lseek(testfd, 0, SEEK_SET) == 0); 485 g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) == 486 G_N_ELEMENTS(bufrecv)); 487 g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); 488 489 object_unref(OBJECT(src)); 490 object_unref(OBJECT(dst)); 491 object_unref(OBJECT(srv)); 492 qapi_free_SocketAddress(listen_addr); 493 qapi_free_SocketAddress(connect_addr); 494 unlink(TEST_SOCKET); 495 unlink(TEST_FILE); 496 close(testfd); 497 for (i = 0; i < nfdrecv; i++) { 498 close(fdrecv[i]); 499 } 500 g_free(fdrecv); 501 } 502 #endif /* _WIN32 */ 503 504 static void test_io_channel_unix_listen_cleanup(void) 505 { 506 QIOChannelSocket *ioc; 507 struct sockaddr_un un; 508 int sock; 509 510 #define TEST_SOCKET "test-io-channel-socket.sock" 511 512 ioc = qio_channel_socket_new(); 513 514 /* Manually bind ioc without calling the qio api to avoid setting 515 * the LISTEN feature */ 516 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); 517 memset(&un, 0, sizeof(un)); 518 un.sun_family = AF_UNIX; 519 snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET); 520 unlink(TEST_SOCKET); 521 bind(sock, (struct sockaddr *)&un, sizeof(un)); 522 ioc->fd = sock; 523 ioc->localAddrLen = sizeof(ioc->localAddr); 524 getsockname(sock, (struct sockaddr *)&ioc->localAddr, 525 &ioc->localAddrLen); 526 527 g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS)); 528 object_unref(OBJECT(ioc)); 529 g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS)); 530 531 unlink(TEST_SOCKET); 532 } 533 534 static void test_io_channel_ipv4_fd(void) 535 { 536 QIOChannel *ioc; 537 int fd = -1; 538 struct sockaddr_in sa = { 539 .sin_family = AF_INET, 540 .sin_addr = { 541 .s_addr = htonl(INADDR_LOOPBACK), 542 } 543 /* Leave port unset for auto-assign */ 544 }; 545 socklen_t salen = sizeof(sa); 546 547 fd = socket(AF_INET, SOCK_STREAM, 0); 548 g_assert_cmpint(fd, >, -1); 549 550 g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0); 551 552 ioc = qio_channel_new_fd(fd, &error_abort); 553 554 g_assert_cmpstr(object_get_typename(OBJECT(ioc)), 555 ==, 556 TYPE_QIO_CHANNEL_SOCKET); 557 558 object_unref(OBJECT(ioc)); 559 } 560 561 562 int main(int argc, char **argv) 563 { 564 bool has_ipv4, has_ipv6, has_afunix; 565 566 module_call_init(MODULE_INIT_QOM); 567 qemu_init_main_loop(&error_abort); 568 socket_init(); 569 570 g_test_init(&argc, &argv, NULL); 571 572 /* We're creating actual IPv4/6 sockets, so we should 573 * check if the host running tests actually supports 574 * each protocol to avoid breaking tests on machines 575 * with either IPv4 or IPv6 disabled. 576 */ 577 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 578 g_printerr("socket_check_protocol_support() failed\n"); 579 goto end; 580 } 581 582 if (has_ipv4) { 583 g_test_add_func("/io/channel/socket/ipv4-sync", 584 test_io_channel_ipv4_sync); 585 g_test_add_func("/io/channel/socket/ipv4-async", 586 test_io_channel_ipv4_async); 587 g_test_add_func("/io/channel/socket/ipv4-fd", 588 test_io_channel_ipv4_fd); 589 } 590 if (has_ipv6) { 591 g_test_add_func("/io/channel/socket/ipv6-sync", 592 test_io_channel_ipv6_sync); 593 g_test_add_func("/io/channel/socket/ipv6-async", 594 test_io_channel_ipv6_async); 595 } 596 597 socket_check_afunix_support(&has_afunix); 598 if (has_afunix) { 599 g_test_add_func("/io/channel/socket/unix-sync", 600 test_io_channel_unix_sync); 601 g_test_add_func("/io/channel/socket/unix-async", 602 test_io_channel_unix_async); 603 #ifndef _WIN32 604 g_test_add_func("/io/channel/socket/unix-fd-pass", 605 test_io_channel_unix_fd_pass); 606 #endif 607 g_test_add_func("/io/channel/socket/unix-listen-cleanup", 608 test_io_channel_unix_listen_cleanup); 609 } 610 611 end: 612 return g_test_run(); 613 } 614