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