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