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