1 /* 2 * Tests for util/qemu-sockets.c 3 * 4 * Copyright 2018 Red Hat, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program 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 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu/sockets.h" 23 #include "qapi/error.h" 24 #include "socket-helpers.h" 25 #include "monitor/monitor.h" 26 27 static void test_fd_is_socket_bad(void) 28 { 29 char *tmp = g_strdup("qemu-test-util-sockets-XXXXXX"); 30 int fd = mkstemp(tmp); 31 if (fd != 0) { 32 unlink(tmp); 33 } 34 g_free(tmp); 35 36 g_assert(fd >= 0); 37 38 g_assert(!fd_is_socket(fd)); 39 close(fd); 40 } 41 42 static void test_fd_is_socket_good(void) 43 { 44 int fd = qemu_socket(PF_INET, SOCK_STREAM, 0); 45 46 g_assert(fd >= 0); 47 48 g_assert(fd_is_socket(fd)); 49 close(fd); 50 } 51 52 static int mon_fd = -1; 53 static const char *mon_fdname; 54 __thread Monitor *cur_mon; 55 56 int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) 57 { 58 g_assert(cur_mon); 59 g_assert(mon == cur_mon); 60 if (mon_fd == -1 || !g_str_equal(mon_fdname, fdname)) { 61 error_setg(errp, "No fd named %s", fdname); 62 return -1; 63 } 64 return dup(mon_fd); 65 } 66 67 /* 68 * Syms of stubs in libqemuutil.a are discarded at .o file 69 * granularity. To replace monitor_get_fd() and monitor_cur(), we 70 * must ensure that we also replace any other symbol that is used in 71 * the binary and would be taken from the same stub object file, 72 * otherwise we get duplicate syms at link time. 73 */ 74 Monitor *monitor_cur(void) { return cur_mon; } 75 Monitor *monitor_set_cur(Coroutine *co, Monitor *mon) { abort(); } 76 int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap) { abort(); } 77 78 #ifndef _WIN32 79 static void test_socket_fd_pass_name_good(void) 80 { 81 SocketAddress addr; 82 int fd; 83 84 cur_mon = g_malloc(1); /* Fake a monitor */ 85 mon_fdname = "myfd"; 86 mon_fd = qemu_socket(AF_INET, SOCK_STREAM, 0); 87 g_assert_cmpint(mon_fd, >, STDERR_FILENO); 88 89 addr.type = SOCKET_ADDRESS_TYPE_FD; 90 addr.u.fd.str = g_strdup(mon_fdname); 91 92 fd = socket_connect(&addr, &error_abort); 93 g_assert_cmpint(fd, !=, -1); 94 g_assert_cmpint(fd, !=, mon_fd); 95 close(fd); 96 97 fd = socket_listen(&addr, 1, &error_abort); 98 g_assert_cmpint(fd, !=, -1); 99 g_assert_cmpint(fd, !=, mon_fd); 100 close(fd); 101 102 g_free(addr.u.fd.str); 103 mon_fdname = NULL; 104 close(mon_fd); 105 mon_fd = -1; 106 g_free(cur_mon); 107 cur_mon = NULL; 108 } 109 110 static void test_socket_fd_pass_name_bad(void) 111 { 112 SocketAddress addr; 113 Error *err = NULL; 114 int fd; 115 116 cur_mon = g_malloc(1); /* Fake a monitor */ 117 mon_fdname = "myfd"; 118 mon_fd = dup(STDOUT_FILENO); 119 g_assert_cmpint(mon_fd, >, STDERR_FILENO); 120 121 addr.type = SOCKET_ADDRESS_TYPE_FD; 122 addr.u.fd.str = g_strdup(mon_fdname); 123 124 fd = socket_connect(&addr, &err); 125 g_assert_cmpint(fd, ==, -1); 126 error_free_or_abort(&err); 127 128 fd = socket_listen(&addr, 1, &err); 129 g_assert_cmpint(fd, ==, -1); 130 error_free_or_abort(&err); 131 132 g_free(addr.u.fd.str); 133 mon_fdname = NULL; 134 close(mon_fd); 135 mon_fd = -1; 136 g_free(cur_mon); 137 cur_mon = NULL; 138 } 139 140 static void test_socket_fd_pass_name_nomon(void) 141 { 142 SocketAddress addr; 143 Error *err = NULL; 144 int fd; 145 146 g_assert(cur_mon == NULL); 147 148 addr.type = SOCKET_ADDRESS_TYPE_FD; 149 addr.u.fd.str = g_strdup("myfd"); 150 151 fd = socket_connect(&addr, &err); 152 g_assert_cmpint(fd, ==, -1); 153 error_free_or_abort(&err); 154 155 fd = socket_listen(&addr, 1, &err); 156 g_assert_cmpint(fd, ==, -1); 157 error_free_or_abort(&err); 158 159 g_free(addr.u.fd.str); 160 } 161 162 163 static void test_socket_fd_pass_num_good(void) 164 { 165 SocketAddress addr; 166 int fd, sfd; 167 168 g_assert(cur_mon == NULL); 169 sfd = qemu_socket(AF_INET, SOCK_STREAM, 0); 170 g_assert_cmpint(sfd, >, STDERR_FILENO); 171 172 addr.type = SOCKET_ADDRESS_TYPE_FD; 173 addr.u.fd.str = g_strdup_printf("%d", sfd); 174 175 fd = socket_connect(&addr, &error_abort); 176 g_assert_cmpint(fd, ==, sfd); 177 178 fd = socket_listen(&addr, 1, &error_abort); 179 g_assert_cmpint(fd, ==, sfd); 180 181 g_free(addr.u.fd.str); 182 close(sfd); 183 } 184 185 static void test_socket_fd_pass_num_bad(void) 186 { 187 SocketAddress addr; 188 Error *err = NULL; 189 int fd, sfd; 190 191 g_assert(cur_mon == NULL); 192 sfd = dup(STDOUT_FILENO); 193 194 addr.type = SOCKET_ADDRESS_TYPE_FD; 195 addr.u.fd.str = g_strdup_printf("%d", sfd); 196 197 fd = socket_connect(&addr, &err); 198 g_assert_cmpint(fd, ==, -1); 199 error_free_or_abort(&err); 200 201 fd = socket_listen(&addr, 1, &err); 202 g_assert_cmpint(fd, ==, -1); 203 error_free_or_abort(&err); 204 205 g_free(addr.u.fd.str); 206 close(sfd); 207 } 208 209 static void test_socket_fd_pass_num_nocli(void) 210 { 211 SocketAddress addr; 212 Error *err = NULL; 213 int fd; 214 215 cur_mon = g_malloc(1); /* Fake a monitor */ 216 217 addr.type = SOCKET_ADDRESS_TYPE_FD; 218 addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO); 219 220 fd = socket_connect(&addr, &err); 221 g_assert_cmpint(fd, ==, -1); 222 error_free_or_abort(&err); 223 224 fd = socket_listen(&addr, 1, &err); 225 g_assert_cmpint(fd, ==, -1); 226 error_free_or_abort(&err); 227 228 g_free(addr.u.fd.str); 229 } 230 #endif 231 232 #ifdef CONFIG_LINUX 233 234 #define ABSTRACT_SOCKET_VARIANTS 3 235 236 typedef struct { 237 SocketAddress *server, *client[ABSTRACT_SOCKET_VARIANTS]; 238 bool expect_connect[ABSTRACT_SOCKET_VARIANTS]; 239 } abstract_socket_matrix_row; 240 241 static gpointer unix_client_thread_func(gpointer user_data) 242 { 243 abstract_socket_matrix_row *row = user_data; 244 Error *err = NULL; 245 int i, fd; 246 247 for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) { 248 if (row->expect_connect[i]) { 249 fd = socket_connect(row->client[i], &error_abort); 250 g_assert_cmpint(fd, >=, 0); 251 } else { 252 fd = socket_connect(row->client[i], &err); 253 g_assert_cmpint(fd, ==, -1); 254 error_free_or_abort(&err); 255 } 256 close(fd); 257 } 258 return NULL; 259 } 260 261 static void test_socket_unix_abstract_row(abstract_socket_matrix_row *test) 262 { 263 int fd, connfd, i; 264 GThread *cli; 265 struct sockaddr_un un; 266 socklen_t len = sizeof(un); 267 268 /* Last one must connect, or else accept() below hangs */ 269 assert(test->expect_connect[ABSTRACT_SOCKET_VARIANTS - 1]); 270 271 fd = socket_listen(test->server, 1, &error_abort); 272 g_assert_cmpint(fd, >=, 0); 273 g_assert(fd_is_socket(fd)); 274 275 cli = g_thread_new("abstract_unix_client", 276 unix_client_thread_func, 277 test); 278 279 for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) { 280 if (test->expect_connect[i]) { 281 connfd = accept(fd, (struct sockaddr *)&un, &len); 282 g_assert_cmpint(connfd, !=, -1); 283 close(connfd); 284 } 285 } 286 287 close(fd); 288 g_thread_join(cli); 289 } 290 291 static void test_socket_unix_abstract(void) 292 { 293 SocketAddress addr, addr_tight, addr_padded; 294 abstract_socket_matrix_row matrix[ABSTRACT_SOCKET_VARIANTS] = { 295 { &addr, 296 { &addr_tight, &addr_padded, &addr }, 297 { true, false, true } }, 298 { &addr_tight, 299 { &addr_padded, &addr, &addr_tight }, 300 { false, true, true } }, 301 { &addr_padded, 302 { &addr, &addr_tight, &addr_padded }, 303 { false, false, true } } 304 }; 305 int i; 306 307 i = g_file_open_tmp("unix-XXXXXX", &addr.u.q_unix.path, NULL); 308 g_assert_true(i >= 0); 309 close(i); 310 311 addr.type = SOCKET_ADDRESS_TYPE_UNIX; 312 addr.u.q_unix.has_abstract = true; 313 addr.u.q_unix.abstract = true; 314 addr.u.q_unix.has_tight = false; 315 addr.u.q_unix.tight = false; 316 317 addr_tight = addr; 318 addr_tight.u.q_unix.has_tight = true; 319 addr_tight.u.q_unix.tight = true; 320 321 addr_padded = addr; 322 addr_padded.u.q_unix.has_tight = true; 323 addr_padded.u.q_unix.tight = false; 324 325 for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) { 326 test_socket_unix_abstract_row(&matrix[i]); 327 } 328 329 unlink(addr.u.q_unix.path); 330 g_free(addr.u.q_unix.path); 331 } 332 333 #endif /* CONFIG_LINUX */ 334 335 static void inet_parse_test_helper(const char *str, 336 InetSocketAddress *exp_addr, bool success) 337 { 338 InetSocketAddress addr; 339 Error *error = NULL; 340 341 int rc = inet_parse(&addr, str, &error); 342 343 if (success) { 344 if (error) { 345 error_report_err(error); 346 } 347 g_assert_cmpint(rc, ==, 0); 348 } else { 349 error_free(error); 350 g_assert_cmpint(rc, <, 0); 351 } 352 if (exp_addr != NULL) { 353 g_assert_cmpstr(addr.host, ==, exp_addr->host); 354 g_assert_cmpstr(addr.port, ==, exp_addr->port); 355 /* Own members: */ 356 g_assert_cmpint(addr.has_numeric, ==, exp_addr->has_numeric); 357 g_assert_cmpint(addr.numeric, ==, exp_addr->numeric); 358 g_assert_cmpint(addr.has_to, ==, exp_addr->has_to); 359 g_assert_cmpint(addr.to, ==, exp_addr->to); 360 g_assert_cmpint(addr.has_ipv4, ==, exp_addr->has_ipv4); 361 g_assert_cmpint(addr.ipv4, ==, exp_addr->ipv4); 362 g_assert_cmpint(addr.has_ipv6, ==, exp_addr->has_ipv6); 363 g_assert_cmpint(addr.ipv6, ==, exp_addr->ipv6); 364 g_assert_cmpint(addr.has_keep_alive, ==, exp_addr->has_keep_alive); 365 g_assert_cmpint(addr.keep_alive, ==, exp_addr->keep_alive); 366 #ifdef HAVE_TCP_KEEPCNT 367 g_assert_cmpint(addr.has_keep_alive_count, ==, 368 exp_addr->has_keep_alive_count); 369 g_assert_cmpint(addr.keep_alive_count, ==, 370 exp_addr->keep_alive_count); 371 #endif 372 #ifdef HAVE_TCP_KEEPIDLE 373 g_assert_cmpint(addr.has_keep_alive_idle, ==, 374 exp_addr->has_keep_alive_idle); 375 g_assert_cmpint(addr.keep_alive_idle, ==, 376 exp_addr->keep_alive_idle); 377 #endif 378 #ifdef HAVE_TCP_KEEPINTVL 379 g_assert_cmpint(addr.has_keep_alive_interval, ==, 380 exp_addr->has_keep_alive_interval); 381 g_assert_cmpint(addr.keep_alive_interval, ==, 382 exp_addr->keep_alive_interval); 383 #endif 384 #ifdef HAVE_IPPROTO_MPTCP 385 g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp); 386 g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp); 387 #endif 388 } 389 390 g_free(addr.host); 391 g_free(addr.port); 392 } 393 394 static void test_inet_parse_nohost_good(void) 395 { 396 char host[] = ""; 397 char port[] = "5000"; 398 InetSocketAddress exp_addr = { 399 .host = host, 400 .port = port, 401 }; 402 inet_parse_test_helper(":5000", &exp_addr, true); 403 } 404 405 static void test_inet_parse_empty_bad(void) 406 { 407 inet_parse_test_helper("", NULL, false); 408 } 409 410 static void test_inet_parse_only_colon_bad(void) 411 { 412 inet_parse_test_helper(":", NULL, false); 413 } 414 415 static void test_inet_parse_ipv4_good(void) 416 { 417 char host[] = "127.0.0.1"; 418 char port[] = "5000"; 419 InetSocketAddress exp_addr = { 420 .host = host, 421 .port = port, 422 }; 423 inet_parse_test_helper("127.0.0.1:5000", &exp_addr, true); 424 } 425 426 static void test_inet_parse_ipv4_noport_bad(void) 427 { 428 inet_parse_test_helper("127.0.0.1", NULL, false); 429 } 430 431 static void test_inet_parse_ipv6_good(void) 432 { 433 char host[] = "::1"; 434 char port[] = "5000"; 435 InetSocketAddress exp_addr = { 436 .host = host, 437 .port = port, 438 }; 439 inet_parse_test_helper("[::1]:5000", &exp_addr, true); 440 } 441 442 static void test_inet_parse_ipv6_noend_bad(void) 443 { 444 inet_parse_test_helper("[::1", NULL, false); 445 } 446 447 static void test_inet_parse_ipv6_noport_bad(void) 448 { 449 inet_parse_test_helper("[::1]:", NULL, false); 450 } 451 452 static void test_inet_parse_ipv6_empty_bad(void) 453 { 454 inet_parse_test_helper("[]:5000", NULL, false); 455 } 456 457 static void test_inet_parse_hostname_good(void) 458 { 459 char host[] = "localhost"; 460 char port[] = "5000"; 461 InetSocketAddress exp_addr = { 462 .host = host, 463 .port = port, 464 }; 465 inet_parse_test_helper("localhost:5000", &exp_addr, true); 466 } 467 468 static void test_inet_parse_all_options_good(void) 469 { 470 char host[] = "::1"; 471 char port[] = "5000"; 472 InetSocketAddress exp_addr = { 473 .host = host, 474 .port = port, 475 .has_numeric = true, 476 .numeric = true, 477 .has_to = true, 478 .to = 5006, 479 .has_ipv4 = true, 480 .ipv4 = false, 481 .has_ipv6 = true, 482 .ipv6 = true, 483 .has_keep_alive = true, 484 .keep_alive = true, 485 #ifdef HAVE_TCP_KEEPCNT 486 .has_keep_alive_count = true, 487 .keep_alive_count = 10, 488 #endif 489 #ifdef HAVE_TCP_KEEPIDLE 490 .has_keep_alive_idle = true, 491 .keep_alive_idle = 60, 492 #endif 493 #ifdef HAVE_TCP_KEEPINTVL 494 .has_keep_alive_interval = true, 495 .keep_alive_interval = 30, 496 #endif 497 #ifdef HAVE_IPPROTO_MPTCP 498 .has_mptcp = true, 499 .mptcp = false, 500 #endif 501 }; 502 inet_parse_test_helper( 503 "[::1]:5000,numeric=on,to=5006,ipv4=off,ipv6=on,keep-alive=on" 504 #ifdef HAVE_TCP_KEEPCNT 505 ",keep-alive-count=10" 506 #endif 507 #ifdef HAVE_TCP_KEEPIDLE 508 ",keep-alive-idle=60" 509 #endif 510 #ifdef HAVE_TCP_KEEPINTVL 511 ",keep-alive-interval=30" 512 #endif 513 #ifdef HAVE_IPPROTO_MPTCP 514 ",mptcp=off" 515 #endif 516 , &exp_addr, true); 517 } 518 519 static void test_inet_parse_all_implicit_bool_good(void) 520 { 521 char host[] = "::1"; 522 char port[] = "5000"; 523 InetSocketAddress exp_addr = { 524 .host = host, 525 .port = port, 526 .has_numeric = true, 527 .numeric = true, 528 .has_to = true, 529 .to = 5006, 530 .has_ipv4 = true, 531 .ipv4 = true, 532 .has_ipv6 = true, 533 .ipv6 = true, 534 .has_keep_alive = true, 535 .keep_alive = true, 536 #ifdef HAVE_IPPROTO_MPTCP 537 .has_mptcp = true, 538 .mptcp = true, 539 #endif 540 }; 541 inet_parse_test_helper( 542 "[::1]:5000,numeric,to=5006,ipv4,ipv6,keep-alive" 543 #ifdef HAVE_IPPROTO_MPTCP 544 ",mptcp" 545 #endif 546 , &exp_addr, true); 547 } 548 549 int main(int argc, char **argv) 550 { 551 bool has_ipv4, has_ipv6; 552 553 qemu_init_main_loop(&error_abort); 554 socket_init(); 555 556 g_test_init(&argc, &argv, NULL); 557 558 /* We're creating actual IPv4/6 sockets, so we should 559 * check if the host running tests actually supports 560 * each protocol to avoid breaking tests on machines 561 * with either IPv4 or IPv6 disabled. 562 */ 563 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 564 g_printerr("socket_check_protocol_support() failed\n"); 565 goto end; 566 } 567 568 if (has_ipv4) { 569 g_test_add_func("/util/socket/is-socket/bad", 570 test_fd_is_socket_bad); 571 g_test_add_func("/util/socket/is-socket/good", 572 test_fd_is_socket_good); 573 #ifndef _WIN32 574 g_test_add_func("/socket/fd-pass/name/good", 575 test_socket_fd_pass_name_good); 576 g_test_add_func("/socket/fd-pass/name/bad", 577 test_socket_fd_pass_name_bad); 578 g_test_add_func("/socket/fd-pass/name/nomon", 579 test_socket_fd_pass_name_nomon); 580 g_test_add_func("/socket/fd-pass/num/good", 581 test_socket_fd_pass_num_good); 582 g_test_add_func("/socket/fd-pass/num/bad", 583 test_socket_fd_pass_num_bad); 584 g_test_add_func("/socket/fd-pass/num/nocli", 585 test_socket_fd_pass_num_nocli); 586 #endif 587 } 588 589 #ifdef CONFIG_LINUX 590 g_test_add_func("/util/socket/unix-abstract", 591 test_socket_unix_abstract); 592 #endif 593 594 g_test_add_func("/util/socket/inet-parse/nohost-good", 595 test_inet_parse_nohost_good); 596 g_test_add_func("/util/socket/inet-parse/empty-bad", 597 test_inet_parse_empty_bad); 598 g_test_add_func("/util/socket/inet-parse/only-colon-bad", 599 test_inet_parse_only_colon_bad); 600 g_test_add_func("/util/socket/inet-parse/ipv4-good", 601 test_inet_parse_ipv4_good); 602 g_test_add_func("/util/socket/inet-parse/ipv4-noport-bad", 603 test_inet_parse_ipv4_noport_bad); 604 g_test_add_func("/util/socket/inet-parse/ipv6-good", 605 test_inet_parse_ipv6_good); 606 g_test_add_func("/util/socket/inet-parse/ipv6-noend-bad", 607 test_inet_parse_ipv6_noend_bad); 608 g_test_add_func("/util/socket/inet-parse/ipv6-noport-bad", 609 test_inet_parse_ipv6_noport_bad); 610 g_test_add_func("/util/socket/inet-parse/ipv6-empty-bad", 611 test_inet_parse_ipv6_empty_bad); 612 g_test_add_func("/util/socket/inet-parse/hostname-good", 613 test_inet_parse_hostname_good); 614 g_test_add_func("/util/socket/inet-parse/all-options-good", 615 test_inet_parse_all_options_good); 616 g_test_add_func("/util/socket/inet-parse/all-bare-bool-good", 617 test_inet_parse_all_implicit_bool_good); 618 619 end: 620 return g_test_run(); 621 } 622