qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 1471 lines 45 kB view raw
1#include "qemu/osdep.h" 2#include <glib/gstdio.h> 3 4#include "qemu/config-file.h" 5#include "qemu/module.h" 6#include "qemu/option.h" 7#include "qemu/sockets.h" 8#include "chardev/char-fe.h" 9#include "chardev/char-mux.h" 10#include "sysemu/sysemu.h" 11#include "qapi/error.h" 12#include "qapi/qapi-commands-char.h" 13#include "qapi/qmp/qdict.h" 14#include "qom/qom-qobject.h" 15#include "io/channel-socket.h" 16#include "qapi/qobject-input-visitor.h" 17#include "qapi/qapi-visit-sockets.h" 18#include "socket-helpers.h" 19 20static bool quit; 21 22typedef struct FeHandler { 23 int read_count; 24 bool is_open; 25 int openclose_count; 26 bool openclose_mismatch; 27 int last_event; 28 char read_buf[128]; 29} FeHandler; 30 31static void main_loop(void) 32{ 33 quit = false; 34 do { 35 main_loop_wait(false); 36 } while (!quit); 37} 38 39static int fe_can_read(void *opaque) 40{ 41 FeHandler *h = opaque; 42 43 return sizeof(h->read_buf) - h->read_count; 44} 45 46static void fe_read(void *opaque, const uint8_t *buf, int size) 47{ 48 FeHandler *h = opaque; 49 50 g_assert_cmpint(size, <=, fe_can_read(opaque)); 51 52 memcpy(h->read_buf + h->read_count, buf, size); 53 h->read_count += size; 54 quit = true; 55} 56 57static void fe_event(void *opaque, QEMUChrEvent event) 58{ 59 FeHandler *h = opaque; 60 bool new_open_state; 61 62 h->last_event = event; 63 switch (event) { 64 case CHR_EVENT_BREAK: 65 break; 66 case CHR_EVENT_OPENED: 67 case CHR_EVENT_CLOSED: 68 h->openclose_count++; 69 new_open_state = (event == CHR_EVENT_OPENED); 70 if (h->is_open == new_open_state) { 71 h->openclose_mismatch = true; 72 } 73 h->is_open = new_open_state; 74 /* no break */ 75 default: 76 quit = true; 77 break; 78 } 79} 80 81#ifdef _WIN32 82static void char_console_test_subprocess(void) 83{ 84 QemuOpts *opts; 85 Chardev *chr; 86 87 opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label", 88 1, &error_abort); 89 qemu_opt_set(opts, "backend", "console", &error_abort); 90 91 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 92 g_assert_nonnull(chr); 93 94 qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7); 95 96 qemu_opts_del(opts); 97 object_unparent(OBJECT(chr)); 98} 99 100static void char_console_test(void) 101{ 102 g_test_trap_subprocess("/char/console/subprocess", 0, 0); 103 g_test_trap_assert_passed(); 104 g_test_trap_assert_stdout("CONSOLE"); 105} 106#endif 107static void char_stdio_test_subprocess(void) 108{ 109 Chardev *chr; 110 CharBackend be; 111 int ret; 112 113 chr = qemu_chr_new("label", "stdio", NULL); 114 g_assert_nonnull(chr); 115 116 qemu_chr_fe_init(&be, chr, &error_abort); 117 qemu_chr_fe_set_open(&be, true); 118 ret = qemu_chr_fe_write(&be, (void *)"buf", 4); 119 g_assert_cmpint(ret, ==, 4); 120 121 qemu_chr_fe_deinit(&be, true); 122} 123 124static void char_stdio_test(void) 125{ 126 g_test_trap_subprocess("/char/stdio/subprocess", 0, 0); 127 g_test_trap_assert_passed(); 128 g_test_trap_assert_stdout("buf"); 129} 130 131static void char_ringbuf_test(void) 132{ 133 QemuOpts *opts; 134 Chardev *chr; 135 CharBackend be; 136 char *data; 137 int ret; 138 139 opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label", 140 1, &error_abort); 141 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 142 143 qemu_opt_set(opts, "size", "5", &error_abort); 144 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 145 g_assert_null(chr); 146 qemu_opts_del(opts); 147 148 opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label", 149 1, &error_abort); 150 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 151 qemu_opt_set(opts, "size", "2", &error_abort); 152 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 153 g_assert_nonnull(chr); 154 qemu_opts_del(opts); 155 156 qemu_chr_fe_init(&be, chr, &error_abort); 157 ret = qemu_chr_fe_write(&be, (void *)"buff", 4); 158 g_assert_cmpint(ret, ==, 4); 159 160 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort); 161 g_assert_cmpstr(data, ==, "ff"); 162 g_free(data); 163 164 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort); 165 g_assert_cmpstr(data, ==, ""); 166 g_free(data); 167 168 qemu_chr_fe_deinit(&be, true); 169 170 /* check alias */ 171 opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label", 172 1, &error_abort); 173 qemu_opt_set(opts, "backend", "memory", &error_abort); 174 qemu_opt_set(opts, "size", "2", &error_abort); 175 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 176 g_assert_nonnull(chr); 177 object_unparent(OBJECT(chr)); 178 qemu_opts_del(opts); 179} 180 181static void char_mux_test(void) 182{ 183 QemuOpts *opts; 184 Chardev *chr, *base; 185 char *data; 186 FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, }; 187 CharBackend chr_be1, chr_be2; 188 189 opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label", 190 1, &error_abort); 191 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 192 qemu_opt_set(opts, "size", "128", &error_abort); 193 qemu_opt_set(opts, "mux", "on", &error_abort); 194 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 195 g_assert_nonnull(chr); 196 qemu_opts_del(opts); 197 198 qemu_chr_fe_init(&chr_be1, chr, &error_abort); 199 qemu_chr_fe_set_handlers(&chr_be1, 200 fe_can_read, 201 fe_read, 202 fe_event, 203 NULL, 204 &h1, 205 NULL, true); 206 207 qemu_chr_fe_init(&chr_be2, chr, &error_abort); 208 qemu_chr_fe_set_handlers(&chr_be2, 209 fe_can_read, 210 fe_read, 211 fe_event, 212 NULL, 213 &h2, 214 NULL, true); 215 qemu_chr_fe_take_focus(&chr_be2); 216 217 base = qemu_chr_find("mux-label-base"); 218 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0); 219 220 qemu_chr_be_write(base, (void *)"hello", 6); 221 g_assert_cmpint(h1.read_count, ==, 0); 222 g_assert_cmpint(h2.read_count, ==, 6); 223 g_assert_cmpstr(h2.read_buf, ==, "hello"); 224 h2.read_count = 0; 225 226 g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */ 227 g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */ 228 /* sending event on the base broadcast to all fe, historical reasons? */ 229 qemu_chr_be_event(base, 42); 230 g_assert_cmpint(h1.last_event, ==, 42); 231 g_assert_cmpint(h2.last_event, ==, 42); 232 qemu_chr_be_event(chr, -1); 233 g_assert_cmpint(h1.last_event, ==, 42); 234 g_assert_cmpint(h2.last_event, ==, -1); 235 236 /* switch focus */ 237 qemu_chr_be_write(base, (void *)"\1b", 2); 238 g_assert_cmpint(h1.last_event, ==, 42); 239 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK); 240 241 qemu_chr_be_write(base, (void *)"\1c", 2); 242 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN); 243 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); 244 qemu_chr_be_event(chr, -1); 245 g_assert_cmpint(h1.last_event, ==, -1); 246 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); 247 248 qemu_chr_be_write(base, (void *)"hello", 6); 249 g_assert_cmpint(h2.read_count, ==, 0); 250 g_assert_cmpint(h1.read_count, ==, 6); 251 g_assert_cmpstr(h1.read_buf, ==, "hello"); 252 h1.read_count = 0; 253 254 qemu_chr_be_write(base, (void *)"\1b", 2); 255 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK); 256 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); 257 258 /* open/close state and corresponding events */ 259 g_assert_true(qemu_chr_fe_backend_open(&chr_be1)); 260 g_assert_true(qemu_chr_fe_backend_open(&chr_be2)); 261 g_assert_true(h1.is_open); 262 g_assert_false(h1.openclose_mismatch); 263 g_assert_true(h2.is_open); 264 g_assert_false(h2.openclose_mismatch); 265 266 h1.openclose_count = h2.openclose_count = 0; 267 268 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, 269 NULL, NULL, false); 270 qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, NULL, NULL, 271 NULL, NULL, false); 272 g_assert_cmpint(h1.openclose_count, ==, 0); 273 g_assert_cmpint(h2.openclose_count, ==, 0); 274 275 h1.is_open = h2.is_open = false; 276 qemu_chr_fe_set_handlers(&chr_be1, 277 NULL, 278 NULL, 279 fe_event, 280 NULL, 281 &h1, 282 NULL, false); 283 qemu_chr_fe_set_handlers(&chr_be2, 284 NULL, 285 NULL, 286 fe_event, 287 NULL, 288 &h2, 289 NULL, false); 290 g_assert_cmpint(h1.openclose_count, ==, 1); 291 g_assert_false(h1.openclose_mismatch); 292 g_assert_cmpint(h2.openclose_count, ==, 1); 293 g_assert_false(h2.openclose_mismatch); 294 295 qemu_chr_be_event(base, CHR_EVENT_CLOSED); 296 qemu_chr_be_event(base, CHR_EVENT_OPENED); 297 g_assert_cmpint(h1.openclose_count, ==, 3); 298 g_assert_false(h1.openclose_mismatch); 299 g_assert_cmpint(h2.openclose_count, ==, 3); 300 g_assert_false(h2.openclose_mismatch); 301 302 qemu_chr_fe_set_handlers(&chr_be2, 303 fe_can_read, 304 fe_read, 305 fe_event, 306 NULL, 307 &h2, 308 NULL, false); 309 qemu_chr_fe_set_handlers(&chr_be1, 310 fe_can_read, 311 fe_read, 312 fe_event, 313 NULL, 314 &h1, 315 NULL, false); 316 317 /* remove first handler */ 318 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, 319 NULL, NULL, true); 320 qemu_chr_be_write(base, (void *)"hello", 6); 321 g_assert_cmpint(h1.read_count, ==, 0); 322 g_assert_cmpint(h2.read_count, ==, 0); 323 324 qemu_chr_be_write(base, (void *)"\1c", 2); 325 qemu_chr_be_write(base, (void *)"hello", 6); 326 g_assert_cmpint(h1.read_count, ==, 0); 327 g_assert_cmpint(h2.read_count, ==, 6); 328 g_assert_cmpstr(h2.read_buf, ==, "hello"); 329 h2.read_count = 0; 330 331 /* print help */ 332 qemu_chr_be_write(base, (void *)"\1?", 2); 333 data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort); 334 g_assert_cmpint(strlen(data), !=, 0); 335 g_free(data); 336 337 qemu_chr_fe_deinit(&chr_be1, false); 338 qemu_chr_fe_deinit(&chr_be2, true); 339} 340 341 342static void websock_server_read(void *opaque, const uint8_t *buf, int size) 343{ 344 g_assert_cmpint(size, ==, 5); 345 g_assert(memcmp(buf, "world", size) == 0); 346 quit = true; 347} 348 349 350static int websock_server_can_read(void *opaque) 351{ 352 return 10; 353} 354 355 356static bool websock_check_http_headers(char *buf, int size) 357{ 358 int i; 359 const char *ans[] = { "HTTP/1.1 101 Switching Protocols\r\n", 360 "Server: QEMU VNC\r\n", 361 "Upgrade: websocket\r\n", 362 "Connection: Upgrade\r\n", 363 "Sec-WebSocket-Accept:", 364 "Sec-WebSocket-Protocol: binary\r\n" }; 365 366 for (i = 0; i < 6; i++) { 367 if (g_strstr_len(buf, size, ans[i]) == NULL) { 368 return false; 369 } 370 } 371 372 return true; 373} 374 375 376static void websock_client_read(void *opaque, const uint8_t *buf, int size) 377{ 378 const uint8_t ping[] = { 0x89, 0x85, /* Ping header */ 379 0x07, 0x77, 0x9e, 0xf9, /* Masking key */ 380 0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ }; 381 382 const uint8_t binary[] = { 0x82, 0x85, /* Binary header */ 383 0x74, 0x90, 0xb9, 0xdf, /* Masking key */ 384 0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ }; 385 Chardev *chr_client = opaque; 386 387 if (websock_check_http_headers((char *) buf, size)) { 388 qemu_chr_fe_write(chr_client->be, ping, sizeof(ping)); 389 } else if (buf[0] == 0x8a && buf[1] == 0x05) { 390 g_assert(strncmp((char *) buf + 2, "hello", 5) == 0); 391 qemu_chr_fe_write(chr_client->be, binary, sizeof(binary)); 392 } else { 393 g_assert(buf[0] == 0x88 && buf[1] == 0x16); 394 g_assert(strncmp((char *) buf + 4, "peer requested close", 10) == 0); 395 quit = true; 396 } 397} 398 399 400static int websock_client_can_read(void *opaque) 401{ 402 return 4096; 403} 404 405 406static void char_websock_test(void) 407{ 408 QObject *addr; 409 QDict *qdict; 410 const char *port; 411 char *tmp; 412 char *handshake_port; 413 CharBackend be; 414 CharBackend client_be; 415 Chardev *chr_client; 416 Chardev *chr = qemu_chr_new("server", 417 "websocket:127.0.0.1:0,server,nowait", NULL); 418 const char handshake[] = "GET / HTTP/1.1\r\n" 419 "Upgrade: websocket\r\n" 420 "Connection: Upgrade\r\n" 421 "Host: localhost:%s\r\n" 422 "Origin: http://localhost:%s\r\n" 423 "Sec-WebSocket-Key: o9JHNiS3/0/0zYE1wa3yIw==\r\n" 424 "Sec-WebSocket-Version: 13\r\n" 425 "Sec-WebSocket-Protocol: binary\r\n\r\n"; 426 const uint8_t close[] = { 0x88, 0x82, /* Close header */ 427 0xef, 0xaa, 0xc5, 0x97, /* Masking key */ 428 0xec, 0x42 /* Status code */ }; 429 430 addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 431 qdict = qobject_to(QDict, addr); 432 port = qdict_get_str(qdict, "port"); 433 tmp = g_strdup_printf("tcp:127.0.0.1:%s", port); 434 handshake_port = g_strdup_printf(handshake, port, port); 435 qobject_unref(qdict); 436 437 qemu_chr_fe_init(&be, chr, &error_abort); 438 qemu_chr_fe_set_handlers(&be, websock_server_can_read, websock_server_read, 439 NULL, NULL, chr, NULL, true); 440 441 chr_client = qemu_chr_new("client", tmp, NULL); 442 qemu_chr_fe_init(&client_be, chr_client, &error_abort); 443 qemu_chr_fe_set_handlers(&client_be, websock_client_can_read, 444 websock_client_read, 445 NULL, NULL, chr_client, NULL, true); 446 g_free(tmp); 447 448 qemu_chr_write_all(chr_client, 449 (uint8_t *) handshake_port, 450 strlen(handshake_port)); 451 g_free(handshake_port); 452 main_loop(); 453 454 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 455 g_assert(object_property_get_bool(OBJECT(chr_client), 456 "connected", &error_abort)); 457 458 qemu_chr_write_all(chr_client, close, sizeof(close)); 459 main_loop(); 460 461 object_unparent(OBJECT(chr_client)); 462 object_unparent(OBJECT(chr)); 463} 464 465 466#ifndef _WIN32 467static void char_pipe_test(void) 468{ 469 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 470 gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL); 471 Chardev *chr; 472 CharBackend be; 473 int ret, fd; 474 char buf[10]; 475 FeHandler fe = { 0, }; 476 477 in = g_strdup_printf("%s.in", pipe); 478 if (mkfifo(in, 0600) < 0) { 479 abort(); 480 } 481 out = g_strdup_printf("%s.out", pipe); 482 if (mkfifo(out, 0600) < 0) { 483 abort(); 484 } 485 486 tmp = g_strdup_printf("pipe:%s", pipe); 487 chr = qemu_chr_new("pipe", tmp, NULL); 488 g_assert_nonnull(chr); 489 g_free(tmp); 490 491 qemu_chr_fe_init(&be, chr, &error_abort); 492 493 ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9); 494 g_assert_cmpint(ret, ==, 9); 495 496 fd = open(out, O_RDWR); 497 ret = read(fd, buf, sizeof(buf)); 498 g_assert_cmpint(ret, ==, 9); 499 g_assert_cmpstr(buf, ==, "pipe-out"); 500 close(fd); 501 502 fd = open(in, O_WRONLY); 503 ret = write(fd, "pipe-in", 8); 504 g_assert_cmpint(ret, ==, 8); 505 close(fd); 506 507 qemu_chr_fe_set_handlers(&be, 508 fe_can_read, 509 fe_read, 510 fe_event, 511 NULL, 512 &fe, 513 NULL, true); 514 515 main_loop(); 516 517 g_assert_cmpint(fe.read_count, ==, 8); 518 g_assert_cmpstr(fe.read_buf, ==, "pipe-in"); 519 520 qemu_chr_fe_deinit(&be, true); 521 522 g_assert(g_unlink(in) == 0); 523 g_assert(g_unlink(out) == 0); 524 g_assert(g_rmdir(tmp_path) == 0); 525 g_free(in); 526 g_free(out); 527 g_free(tmp_path); 528 g_free(pipe); 529} 530#endif 531 532typedef struct SocketIdleData { 533 GMainLoop *loop; 534 Chardev *chr; 535 bool conn_expected; 536 CharBackend *be; 537 CharBackend *client_be; 538} SocketIdleData; 539 540 541static void socket_read_hello(void *opaque, const uint8_t *buf, int size) 542{ 543 g_assert_cmpint(size, ==, 5); 544 g_assert(strncmp((char *)buf, "hello", 5) == 0); 545 546 quit = true; 547} 548 549static int socket_can_read_hello(void *opaque) 550{ 551 return 10; 552} 553 554static int make_udp_socket(int *port) 555{ 556 struct sockaddr_in addr = { 0, }; 557 socklen_t alen = sizeof(addr); 558 int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0); 559 560 g_assert_cmpint(sock, >, 0); 561 addr.sin_family = AF_INET ; 562 addr.sin_addr.s_addr = htonl(INADDR_ANY); 563 addr.sin_port = 0; 564 ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); 565 g_assert_cmpint(ret, ==, 0); 566 ret = getsockname(sock, (struct sockaddr *)&addr, &alen); 567 g_assert_cmpint(ret, ==, 0); 568 569 *port = ntohs(addr.sin_port); 570 return sock; 571} 572 573static void char_udp_test_internal(Chardev *reuse_chr, int sock) 574{ 575 struct sockaddr_in other; 576 SocketIdleData d = { 0, }; 577 Chardev *chr; 578 CharBackend *be; 579 socklen_t alen = sizeof(other); 580 int ret; 581 char buf[10]; 582 char *tmp = NULL; 583 584 if (reuse_chr) { 585 chr = reuse_chr; 586 be = chr->be; 587 } else { 588 int port; 589 sock = make_udp_socket(&port); 590 tmp = g_strdup_printf("udp:127.0.0.1:%d", port); 591 chr = qemu_chr_new("client", tmp, NULL); 592 g_assert_nonnull(chr); 593 594 be = g_alloca(sizeof(CharBackend)); 595 qemu_chr_fe_init(be, chr, &error_abort); 596 } 597 598 d.chr = chr; 599 qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello, 600 NULL, NULL, &d, NULL, true); 601 ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5); 602 g_assert_cmpint(ret, ==, 5); 603 604 ret = recvfrom(sock, buf, sizeof(buf), 0, 605 (struct sockaddr *)&other, &alen); 606 g_assert_cmpint(ret, ==, 5); 607 ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen); 608 g_assert_cmpint(ret, ==, 5); 609 610 main_loop(); 611 612 if (!reuse_chr) { 613 close(sock); 614 qemu_chr_fe_deinit(be, true); 615 } 616 g_free(tmp); 617} 618 619static void char_udp_test(void) 620{ 621 char_udp_test_internal(NULL, 0); 622} 623 624 625typedef struct { 626 int event; 627 bool got_pong; 628} CharSocketTestData; 629 630 631#define SOCKET_PING "Hello" 632#define SOCKET_PONG "World" 633 634 635static void 636char_socket_event(void *opaque, QEMUChrEvent event) 637{ 638 CharSocketTestData *data = opaque; 639 data->event = event; 640} 641 642 643static void 644char_socket_read(void *opaque, const uint8_t *buf, int size) 645{ 646 CharSocketTestData *data = opaque; 647 g_assert_cmpint(size, ==, sizeof(SOCKET_PONG)); 648 g_assert(memcmp(buf, SOCKET_PONG, size) == 0); 649 data->got_pong = true; 650} 651 652 653static int 654char_socket_can_read(void *opaque) 655{ 656 return sizeof(SOCKET_PONG); 657} 658 659 660static char * 661char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass, 662 const char *reconnect, bool is_listen) 663{ 664 if (fd_pass) { 665 QIOChannelSocket *ioc = qio_channel_socket_new(); 666 int fd; 667 char *optstr; 668 g_assert(!reconnect); 669 if (is_listen) { 670 qio_channel_socket_listen_sync(ioc, addr, 1, &error_abort); 671 } else { 672 qio_channel_socket_connect_sync(ioc, addr, &error_abort); 673 } 674 fd = ioc->fd; 675 ioc->fd = -1; 676 optstr = g_strdup_printf("socket,id=cdev0,fd=%d%s", 677 fd, is_listen ? ",server,nowait" : ""); 678 object_unref(OBJECT(ioc)); 679 return optstr; 680 } else { 681 switch (addr->type) { 682 case SOCKET_ADDRESS_TYPE_INET: 683 return g_strdup_printf("socket,id=cdev0,host=%s,port=%s%s%s", 684 addr->u.inet.host, 685 addr->u.inet.port, 686 reconnect ? reconnect : "", 687 is_listen ? ",server,nowait" : ""); 688 689 case SOCKET_ADDRESS_TYPE_UNIX: 690 return g_strdup_printf("socket,id=cdev0,path=%s%s%s", 691 addr->u.q_unix.path, 692 reconnect ? reconnect : "", 693 is_listen ? ",server,nowait" : ""); 694 695 default: 696 g_assert_not_reached(); 697 } 698 } 699} 700 701 702static void 703char_socket_ping_pong(QIOChannel *ioc) 704{ 705 char greeting[sizeof(SOCKET_PING)]; 706 const char *response = SOCKET_PONG; 707 708 qio_channel_read_all(ioc, greeting, sizeof(greeting), &error_abort); 709 710 g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0); 711 712 qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), &error_abort); 713 714 object_unref(OBJECT(ioc)); 715} 716 717 718static gpointer 719char_socket_server_client_thread(gpointer data) 720{ 721 SocketAddress *addr = data; 722 QIOChannelSocket *ioc = qio_channel_socket_new(); 723 724 qio_channel_socket_connect_sync(ioc, addr, &error_abort); 725 726 char_socket_ping_pong(QIO_CHANNEL(ioc)); 727 728 return NULL; 729} 730 731 732typedef struct { 733 SocketAddress *addr; 734 bool wait_connected; 735 bool fd_pass; 736} CharSocketServerTestConfig; 737 738 739static void char_socket_server_test(gconstpointer opaque) 740{ 741 const CharSocketServerTestConfig *config = opaque; 742 Chardev *chr; 743 CharBackend be = {0}; 744 CharSocketTestData data = {0}; 745 QObject *qaddr; 746 SocketAddress *addr; 747 Visitor *v; 748 QemuThread thread; 749 int ret; 750 bool reconnected = false; 751 char *optstr; 752 QemuOpts *opts; 753 754 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 755 /* 756 * We rely on config->addr containing "nowait", otherwise 757 * qemu_chr_new() will block until a client connects. We 758 * can't spawn our client thread though, because until 759 * qemu_chr_new() returns we don't know what TCP port was 760 * allocated by the OS 761 */ 762 optstr = char_socket_addr_to_opt_str(config->addr, 763 config->fd_pass, 764 NULL, 765 true); 766 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 767 optstr, true); 768 g_assert_nonnull(opts); 769 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 770 qemu_opts_del(opts); 771 g_assert_nonnull(chr); 772 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 773 774 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 775 g_assert_nonnull(qaddr); 776 777 v = qobject_input_visitor_new(qaddr); 778 visit_type_SocketAddress(v, "addr", &addr, &error_abort); 779 visit_free(v); 780 qobject_unref(qaddr); 781 782 qemu_chr_fe_init(&be, chr, &error_abort); 783 784 reconnect: 785 data.event = -1; 786 qemu_chr_fe_set_handlers(&be, NULL, NULL, 787 char_socket_event, NULL, 788 &data, NULL, true); 789 g_assert(data.event == -1); 790 791 /* 792 * Kick off a thread to act as the "remote" client 793 * which just plays ping-pong with us 794 */ 795 qemu_thread_create(&thread, "client", 796 char_socket_server_client_thread, 797 addr, QEMU_THREAD_JOINABLE); 798 g_assert(data.event == -1); 799 800 if (config->wait_connected) { 801 /* Synchronously accept a connection */ 802 qemu_chr_wait_connected(chr, &error_abort); 803 } else { 804 /* 805 * Asynchronously accept a connection when the evnt 806 * loop reports the listener socket as readable 807 */ 808 while (data.event == -1) { 809 main_loop_wait(false); 810 } 811 } 812 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 813 g_assert(data.event == CHR_EVENT_OPENED); 814 data.event = -1; 815 816 /* Send a greeting to the client */ 817 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING, 818 sizeof(SOCKET_PING)); 819 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING)); 820 g_assert(data.event == -1); 821 822 /* Setup a callback to receive the reply to our greeting */ 823 qemu_chr_fe_set_handlers(&be, char_socket_can_read, 824 char_socket_read, 825 char_socket_event, NULL, 826 &data, NULL, true); 827 g_assert(data.event == CHR_EVENT_OPENED); 828 data.event = -1; 829 830 /* Wait for the client to go away */ 831 while (data.event == -1) { 832 main_loop_wait(false); 833 } 834 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 835 g_assert(data.event == CHR_EVENT_CLOSED); 836 g_assert(data.got_pong); 837 838 qemu_thread_join(&thread); 839 840 if (!reconnected) { 841 reconnected = true; 842 goto reconnect; 843 } 844 845 qapi_free_SocketAddress(addr); 846 object_unparent(OBJECT(chr)); 847 g_free(optstr); 848 g_unsetenv("QTEST_SILENT_ERRORS"); 849} 850 851 852static gpointer 853char_socket_client_server_thread(gpointer data) 854{ 855 QIOChannelSocket *ioc = data; 856 QIOChannelSocket *cioc; 857 858 cioc = qio_channel_socket_accept(ioc, &error_abort); 859 g_assert_nonnull(cioc); 860 861 char_socket_ping_pong(QIO_CHANNEL(cioc)); 862 863 return NULL; 864} 865 866 867typedef struct { 868 SocketAddress *addr; 869 const char *reconnect; 870 bool wait_connected; 871 bool fd_pass; 872} CharSocketClientTestConfig; 873 874 875static void char_socket_client_test(gconstpointer opaque) 876{ 877 const CharSocketClientTestConfig *config = opaque; 878 QIOChannelSocket *ioc; 879 char *optstr; 880 Chardev *chr; 881 CharBackend be = {0}; 882 CharSocketTestData data = {0}; 883 SocketAddress *addr; 884 QemuThread thread; 885 int ret; 886 bool reconnected = false; 887 QemuOpts *opts; 888 889 /* 890 * Setup a listener socket and determine get its address 891 * so we know the TCP port for the client later 892 */ 893 ioc = qio_channel_socket_new(); 894 g_assert_nonnull(ioc); 895 qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); 896 addr = qio_channel_socket_get_local_address(ioc, &error_abort); 897 g_assert_nonnull(addr); 898 899 /* 900 * Kick off a thread to act as the "remote" client 901 * which just plays ping-pong with us 902 */ 903 qemu_thread_create(&thread, "client", 904 char_socket_client_server_thread, 905 ioc, QEMU_THREAD_JOINABLE); 906 907 /* 908 * Populate the chardev address based on what the server 909 * is actually listening on 910 */ 911 optstr = char_socket_addr_to_opt_str(addr, 912 config->fd_pass, 913 config->reconnect, 914 false); 915 916 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 917 optstr, true); 918 g_assert_nonnull(opts); 919 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 920 qemu_opts_del(opts); 921 g_assert_nonnull(chr); 922 923 if (config->reconnect) { 924 /* 925 * If reconnect is set, the connection will be 926 * established in a background thread and we won't 927 * see the "connected" status updated until we 928 * run the main event loop, or call qemu_chr_wait_connected 929 */ 930 g_assert(!object_property_get_bool(OBJECT(chr), "connected", 931 &error_abort)); 932 } else { 933 g_assert(object_property_get_bool(OBJECT(chr), "connected", 934 &error_abort)); 935 } 936 937 qemu_chr_fe_init(&be, chr, &error_abort); 938 939 reconnect: 940 data.event = -1; 941 qemu_chr_fe_set_handlers(&be, NULL, NULL, 942 char_socket_event, NULL, 943 &data, NULL, true); 944 if (config->reconnect) { 945 g_assert(data.event == -1); 946 } else { 947 g_assert(data.event == CHR_EVENT_OPENED); 948 } 949 950 if (config->wait_connected) { 951 /* 952 * Synchronously wait for the connection to complete 953 * This should be a no-op if reconnect is not set. 954 */ 955 qemu_chr_wait_connected(chr, &error_abort); 956 } else { 957 /* 958 * Asynchronously wait for the connection to be reported 959 * as complete when the background thread reports its 960 * status. 961 * The loop will short-circuit if reconnect was set 962 */ 963 while (data.event == -1) { 964 main_loop_wait(false); 965 } 966 } 967 g_assert(data.event == CHR_EVENT_OPENED); 968 data.event = -1; 969 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 970 971 /* Send a greeting to the server */ 972 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING, 973 sizeof(SOCKET_PING)); 974 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING)); 975 g_assert(data.event == -1); 976 977 /* Setup a callback to receive the reply to our greeting */ 978 qemu_chr_fe_set_handlers(&be, char_socket_can_read, 979 char_socket_read, 980 char_socket_event, NULL, 981 &data, NULL, true); 982 g_assert(data.event == CHR_EVENT_OPENED); 983 data.event = -1; 984 985 /* Wait for the server to go away */ 986 while (data.event == -1) { 987 main_loop_wait(false); 988 } 989 g_assert(data.event == CHR_EVENT_CLOSED); 990 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 991 g_assert(data.got_pong); 992 qemu_thread_join(&thread); 993 994 if (config->reconnect && !reconnected) { 995 reconnected = true; 996 qemu_thread_create(&thread, "client", 997 char_socket_client_server_thread, 998 ioc, QEMU_THREAD_JOINABLE); 999 goto reconnect; 1000 } 1001 1002 object_unref(OBJECT(ioc)); 1003 object_unparent(OBJECT(chr)); 1004 qapi_free_SocketAddress(addr); 1005 g_free(optstr); 1006} 1007 1008static void 1009count_closed_event(void *opaque, QEMUChrEvent event) 1010{ 1011 int *count = opaque; 1012 if (event == CHR_EVENT_CLOSED) { 1013 (*count)++; 1014 } 1015} 1016 1017static void 1018char_socket_discard_read(void *opaque, const uint8_t *buf, int size) 1019{ 1020} 1021 1022static void char_socket_server_two_clients_test(gconstpointer opaque) 1023{ 1024 SocketAddress *incoming_addr = (gpointer) opaque; 1025 Chardev *chr; 1026 CharBackend be = {0}; 1027 QObject *qaddr; 1028 SocketAddress *addr; 1029 Visitor *v; 1030 char *optstr; 1031 QemuOpts *opts; 1032 QIOChannelSocket *ioc1, *ioc2; 1033 int closed = 0; 1034 1035 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1036 /* 1037 * We rely on addr containing "nowait", otherwise 1038 * qemu_chr_new() will block until a client connects. We 1039 * can't spawn our client thread though, because until 1040 * qemu_chr_new() returns we don't know what TCP port was 1041 * allocated by the OS 1042 */ 1043 optstr = char_socket_addr_to_opt_str(incoming_addr, 1044 false, 1045 NULL, 1046 true); 1047 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1048 optstr, true); 1049 g_assert_nonnull(opts); 1050 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1051 qemu_opts_del(opts); 1052 g_assert_nonnull(chr); 1053 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1054 1055 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 1056 g_assert_nonnull(qaddr); 1057 1058 v = qobject_input_visitor_new(qaddr); 1059 visit_type_SocketAddress(v, "addr", &addr, &error_abort); 1060 visit_free(v); 1061 qobject_unref(qaddr); 1062 1063 qemu_chr_fe_init(&be, chr, &error_abort); 1064 1065 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read, 1066 count_closed_event, NULL, 1067 &closed, NULL, true); 1068 1069 ioc1 = qio_channel_socket_new(); 1070 qio_channel_socket_connect_sync(ioc1, addr, &error_abort); 1071 qemu_chr_wait_connected(chr, &error_abort); 1072 1073 /* switch the chardev to another context */ 1074 GMainContext *ctx = g_main_context_new(); 1075 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read, 1076 count_closed_event, NULL, 1077 &closed, ctx, true); 1078 1079 /* Start a second connection while the first is still connected. 1080 * It will be placed in the listen() backlog, and connect() will 1081 * succeed immediately. 1082 */ 1083 ioc2 = qio_channel_socket_new(); 1084 qio_channel_socket_connect_sync(ioc2, addr, &error_abort); 1085 1086 object_unref(OBJECT(ioc1)); 1087 /* The two connections should now be processed serially. */ 1088 while (g_main_context_iteration(ctx, TRUE)) { 1089 if (closed == 1 && ioc2) { 1090 object_unref(OBJECT(ioc2)); 1091 ioc2 = NULL; 1092 } 1093 if (closed == 2) { 1094 break; 1095 } 1096 } 1097 1098 qapi_free_SocketAddress(addr); 1099 object_unparent(OBJECT(chr)); 1100 g_main_context_unref(ctx); 1101 g_free(optstr); 1102 g_unsetenv("QTEST_SILENT_ERRORS"); 1103} 1104 1105 1106#if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) 1107static void char_serial_test(void) 1108{ 1109 QemuOpts *opts; 1110 Chardev *chr; 1111 1112 opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id", 1113 1, &error_abort); 1114 qemu_opt_set(opts, "backend", "serial", &error_abort); 1115 qemu_opt_set(opts, "path", "/dev/null", &error_abort); 1116 1117 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 1118 g_assert_nonnull(chr); 1119 /* TODO: add more tests with a pty */ 1120 object_unparent(OBJECT(chr)); 1121 1122 /* test tty alias */ 1123 qemu_opt_set(opts, "backend", "tty", &error_abort); 1124 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 1125 g_assert_nonnull(chr); 1126 object_unparent(OBJECT(chr)); 1127 1128 qemu_opts_del(opts); 1129} 1130#endif 1131 1132#ifndef _WIN32 1133static void char_file_fifo_test(void) 1134{ 1135 Chardev *chr; 1136 CharBackend be; 1137 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1138 char *fifo = g_build_filename(tmp_path, "fifo", NULL); 1139 char *out = g_build_filename(tmp_path, "out", NULL); 1140 ChardevFile file = { .in = fifo, 1141 .has_in = true, 1142 .out = out }; 1143 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1144 .u.file.data = &file }; 1145 FeHandler fe = { 0, }; 1146 int fd, ret; 1147 1148 if (mkfifo(fifo, 0600) < 0) { 1149 abort(); 1150 } 1151 1152 fd = open(fifo, O_RDWR); 1153 ret = write(fd, "fifo-in", 8); 1154 g_assert_cmpint(ret, ==, 8); 1155 1156 chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend, 1157 NULL, &error_abort); 1158 1159 qemu_chr_fe_init(&be, chr, &error_abort); 1160 qemu_chr_fe_set_handlers(&be, 1161 fe_can_read, 1162 fe_read, 1163 fe_event, 1164 NULL, 1165 &fe, NULL, true); 1166 1167 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK); 1168 qmp_chardev_send_break("label-foo", NULL); 1169 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK); 1170 qmp_chardev_send_break("label-file", NULL); 1171 g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK); 1172 1173 main_loop(); 1174 1175 close(fd); 1176 1177 g_assert_cmpint(fe.read_count, ==, 8); 1178 g_assert_cmpstr(fe.read_buf, ==, "fifo-in"); 1179 1180 qemu_chr_fe_deinit(&be, true); 1181 1182 g_unlink(fifo); 1183 g_free(fifo); 1184 g_unlink(out); 1185 g_free(out); 1186 g_rmdir(tmp_path); 1187 g_free(tmp_path); 1188} 1189#endif 1190 1191static void char_file_test_internal(Chardev *ext_chr, const char *filepath) 1192{ 1193 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1194 char *out; 1195 Chardev *chr; 1196 char *contents = NULL; 1197 ChardevFile file = {}; 1198 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1199 .u.file.data = &file }; 1200 gsize length; 1201 int ret; 1202 1203 if (ext_chr) { 1204 chr = ext_chr; 1205 out = g_strdup(filepath); 1206 file.out = out; 1207 } else { 1208 out = g_build_filename(tmp_path, "out", NULL); 1209 file.out = out; 1210 chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend, 1211 NULL, &error_abort); 1212 } 1213 ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6); 1214 g_assert_cmpint(ret, ==, 6); 1215 1216 ret = g_file_get_contents(out, &contents, &length, NULL); 1217 g_assert(ret == TRUE); 1218 g_assert_cmpint(length, ==, 6); 1219 g_assert(strncmp(contents, "hello!", 6) == 0); 1220 1221 if (!ext_chr) { 1222 object_unref(OBJECT(chr)); 1223 g_unlink(out); 1224 } 1225 g_free(contents); 1226 g_rmdir(tmp_path); 1227 g_free(tmp_path); 1228 g_free(out); 1229} 1230 1231static void char_file_test(void) 1232{ 1233 char_file_test_internal(NULL, NULL); 1234} 1235 1236static void char_null_test(void) 1237{ 1238 Error *err = NULL; 1239 Chardev *chr; 1240 CharBackend be; 1241 int ret; 1242 1243 chr = qemu_chr_find("label-null"); 1244 g_assert_null(chr); 1245 1246 chr = qemu_chr_new("label-null", "null", NULL); 1247 chr = qemu_chr_find("label-null"); 1248 g_assert_nonnull(chr); 1249 1250 g_assert(qemu_chr_has_feature(chr, 1251 QEMU_CHAR_FEATURE_FD_PASS) == false); 1252 g_assert(qemu_chr_has_feature(chr, 1253 QEMU_CHAR_FEATURE_RECONNECTABLE) == false); 1254 1255 /* check max avail */ 1256 qemu_chr_fe_init(&be, chr, &error_abort); 1257 qemu_chr_fe_init(&be, chr, &err); 1258 error_free_or_abort(&err); 1259 1260 /* deinit & reinit */ 1261 qemu_chr_fe_deinit(&be, false); 1262 qemu_chr_fe_init(&be, chr, &error_abort); 1263 1264 qemu_chr_fe_set_open(&be, true); 1265 1266 qemu_chr_fe_set_handlers(&be, 1267 fe_can_read, 1268 fe_read, 1269 fe_event, 1270 NULL, 1271 NULL, NULL, true); 1272 1273 ret = qemu_chr_fe_write(&be, (void *)"buf", 4); 1274 g_assert_cmpint(ret, ==, 4); 1275 1276 qemu_chr_fe_deinit(&be, true); 1277} 1278 1279static void char_invalid_test(void) 1280{ 1281 Chardev *chr; 1282 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1283 chr = qemu_chr_new("label-invalid", "invalid", NULL); 1284 g_assert_null(chr); 1285 g_unsetenv("QTEST_SILENT_ERRORS"); 1286} 1287 1288static int chardev_change(void *opaque) 1289{ 1290 return 0; 1291} 1292 1293static int chardev_change_denied(void *opaque) 1294{ 1295 return -1; 1296} 1297 1298static void char_hotswap_test(void) 1299{ 1300 char *chr_args; 1301 Chardev *chr; 1302 CharBackend be; 1303 1304 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1305 char *filename = g_build_filename(tmp_path, "file", NULL); 1306 ChardevFile file = { .out = filename }; 1307 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1308 .u.file.data = &file }; 1309 ChardevReturn *ret; 1310 1311 int port; 1312 int sock = make_udp_socket(&port); 1313 g_assert_cmpint(sock, >, 0); 1314 1315 chr_args = g_strdup_printf("udp:127.0.0.1:%d", port); 1316 1317 chr = qemu_chr_new("chardev", chr_args, NULL); 1318 qemu_chr_fe_init(&be, chr, &error_abort); 1319 1320 /* check that chardev operates correctly */ 1321 char_udp_test_internal(chr, sock); 1322 1323 /* set the handler that denies the hotswap */ 1324 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1325 NULL, chardev_change_denied, NULL, NULL, true); 1326 1327 /* now, change is denied and has to keep the old backend operating */ 1328 ret = qmp_chardev_change("chardev", &backend, NULL); 1329 g_assert(!ret); 1330 g_assert(be.chr == chr); 1331 1332 char_udp_test_internal(chr, sock); 1333 1334 /* now allow the change */ 1335 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1336 NULL, chardev_change, NULL, NULL, true); 1337 1338 /* has to succeed now */ 1339 ret = qmp_chardev_change("chardev", &backend, &error_abort); 1340 g_assert(be.chr != chr); 1341 1342 close(sock); 1343 chr = be.chr; 1344 1345 /* run the file chardev test */ 1346 char_file_test_internal(chr, filename); 1347 1348 object_unparent(OBJECT(chr)); 1349 1350 qapi_free_ChardevReturn(ret); 1351 g_unlink(filename); 1352 g_free(filename); 1353 g_rmdir(tmp_path); 1354 g_free(tmp_path); 1355 g_free(chr_args); 1356} 1357 1358static SocketAddress tcpaddr = { 1359 .type = SOCKET_ADDRESS_TYPE_INET, 1360 .u.inet.host = (char *)"127.0.0.1", 1361 .u.inet.port = (char *)"0", 1362}; 1363#ifndef WIN32 1364static SocketAddress unixaddr = { 1365 .type = SOCKET_ADDRESS_TYPE_UNIX, 1366 .u.q_unix.path = (char *)"test-char.sock", 1367}; 1368#endif 1369 1370int main(int argc, char **argv) 1371{ 1372 bool has_ipv4, has_ipv6; 1373 1374 qemu_init_main_loop(&error_abort); 1375 socket_init(); 1376 1377 g_test_init(&argc, &argv, NULL); 1378 1379 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 1380 g_printerr("socket_check_protocol_support() failed\n"); 1381 goto end; 1382 } 1383 1384 module_call_init(MODULE_INIT_QOM); 1385 qemu_add_opts(&qemu_chardev_opts); 1386 1387 g_test_add_func("/char/null", char_null_test); 1388 g_test_add_func("/char/invalid", char_invalid_test); 1389 g_test_add_func("/char/ringbuf", char_ringbuf_test); 1390 g_test_add_func("/char/mux", char_mux_test); 1391#ifdef _WIN32 1392 g_test_add_func("/char/console/subprocess", char_console_test_subprocess); 1393 g_test_add_func("/char/console", char_console_test); 1394#endif 1395 g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess); 1396 g_test_add_func("/char/stdio", char_stdio_test); 1397#ifndef _WIN32 1398 g_test_add_func("/char/pipe", char_pipe_test); 1399#endif 1400 g_test_add_func("/char/file", char_file_test); 1401#ifndef _WIN32 1402 g_test_add_func("/char/file-fifo", char_file_fifo_test); 1403#endif 1404 1405#define SOCKET_SERVER_TEST(name, addr) \ 1406 static CharSocketServerTestConfig server1 ## name = \ 1407 { addr, false, false }; \ 1408 static CharSocketServerTestConfig server2 ## name = \ 1409 { addr, true, false }; \ 1410 static CharSocketServerTestConfig server3 ## name = \ 1411 { addr, false, true }; \ 1412 static CharSocketServerTestConfig server4 ## name = \ 1413 { addr, true, true }; \ 1414 g_test_add_data_func("/char/socket/server/mainloop/" # name, \ 1415 &server1 ##name, char_socket_server_test); \ 1416 g_test_add_data_func("/char/socket/server/wait-conn/" # name, \ 1417 &server2 ##name, char_socket_server_test); \ 1418 g_test_add_data_func("/char/socket/server/mainloop-fdpass/" # name, \ 1419 &server3 ##name, char_socket_server_test); \ 1420 g_test_add_data_func("/char/socket/server/wait-conn-fdpass/" # name, \ 1421 &server4 ##name, char_socket_server_test) 1422 1423#define SOCKET_CLIENT_TEST(name, addr) \ 1424 static CharSocketClientTestConfig client1 ## name = \ 1425 { addr, NULL, false, false }; \ 1426 static CharSocketClientTestConfig client2 ## name = \ 1427 { addr, NULL, true, false }; \ 1428 static CharSocketClientTestConfig client3 ## name = \ 1429 { addr, ",reconnect=1", false }; \ 1430 static CharSocketClientTestConfig client4 ## name = \ 1431 { addr, ",reconnect=1", true }; \ 1432 static CharSocketClientTestConfig client5 ## name = \ 1433 { addr, NULL, false, true }; \ 1434 static CharSocketClientTestConfig client6 ## name = \ 1435 { addr, NULL, true, true }; \ 1436 g_test_add_data_func("/char/socket/client/mainloop/" # name, \ 1437 &client1 ##name, char_socket_client_test); \ 1438 g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ 1439 &client2 ##name, char_socket_client_test); \ 1440 g_test_add_data_func("/char/socket/client/mainloop-reconnect/" # name, \ 1441 &client3 ##name, char_socket_client_test); \ 1442 g_test_add_data_func("/char/socket/client/wait-conn-reconnect/" # name, \ 1443 &client4 ##name, char_socket_client_test); \ 1444 g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \ 1445 &client5 ##name, char_socket_client_test); \ 1446 g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ 1447 &client6 ##name, char_socket_client_test) 1448 1449 if (has_ipv4) { 1450 SOCKET_SERVER_TEST(tcp, &tcpaddr); 1451 SOCKET_CLIENT_TEST(tcp, &tcpaddr); 1452 g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr, 1453 char_socket_server_two_clients_test); 1454 } 1455#ifndef WIN32 1456 SOCKET_SERVER_TEST(unix, &unixaddr); 1457 SOCKET_CLIENT_TEST(unix, &unixaddr); 1458 g_test_add_data_func("/char/socket/server/two-clients/unix", &unixaddr, 1459 char_socket_server_two_clients_test); 1460#endif 1461 1462 g_test_add_func("/char/udp", char_udp_test); 1463#if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) 1464 g_test_add_func("/char/serial", char_serial_test); 1465#endif 1466 g_test_add_func("/char/hotswap", char_hotswap_test); 1467 g_test_add_func("/char/websocket", char_websock_test); 1468 1469end: 1470 return g_test_run(); 1471}