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