test-io-channel-socket.c (18832B)
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 31static 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 52static 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 88struct TestIOChannelData { 89 bool err; 90 GMainLoop *loop; 91}; 92 93 94static 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 103static 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 159static 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 171static 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 g_assert(!passFD || 183 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 184 g_assert(!passFD || 185 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 186 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 187 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 188 189 test_io_channel_socket_path_exists(listen_addr, true); 190 191 test = qio_channel_test_new(); 192 qio_channel_test_run_threads(test, true, src, dst); 193 qio_channel_test_validate(test); 194 195 test_io_channel_socket_path_exists(listen_addr, true); 196 197 /* unref without close, to ensure finalize() cleans up */ 198 199 object_unref(OBJECT(src)); 200 object_unref(OBJECT(dst)); 201 test_io_channel_socket_path_exists(listen_addr, true); 202 203 object_unref(OBJECT(srv)); 204 test_io_channel_socket_path_exists(listen_addr, false); 205 206 test_io_channel_setup_async(listen_addr, connect_addr, 207 &srv, &src, &dst); 208 209 g_assert(!passFD || 210 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 211 g_assert(!passFD || 212 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 213 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 214 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 215 216 test = qio_channel_test_new(); 217 qio_channel_test_run_threads(test, false, src, dst); 218 qio_channel_test_validate(test); 219 220 /* close before unref, to ensure finalize copes with already closed */ 221 222 qio_channel_close(src, &error_abort); 223 qio_channel_close(dst, &error_abort); 224 test_io_channel_socket_path_exists(listen_addr, true); 225 226 object_unref(OBJECT(src)); 227 object_unref(OBJECT(dst)); 228 test_io_channel_socket_path_exists(listen_addr, true); 229 230 qio_channel_close(srv, &error_abort); 231 test_io_channel_socket_path_exists(listen_addr, false); 232 233 object_unref(OBJECT(srv)); 234 test_io_channel_socket_path_exists(listen_addr, false); 235 } else { 236 test_io_channel_setup_sync(listen_addr, connect_addr, 237 &srv, &src, &dst); 238 239 g_assert(!passFD || 240 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 241 g_assert(!passFD || 242 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 243 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 244 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 245 246 test_io_channel_socket_path_exists(listen_addr, true); 247 248 test = qio_channel_test_new(); 249 qio_channel_test_run_threads(test, true, src, dst); 250 qio_channel_test_validate(test); 251 252 test_io_channel_socket_path_exists(listen_addr, true); 253 254 /* unref without close, to ensure finalize() cleans up */ 255 256 object_unref(OBJECT(src)); 257 object_unref(OBJECT(dst)); 258 test_io_channel_socket_path_exists(listen_addr, true); 259 260 object_unref(OBJECT(srv)); 261 test_io_channel_socket_path_exists(listen_addr, false); 262 263 test_io_channel_setup_sync(listen_addr, connect_addr, 264 &srv, &src, &dst); 265 266 g_assert(!passFD || 267 qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 268 g_assert(!passFD || 269 qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 270 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_SHUTDOWN)); 271 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_SHUTDOWN)); 272 273 test = qio_channel_test_new(); 274 qio_channel_test_run_threads(test, false, src, dst); 275 qio_channel_test_validate(test); 276 277 test_io_channel_socket_path_exists(listen_addr, true); 278 279 /* close before unref, to ensure finalize copes with already closed */ 280 281 qio_channel_close(src, &error_abort); 282 qio_channel_close(dst, &error_abort); 283 test_io_channel_socket_path_exists(listen_addr, true); 284 285 object_unref(OBJECT(src)); 286 object_unref(OBJECT(dst)); 287 test_io_channel_socket_path_exists(listen_addr, true); 288 289 qio_channel_close(srv, &error_abort); 290 test_io_channel_socket_path_exists(listen_addr, false); 291 292 object_unref(OBJECT(srv)); 293 test_io_channel_socket_path_exists(listen_addr, false); 294 } 295} 296 297 298static void test_io_channel_ipv4(bool async) 299{ 300 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 301 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 302 303 listen_addr->type = SOCKET_ADDRESS_TYPE_INET; 304 listen_addr->u.inet = (InetSocketAddress) { 305 .host = g_strdup("127.0.0.1"), 306 .port = NULL, /* Auto-select */ 307 }; 308 309 connect_addr->type = SOCKET_ADDRESS_TYPE_INET; 310 connect_addr->u.inet = (InetSocketAddress) { 311 .host = g_strdup("127.0.0.1"), 312 .port = NULL, /* Filled in later */ 313 }; 314 315 test_io_channel(async, listen_addr, connect_addr, false); 316 317 qapi_free_SocketAddress(listen_addr); 318 qapi_free_SocketAddress(connect_addr); 319} 320 321 322static void test_io_channel_ipv4_sync(void) 323{ 324 return test_io_channel_ipv4(false); 325} 326 327 328static void test_io_channel_ipv4_async(void) 329{ 330 return test_io_channel_ipv4(true); 331} 332 333 334static void test_io_channel_ipv6(bool async) 335{ 336 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 337 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 338 339 listen_addr->type = SOCKET_ADDRESS_TYPE_INET; 340 listen_addr->u.inet = (InetSocketAddress) { 341 .host = g_strdup("::1"), 342 .port = NULL, /* Auto-select */ 343 }; 344 345 connect_addr->type = SOCKET_ADDRESS_TYPE_INET; 346 connect_addr->u.inet = (InetSocketAddress) { 347 .host = g_strdup("::1"), 348 .port = NULL, /* Filled in later */ 349 }; 350 351 test_io_channel(async, listen_addr, connect_addr, false); 352 353 qapi_free_SocketAddress(listen_addr); 354 qapi_free_SocketAddress(connect_addr); 355} 356 357 358static void test_io_channel_ipv6_sync(void) 359{ 360 return test_io_channel_ipv6(false); 361} 362 363 364static void test_io_channel_ipv6_async(void) 365{ 366 return test_io_channel_ipv6(true); 367} 368 369 370#ifndef _WIN32 371static void test_io_channel_unix(bool async) 372{ 373 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 374 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 375 376#define TEST_SOCKET "test-io-channel-socket.sock" 377 listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 378 listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 379 380 connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 381 connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 382 383 test_io_channel(async, listen_addr, connect_addr, true); 384 385 qapi_free_SocketAddress(listen_addr); 386 qapi_free_SocketAddress(connect_addr); 387} 388 389 390static void test_io_channel_unix_sync(void) 391{ 392 return test_io_channel_unix(false); 393} 394 395 396static void test_io_channel_unix_async(void) 397{ 398 return test_io_channel_unix(true); 399} 400 401static void test_io_channel_unix_fd_pass(void) 402{ 403 SocketAddress *listen_addr = g_new0(SocketAddress, 1); 404 SocketAddress *connect_addr = g_new0(SocketAddress, 1); 405 QIOChannel *src, *dst, *srv; 406 int testfd; 407 int fdsend[3]; 408 int *fdrecv = NULL; 409 size_t nfdrecv = 0; 410 size_t i; 411 char bufsend[12], bufrecv[12]; 412 struct iovec iosend[1], iorecv[1]; 413 414#define TEST_SOCKET "test-io-channel-socket.sock" 415#define TEST_FILE "test-io-channel-socket.txt" 416 417 testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700); 418 g_assert(testfd != -1); 419 fdsend[0] = testfd; 420 fdsend[1] = testfd; 421 fdsend[2] = testfd; 422 423 listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 424 listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 425 426 connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX; 427 connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET); 428 429 test_io_channel_setup_sync(listen_addr, connect_addr, &srv, &src, &dst); 430 431 memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend)); 432 433 iosend[0].iov_base = bufsend; 434 iosend[0].iov_len = G_N_ELEMENTS(bufsend); 435 436 iorecv[0].iov_base = bufrecv; 437 iorecv[0].iov_len = G_N_ELEMENTS(bufrecv); 438 439 g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); 440 g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); 441 442 qio_channel_writev_full(src, 443 iosend, 444 G_N_ELEMENTS(iosend), 445 fdsend, 446 G_N_ELEMENTS(fdsend), 447 &error_abort); 448 449 qio_channel_readv_full(dst, 450 iorecv, 451 G_N_ELEMENTS(iorecv), 452 &fdrecv, 453 &nfdrecv, 454 &error_abort); 455 456 g_assert(nfdrecv == G_N_ELEMENTS(fdsend)); 457 /* Each recvd FD should be different from sent FD */ 458 for (i = 0; i < nfdrecv; i++) { 459 g_assert_cmpint(fdrecv[i], !=, testfd); 460 } 461 /* Each recvd FD should be different from each other */ 462 g_assert_cmpint(fdrecv[0], !=, fdrecv[1]); 463 g_assert_cmpint(fdrecv[0], !=, fdrecv[2]); 464 g_assert_cmpint(fdrecv[1], !=, fdrecv[2]); 465 466 /* Check the I/O buf we sent at the same time matches */ 467 g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); 468 469 /* Write some data into the FD we received */ 470 g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) == 471 G_N_ELEMENTS(bufsend)); 472 473 /* Read data from the original FD and make sure it matches */ 474 memset(bufrecv, 0, G_N_ELEMENTS(bufrecv)); 475 g_assert(lseek(testfd, 0, SEEK_SET) == 0); 476 g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) == 477 G_N_ELEMENTS(bufrecv)); 478 g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); 479 480 object_unref(OBJECT(src)); 481 object_unref(OBJECT(dst)); 482 object_unref(OBJECT(srv)); 483 qapi_free_SocketAddress(listen_addr); 484 qapi_free_SocketAddress(connect_addr); 485 unlink(TEST_SOCKET); 486 unlink(TEST_FILE); 487 close(testfd); 488 for (i = 0; i < nfdrecv; i++) { 489 close(fdrecv[i]); 490 } 491 g_free(fdrecv); 492} 493 494static void test_io_channel_unix_listen_cleanup(void) 495{ 496 QIOChannelSocket *ioc; 497 struct sockaddr_un un; 498 int sock; 499 500#define TEST_SOCKET "test-io-channel-socket.sock" 501 502 ioc = qio_channel_socket_new(); 503 504 /* Manually bind ioc without calling the qio api to avoid setting 505 * the LISTEN feature */ 506 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); 507 memset(&un, 0, sizeof(un)); 508 un.sun_family = AF_UNIX; 509 snprintf(un.sun_path, sizeof(un.sun_path), "%s", TEST_SOCKET); 510 unlink(TEST_SOCKET); 511 bind(sock, (struct sockaddr *)&un, sizeof(un)); 512 ioc->fd = sock; 513 ioc->localAddrLen = sizeof(ioc->localAddr); 514 getsockname(sock, (struct sockaddr *)&ioc->localAddr, 515 &ioc->localAddrLen); 516 517 g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS)); 518 object_unref(OBJECT(ioc)); 519 g_assert(g_file_test(TEST_SOCKET, G_FILE_TEST_EXISTS)); 520 521 unlink(TEST_SOCKET); 522} 523 524#endif /* _WIN32 */ 525 526 527static void test_io_channel_ipv4_fd(void) 528{ 529 QIOChannel *ioc; 530 int fd = -1; 531 struct sockaddr_in sa = { 532 .sin_family = AF_INET, 533 .sin_addr = { 534 .s_addr = htonl(INADDR_LOOPBACK), 535 } 536 /* Leave port unset for auto-assign */ 537 }; 538 socklen_t salen = sizeof(sa); 539 540 fd = socket(AF_INET, SOCK_STREAM, 0); 541 g_assert_cmpint(fd, >, -1); 542 543 g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0); 544 545 ioc = qio_channel_new_fd(fd, &error_abort); 546 547 g_assert_cmpstr(object_get_typename(OBJECT(ioc)), 548 ==, 549 TYPE_QIO_CHANNEL_SOCKET); 550 551 object_unref(OBJECT(ioc)); 552} 553 554 555int main(int argc, char **argv) 556{ 557 bool has_ipv4, has_ipv6; 558 559 module_call_init(MODULE_INIT_QOM); 560 qemu_init_main_loop(&error_abort); 561 socket_init(); 562 563 g_test_init(&argc, &argv, NULL); 564 565 /* We're creating actual IPv4/6 sockets, so we should 566 * check if the host running tests actually supports 567 * each protocol to avoid breaking tests on machines 568 * with either IPv4 or IPv6 disabled. 569 */ 570 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 571 g_printerr("socket_check_protocol_support() failed\n"); 572 goto end; 573 } 574 575 if (has_ipv4) { 576 g_test_add_func("/io/channel/socket/ipv4-sync", 577 test_io_channel_ipv4_sync); 578 g_test_add_func("/io/channel/socket/ipv4-async", 579 test_io_channel_ipv4_async); 580 g_test_add_func("/io/channel/socket/ipv4-fd", 581 test_io_channel_ipv4_fd); 582 } 583 if (has_ipv6) { 584 g_test_add_func("/io/channel/socket/ipv6-sync", 585 test_io_channel_ipv6_sync); 586 g_test_add_func("/io/channel/socket/ipv6-async", 587 test_io_channel_ipv6_async); 588 } 589 590#ifndef _WIN32 591 g_test_add_func("/io/channel/socket/unix-sync", 592 test_io_channel_unix_sync); 593 g_test_add_func("/io/channel/socket/unix-async", 594 test_io_channel_unix_async); 595 g_test_add_func("/io/channel/socket/unix-fd-pass", 596 test_io_channel_unix_fd_pass); 597 g_test_add_func("/io/channel/socket/unix-listen-cleanup", 598 test_io_channel_unix_listen_cleanup); 599#endif /* _WIN32 */ 600 601end: 602 return g_test_run(); 603}