1 #include "qemu/osdep.h" 2 #include <glib/gstdio.h> 3 4 #include "qapi/error.h" 5 #include "qemu/config-file.h" 6 #include "qemu/module.h" 7 #include "qemu/option.h" 8 #include "qemu/sockets.h" 9 #include "chardev/char-fe.h" 10 #include "system/system.h" 11 #include "qapi/error.h" 12 #include "qapi/qapi-commands-char.h" 13 #include "qobject/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 20 static bool quit; 21 22 typedef 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 31 static void main_loop(void) 32 { 33 quit = false; 34 do { 35 main_loop_wait(false); 36 } while (!quit); 37 } 38 39 static int fe_can_read(void *opaque) 40 { 41 FeHandler *h = opaque; 42 43 return sizeof(h->read_buf) - h->read_count; 44 } 45 46 static 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 57 static 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 /* fallthrough */ 75 default: 76 quit = true; 77 break; 78 } 79 } 80 81 #ifdef _WIN32 82 static 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 100 static 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 107 static 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 124 static 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 131 static 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 181 static 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 Error *error = NULL; 189 190 /* Create mux and chardev to be immediately removed */ 191 opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label", 192 1, &error_abort); 193 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 194 qemu_opt_set(opts, "size", "128", &error_abort); 195 qemu_opt_set(opts, "mux", "on", &error_abort); 196 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 197 g_assert_nonnull(chr); 198 qemu_opts_del(opts); 199 200 /* Remove just created mux and chardev */ 201 qmp_chardev_remove("mux-label", &error_abort); 202 qmp_chardev_remove("mux-label-base", &error_abort); 203 204 opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label", 205 1, &error_abort); 206 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 207 qemu_opt_set(opts, "size", "128", &error_abort); 208 qemu_opt_set(opts, "mux", "on", &error_abort); 209 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 210 g_assert_nonnull(chr); 211 qemu_opts_del(opts); 212 213 qemu_chr_fe_init(&chr_be1, chr, &error_abort); 214 qemu_chr_fe_set_handlers(&chr_be1, 215 fe_can_read, 216 fe_read, 217 fe_event, 218 NULL, 219 &h1, 220 NULL, true); 221 222 qemu_chr_fe_init(&chr_be2, chr, &error_abort); 223 qemu_chr_fe_set_handlers(&chr_be2, 224 fe_can_read, 225 fe_read, 226 fe_event, 227 NULL, 228 &h2, 229 NULL, true); 230 qemu_chr_fe_take_focus(&chr_be2); 231 232 base = qemu_chr_find("mux-label-base"); 233 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0); 234 235 qemu_chr_be_write(base, (void *)"hello", 6); 236 g_assert_cmpint(h1.read_count, ==, 0); 237 g_assert_cmpint(h2.read_count, ==, 6); 238 g_assert_cmpstr(h2.read_buf, ==, "hello"); 239 h2.read_count = 0; 240 241 g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */ 242 g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */ 243 /* sending event on the base broadcast to all fe, historical reasons? */ 244 qemu_chr_be_event(base, 42); 245 g_assert_cmpint(h1.last_event, ==, 42); 246 g_assert_cmpint(h2.last_event, ==, 42); 247 qemu_chr_be_event(chr, -1); 248 g_assert_cmpint(h1.last_event, ==, 42); 249 g_assert_cmpint(h2.last_event, ==, -1); 250 251 /* switch focus */ 252 qemu_chr_be_write(base, (void *)"\1b", 2); 253 g_assert_cmpint(h1.last_event, ==, 42); 254 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK); 255 256 qemu_chr_be_write(base, (void *)"\1c", 2); 257 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN); 258 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); 259 qemu_chr_be_event(chr, -1); 260 g_assert_cmpint(h1.last_event, ==, -1); 261 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); 262 263 qemu_chr_be_write(base, (void *)"hello", 6); 264 g_assert_cmpint(h2.read_count, ==, 0); 265 g_assert_cmpint(h1.read_count, ==, 6); 266 g_assert_cmpstr(h1.read_buf, ==, "hello"); 267 h1.read_count = 0; 268 269 qemu_chr_be_write(base, (void *)"\1b", 2); 270 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK); 271 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); 272 273 /* open/close state and corresponding events */ 274 g_assert_true(qemu_chr_fe_backend_open(&chr_be1)); 275 g_assert_true(qemu_chr_fe_backend_open(&chr_be2)); 276 g_assert_true(h1.is_open); 277 g_assert_false(h1.openclose_mismatch); 278 g_assert_true(h2.is_open); 279 g_assert_false(h2.openclose_mismatch); 280 281 h1.openclose_count = h2.openclose_count = 0; 282 283 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, 284 NULL, NULL, false); 285 qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, NULL, NULL, 286 NULL, NULL, false); 287 g_assert_cmpint(h1.openclose_count, ==, 0); 288 g_assert_cmpint(h2.openclose_count, ==, 0); 289 290 h1.is_open = h2.is_open = false; 291 qemu_chr_fe_set_handlers(&chr_be1, 292 NULL, 293 NULL, 294 fe_event, 295 NULL, 296 &h1, 297 NULL, false); 298 qemu_chr_fe_set_handlers(&chr_be2, 299 NULL, 300 NULL, 301 fe_event, 302 NULL, 303 &h2, 304 NULL, false); 305 g_assert_cmpint(h1.openclose_count, ==, 1); 306 g_assert_false(h1.openclose_mismatch); 307 g_assert_cmpint(h2.openclose_count, ==, 1); 308 g_assert_false(h2.openclose_mismatch); 309 310 qemu_chr_be_event(base, CHR_EVENT_CLOSED); 311 qemu_chr_be_event(base, CHR_EVENT_OPENED); 312 g_assert_cmpint(h1.openclose_count, ==, 3); 313 g_assert_false(h1.openclose_mismatch); 314 g_assert_cmpint(h2.openclose_count, ==, 3); 315 g_assert_false(h2.openclose_mismatch); 316 317 qemu_chr_fe_set_handlers(&chr_be2, 318 fe_can_read, 319 fe_read, 320 fe_event, 321 NULL, 322 &h2, 323 NULL, false); 324 qemu_chr_fe_set_handlers(&chr_be1, 325 fe_can_read, 326 fe_read, 327 fe_event, 328 NULL, 329 &h1, 330 NULL, false); 331 332 /* remove first handler */ 333 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL, 334 NULL, NULL, true); 335 qemu_chr_be_write(base, (void *)"hello", 6); 336 g_assert_cmpint(h1.read_count, ==, 0); 337 g_assert_cmpint(h2.read_count, ==, 0); 338 339 qemu_chr_be_write(base, (void *)"\1c", 2); 340 qemu_chr_be_write(base, (void *)"hello", 6); 341 g_assert_cmpint(h1.read_count, ==, 0); 342 g_assert_cmpint(h2.read_count, ==, 6); 343 g_assert_cmpstr(h2.read_buf, ==, "hello"); 344 h2.read_count = 0; 345 346 /* print help */ 347 qemu_chr_be_write(base, (void *)"\1?", 2); 348 data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort); 349 g_assert_cmpint(strlen(data), !=, 0); 350 g_free(data); 351 352 qemu_chr_fe_deinit(&chr_be1, false); 353 354 qmp_chardev_remove("mux-label", &error); 355 g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label' is busy"); 356 error_free(error); 357 358 qemu_chr_fe_deinit(&chr_be2, false); 359 qmp_chardev_remove("mux-label", &error_abort); 360 } 361 362 static void char_hub_test(void) 363 { 364 QemuOpts *opts; 365 Chardev *hub, *chr1, *chr2, *base; 366 char *data; 367 FeHandler h = { 0, false, 0, false, }; 368 Error *error = NULL; 369 CharBackend chr_be; 370 int ret, i; 371 372 #define RB_SIZE 128 373 374 /* 375 * Create invalid hub 376 * 1. Create hub without a 'chardevs.N' defined (expect error) 377 */ 378 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0", 379 1, &error_abort); 380 qemu_opt_set(opts, "backend", "hub", &error_abort); 381 hub = qemu_chr_new_from_opts(opts, NULL, &error); 382 g_assert_cmpstr(error_get_pretty(error), ==, 383 "hub: 'chardevs' list is not defined"); 384 error_free(error); 385 error = NULL; 386 qemu_opts_del(opts); 387 388 /* 389 * Create invalid hub 390 * 1. Create chardev with embedded mux: 'mux=on' 391 * 2. Create hub which refers mux 392 * 3. Create hub which refers chardev already attached 393 * to the mux (already in use, expect error) 394 */ 395 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr0", 396 1, &error_abort); 397 qemu_opt_set(opts, "mux", "on", &error_abort); 398 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 399 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort); 400 base = qemu_chr_new_from_opts(opts, NULL, &error_abort); 401 g_assert_nonnull(base); 402 qemu_opts_del(opts); 403 404 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0", 405 1, &error_abort); 406 qemu_opt_set(opts, "backend", "hub", &error_abort); 407 qemu_opt_set(opts, "chardevs.0", "chr0", &error_abort); 408 hub = qemu_chr_new_from_opts(opts, NULL, &error); 409 g_assert_cmpstr(error_get_pretty(error), ==, 410 "hub: multiplexers and hub devices can't be " 411 "stacked, check chardev 'chr0', chardev should " 412 "not be a hub device or have 'mux=on' enabled"); 413 error_free(error); 414 error = NULL; 415 qemu_opts_del(opts); 416 417 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0", 418 1, &error_abort); 419 qemu_opt_set(opts, "backend", "hub", &error_abort); 420 qemu_opt_set(opts, "chardevs.0", "chr0-base", &error_abort); 421 hub = qemu_chr_new_from_opts(opts, NULL, &error); 422 g_assert_cmpstr(error_get_pretty(error), ==, 423 "chardev 'chr0-base' is already in use"); 424 error_free(error); 425 error = NULL; 426 qemu_opts_del(opts); 427 428 /* Finalize chr0 */ 429 qmp_chardev_remove("chr0", &error_abort); 430 431 /* 432 * Create invalid hub with more than maximum allowed backends 433 * 1. Create more than maximum allowed 'chardevs.%d' options for 434 * hub (expect error) 435 */ 436 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0", 437 1, &error_abort); 438 for (i = 0; i < 10; i++) { 439 char key[32], val[32]; 440 441 snprintf(key, sizeof(key), "chardevs.%d", i); 442 snprintf(val, sizeof(val), "chr%d", i); 443 qemu_opt_set(opts, key, val, &error); 444 if (error) { 445 char buf[64]; 446 447 snprintf(buf, sizeof(buf), "Invalid parameter 'chardevs.%d'", i); 448 g_assert_cmpstr(error_get_pretty(error), ==, buf); 449 error_free(error); 450 break; 451 } 452 } 453 g_assert_nonnull(error); 454 error = NULL; 455 qemu_opts_del(opts); 456 457 /* 458 * Create hub with 2 backend chardevs and 1 frontend and perform 459 * data aggregation 460 * 1. Create 2 ringbuf backend chardevs 461 * 2. Create 1 frontend 462 * 3. Create hub which refers 2 backend chardevs 463 * 4. Attach hub to a frontend 464 * 5. Attach hub to a frontend second time (expect error) 465 * 6. Perform data aggregation 466 * 7. Remove chr1 ("chr1 is busy", expect error) 467 * 8. Remove hub0 ("hub0 is busy", expect error); 468 * 9. Finilize frontend, hub and backend chardevs in correct order 469 */ 470 471 /* Create first chardev */ 472 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr1", 473 1, &error_abort); 474 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 475 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort); 476 chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); 477 g_assert_nonnull(chr1); 478 qemu_opts_del(opts); 479 480 /* Create second chardev */ 481 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr2", 482 1, &error_abort); 483 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 484 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort); 485 chr2 = qemu_chr_new_from_opts(opts, NULL, &error_abort); 486 g_assert_nonnull(chr2); 487 qemu_opts_del(opts); 488 489 /* Create hub0 and refer 2 backend chardevs */ 490 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0", 491 1, &error_abort); 492 qemu_opt_set(opts, "backend", "hub", &error_abort); 493 qemu_opt_set(opts, "chardevs.0", "chr1", &error_abort); 494 qemu_opt_set(opts, "chardevs.1", "chr2", &error_abort); 495 hub = qemu_chr_new_from_opts(opts, NULL, &error_abort); 496 g_assert_nonnull(hub); 497 qemu_opts_del(opts); 498 499 /* Attach hub to a frontend */ 500 qemu_chr_fe_init(&chr_be, hub, &error_abort); 501 qemu_chr_fe_set_handlers(&chr_be, 502 fe_can_read, 503 fe_read, 504 fe_event, 505 NULL, 506 &h, 507 NULL, true); 508 509 /* Fails second time */ 510 qemu_chr_fe_init(&chr_be, hub, &error); 511 g_assert_cmpstr(error_get_pretty(error), ==, "chardev 'hub0' is already in use"); 512 error_free(error); 513 error = NULL; 514 515 /* Write to backend, chr1 */ 516 base = qemu_chr_find("chr1"); 517 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0); 518 519 qemu_chr_be_write(base, (void *)"hello", 6); 520 g_assert_cmpint(h.read_count, ==, 6); 521 g_assert_cmpstr(h.read_buf, ==, "hello"); 522 h.read_count = 0; 523 524 /* Write to backend, chr2 */ 525 base = qemu_chr_find("chr2"); 526 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0); 527 528 qemu_chr_be_write(base, (void *)"olleh", 6); 529 g_assert_cmpint(h.read_count, ==, 6); 530 g_assert_cmpstr(h.read_buf, ==, "olleh"); 531 h.read_count = 0; 532 533 /* Write to frontend, chr_be */ 534 ret = qemu_chr_fe_write(&chr_be, (void *)"heyhey", 6); 535 g_assert_cmpint(ret, ==, 6); 536 537 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort); 538 g_assert_cmpint(strlen(data), ==, 6); 539 g_assert_cmpstr(data, ==, "heyhey"); 540 g_free(data); 541 542 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort); 543 g_assert_cmpint(strlen(data), ==, 6); 544 g_assert_cmpstr(data, ==, "heyhey"); 545 g_free(data); 546 547 /* Can't be removed, depends on hub0 */ 548 qmp_chardev_remove("chr1", &error); 549 g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'chr1' is busy"); 550 error_free(error); 551 error = NULL; 552 553 /* Can't be removed, depends on frontend chr_be */ 554 qmp_chardev_remove("hub0", &error); 555 g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'hub0' is busy"); 556 error_free(error); 557 error = NULL; 558 559 /* Finalize frontend */ 560 qemu_chr_fe_deinit(&chr_be, false); 561 562 /* Finalize hub0 */ 563 qmp_chardev_remove("hub0", &error_abort); 564 565 /* Finalize backend chardevs */ 566 qmp_chardev_remove("chr1", &error_abort); 567 qmp_chardev_remove("chr2", &error_abort); 568 569 #ifndef _WIN32 570 /* 571 * Create 3 backend chardevs to simulate EAGAIN and watcher. 572 * Mainly copied from char_pipe_test(). 573 * 1. Create 2 ringbuf backend chardevs 574 * 2. Create 1 pipe backend chardev 575 * 3. Create 1 frontend 576 * 4. Create hub which refers 2 backend chardevs 577 * 5. Attach hub to a frontend 578 * 6. Perform data aggregation and check watcher 579 * 7. Finilize frontend, hub and backend chardevs in correct order 580 */ 581 { 582 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 583 gchar *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL); 584 Chardev *chr3; 585 int fd, len; 586 char buf[128]; 587 588 in = g_strdup_printf("%s.in", pipe); 589 if (mkfifo(in, 0600) < 0) { 590 abort(); 591 } 592 out = g_strdup_printf("%s.out", pipe); 593 if (mkfifo(out, 0600) < 0) { 594 abort(); 595 } 596 597 /* Create first chardev */ 598 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr1", 599 1, &error_abort); 600 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 601 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort); 602 chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); 603 g_assert_nonnull(chr1); 604 qemu_opts_del(opts); 605 606 /* Create second chardev */ 607 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr2", 608 1, &error_abort); 609 qemu_opt_set(opts, "backend", "ringbuf", &error_abort); 610 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort); 611 chr2 = qemu_chr_new_from_opts(opts, NULL, &error_abort); 612 g_assert_nonnull(chr2); 613 qemu_opts_del(opts); 614 615 /* Create third chardev */ 616 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr3", 617 1, &error_abort); 618 qemu_opt_set(opts, "backend", "pipe", &error_abort); 619 qemu_opt_set(opts, "path", pipe, &error_abort); 620 chr3 = qemu_chr_new_from_opts(opts, NULL, &error_abort); 621 g_assert_nonnull(chr3); 622 623 /* Create hub0 and refer 3 backend chardevs */ 624 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0", 625 1, &error_abort); 626 qemu_opt_set(opts, "backend", "hub", &error_abort); 627 qemu_opt_set(opts, "chardevs.0", "chr1", &error_abort); 628 qemu_opt_set(opts, "chardevs.1", "chr2", &error_abort); 629 qemu_opt_set(opts, "chardevs.2", "chr3", &error_abort); 630 hub = qemu_chr_new_from_opts(opts, NULL, &error_abort); 631 g_assert_nonnull(hub); 632 qemu_opts_del(opts); 633 634 /* Attach hub to a frontend */ 635 qemu_chr_fe_init(&chr_be, hub, &error_abort); 636 qemu_chr_fe_set_handlers(&chr_be, 637 fe_can_read, 638 fe_read, 639 fe_event, 640 NULL, 641 &h, 642 NULL, true); 643 644 /* Write to frontend, chr_be */ 645 ret = qemu_chr_fe_write(&chr_be, (void *)"thisis", 6); 646 g_assert_cmpint(ret, ==, 6); 647 648 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort); 649 g_assert_cmpint(strlen(data), ==, 6); 650 g_assert_cmpstr(data, ==, "thisis"); 651 g_free(data); 652 653 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort); 654 g_assert_cmpint(strlen(data), ==, 6); 655 g_assert_cmpstr(data, ==, "thisis"); 656 g_free(data); 657 658 fd = open(out, O_RDWR); 659 ret = read(fd, buf, sizeof(buf)); 660 g_assert_cmpint(ret, ==, 6); 661 buf[ret] = 0; 662 g_assert_cmpstr(buf, ==, "thisis"); 663 close(fd); 664 665 /* Add watch. 0 indicates no watches if nothing to wait for */ 666 ret = qemu_chr_fe_add_watch(&chr_be, G_IO_OUT | G_IO_HUP, 667 NULL, NULL); 668 g_assert_cmpint(ret, ==, 0); 669 670 /* 671 * Write to frontend, chr_be, until EAGAIN. Make sure length is 672 * power of two to fit nicely the whole pipe buffer. 673 */ 674 len = 0; 675 while ((ret = qemu_chr_fe_write(&chr_be, (void *)"thisisit", 8)) 676 != -1) { 677 len += ret; 678 } 679 g_assert_cmpint(errno, ==, EAGAIN); 680 681 /* Further all writes should cause EAGAIN */ 682 ret = qemu_chr_fe_write(&chr_be, (void *)"b", 1); 683 g_assert_cmpint(ret, ==, -1); 684 g_assert_cmpint(errno, ==, EAGAIN); 685 686 /* 687 * Add watch. Non 0 indicates we have a blocked chardev, which 688 * can wakes us up when write is possible. 689 */ 690 ret = qemu_chr_fe_add_watch(&chr_be, G_IO_OUT | G_IO_HUP, 691 NULL, NULL); 692 g_assert_cmpint(ret, !=, 0); 693 g_source_remove(ret); 694 695 /* Drain pipe and ring buffers */ 696 fd = open(out, O_RDWR); 697 while ((ret = read(fd, buf, MIN(sizeof(buf), len))) != -1 && len > 0) { 698 len -= ret; 699 } 700 close(fd); 701 702 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort); 703 g_assert_cmpint(strlen(data), ==, 128); 704 g_free(data); 705 706 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort); 707 g_assert_cmpint(strlen(data), ==, 128); 708 g_free(data); 709 710 /* 711 * Now we are good to go, first repeat "lost" sequence, which 712 * was already consumed and drained by the ring buffers, but 713 * pipe have not recieved that yet. 714 */ 715 ret = qemu_chr_fe_write(&chr_be, (void *)"thisisit", 8); 716 g_assert_cmpint(ret, ==, 8); 717 718 ret = qemu_chr_fe_write(&chr_be, (void *)"streamisrestored", 16); 719 g_assert_cmpint(ret, ==, 16); 720 721 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort); 722 g_assert_cmpint(strlen(data), ==, 16); 723 /* Only last 16 bytes, see big comment above */ 724 g_assert_cmpstr(data, ==, "streamisrestored"); 725 g_free(data); 726 727 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort); 728 g_assert_cmpint(strlen(data), ==, 16); 729 /* Only last 16 bytes, see big comment above */ 730 g_assert_cmpstr(data, ==, "streamisrestored"); 731 g_free(data); 732 733 fd = open(out, O_RDWR); 734 ret = read(fd, buf, sizeof(buf)); 735 g_assert_cmpint(ret, ==, 24); 736 buf[ret] = 0; 737 /* Both 8 and 16 bytes */ 738 g_assert_cmpstr(buf, ==, "thisisitstreamisrestored"); 739 close(fd); 740 741 g_free(in); 742 g_free(out); 743 g_free(tmp_path); 744 g_free(pipe); 745 746 /* Finalize frontend */ 747 qemu_chr_fe_deinit(&chr_be, false); 748 749 /* Finalize hub0 */ 750 qmp_chardev_remove("hub0", &error_abort); 751 752 /* Finalize backend chardevs */ 753 qmp_chardev_remove("chr1", &error_abort); 754 qmp_chardev_remove("chr2", &error_abort); 755 qmp_chardev_remove("chr3", &error_abort); 756 } 757 #endif 758 } 759 760 static void websock_server_read(void *opaque, const uint8_t *buf, int size) 761 { 762 g_assert_cmpint(size, ==, 5); 763 g_assert(memcmp(buf, "world", size) == 0); 764 quit = true; 765 } 766 767 768 static int websock_server_can_read(void *opaque) 769 { 770 return 10; 771 } 772 773 774 static bool websock_check_http_headers(char *buf, int size) 775 { 776 int i; 777 const char *ans[] = { "HTTP/1.1 101 Switching Protocols\r\n", 778 "Server: QEMU VNC\r\n", 779 "Upgrade: websocket\r\n", 780 "Connection: Upgrade\r\n", 781 "Sec-WebSocket-Accept:", 782 "Sec-WebSocket-Protocol: binary\r\n" }; 783 784 for (i = 0; i < 6; i++) { 785 if (g_strstr_len(buf, size, ans[i]) == NULL) { 786 return false; 787 } 788 } 789 790 return true; 791 } 792 793 794 static void websock_client_read(void *opaque, const uint8_t *buf, int size) 795 { 796 const uint8_t ping[] = { 0x89, 0x85, /* Ping header */ 797 0x07, 0x77, 0x9e, 0xf9, /* Masking key */ 798 0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ }; 799 800 const uint8_t binary[] = { 0x82, 0x85, /* Binary header */ 801 0x74, 0x90, 0xb9, 0xdf, /* Masking key */ 802 0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ }; 803 Chardev *chr_client = opaque; 804 805 if (websock_check_http_headers((char *) buf, size)) { 806 qemu_chr_fe_write(chr_client->be, ping, sizeof(ping)); 807 } else if (buf[0] == 0x8a && buf[1] == 0x05) { 808 g_assert(strncmp((char *) buf + 2, "hello", 5) == 0); 809 qemu_chr_fe_write(chr_client->be, binary, sizeof(binary)); 810 } else { 811 g_assert(buf[0] == 0x88 && buf[1] == 0x16); 812 g_assert(strncmp((char *) buf + 4, "peer requested close", 10) == 0); 813 quit = true; 814 } 815 } 816 817 818 static int websock_client_can_read(void *opaque) 819 { 820 return 4096; 821 } 822 823 824 static void char_websock_test(void) 825 { 826 QObject *addr; 827 QDict *qdict; 828 const char *port; 829 char *tmp; 830 char *handshake_port; 831 CharBackend be; 832 CharBackend client_be; 833 Chardev *chr_client; 834 Chardev *chr = qemu_chr_new("server", 835 "websocket:127.0.0.1:0,server=on,wait=off", NULL); 836 const char handshake[] = "GET / HTTP/1.1\r\n" 837 "Upgrade: websocket\r\n" 838 "Connection: Upgrade\r\n" 839 "Host: localhost:%s\r\n" 840 "Origin: http://localhost:%s\r\n" 841 "Sec-WebSocket-Key: o9JHNiS3/0/0zYE1wa3yIw==\r\n" 842 "Sec-WebSocket-Version: 13\r\n" 843 "Sec-WebSocket-Protocol: binary\r\n\r\n"; 844 const uint8_t close[] = { 0x88, 0x82, /* Close header */ 845 0xef, 0xaa, 0xc5, 0x97, /* Masking key */ 846 0xec, 0x42 /* Status code */ }; 847 848 addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 849 qdict = qobject_to(QDict, addr); 850 port = qdict_get_str(qdict, "port"); 851 tmp = g_strdup_printf("tcp:127.0.0.1:%s", port); 852 handshake_port = g_strdup_printf(handshake, port, port); 853 qobject_unref(qdict); 854 855 qemu_chr_fe_init(&be, chr, &error_abort); 856 qemu_chr_fe_set_handlers(&be, websock_server_can_read, websock_server_read, 857 NULL, NULL, chr, NULL, true); 858 859 chr_client = qemu_chr_new("client", tmp, NULL); 860 qemu_chr_fe_init(&client_be, chr_client, &error_abort); 861 qemu_chr_fe_set_handlers(&client_be, websock_client_can_read, 862 websock_client_read, 863 NULL, NULL, chr_client, NULL, true); 864 g_free(tmp); 865 866 qemu_chr_write_all(chr_client, 867 (uint8_t *) handshake_port, 868 strlen(handshake_port)); 869 g_free(handshake_port); 870 main_loop(); 871 872 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 873 g_assert(object_property_get_bool(OBJECT(chr_client), 874 "connected", &error_abort)); 875 876 qemu_chr_write_all(chr_client, close, sizeof(close)); 877 main_loop(); 878 879 object_unparent(OBJECT(chr_client)); 880 object_unparent(OBJECT(chr)); 881 } 882 883 884 #ifndef _WIN32 885 static void char_pipe_test(void) 886 { 887 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 888 gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL); 889 Chardev *chr; 890 CharBackend be; 891 int ret, fd; 892 char buf[10]; 893 FeHandler fe = { 0, }; 894 895 in = g_strdup_printf("%s.in", pipe); 896 if (mkfifo(in, 0600) < 0) { 897 abort(); 898 } 899 out = g_strdup_printf("%s.out", pipe); 900 if (mkfifo(out, 0600) < 0) { 901 abort(); 902 } 903 904 tmp = g_strdup_printf("pipe:%s", pipe); 905 chr = qemu_chr_new("pipe", tmp, NULL); 906 g_assert_nonnull(chr); 907 g_free(tmp); 908 909 qemu_chr_fe_init(&be, chr, &error_abort); 910 911 ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9); 912 g_assert_cmpint(ret, ==, 9); 913 914 fd = open(out, O_RDWR); 915 ret = read(fd, buf, sizeof(buf)); 916 g_assert_cmpint(ret, ==, 9); 917 g_assert_cmpstr(buf, ==, "pipe-out"); 918 close(fd); 919 920 fd = open(in, O_WRONLY); 921 ret = write(fd, "pipe-in", 8); 922 g_assert_cmpint(ret, ==, 8); 923 close(fd); 924 925 qemu_chr_fe_set_handlers(&be, 926 fe_can_read, 927 fe_read, 928 fe_event, 929 NULL, 930 &fe, 931 NULL, true); 932 933 main_loop(); 934 935 g_assert_cmpint(fe.read_count, ==, 8); 936 g_assert_cmpstr(fe.read_buf, ==, "pipe-in"); 937 938 qemu_chr_fe_deinit(&be, true); 939 940 g_assert(g_unlink(in) == 0); 941 g_assert(g_unlink(out) == 0); 942 g_assert(g_rmdir(tmp_path) == 0); 943 g_free(in); 944 g_free(out); 945 g_free(tmp_path); 946 g_free(pipe); 947 } 948 #endif 949 950 typedef struct SocketIdleData { 951 GMainLoop *loop; 952 Chardev *chr; 953 bool conn_expected; 954 CharBackend *be; 955 CharBackend *client_be; 956 } SocketIdleData; 957 958 959 static void socket_read_hello(void *opaque, const uint8_t *buf, int size) 960 { 961 g_assert_cmpint(size, ==, 5); 962 g_assert(strncmp((char *)buf, "hello", 5) == 0); 963 964 quit = true; 965 } 966 967 static int socket_can_read_hello(void *opaque) 968 { 969 return 10; 970 } 971 972 static int make_udp_socket(int *port) 973 { 974 struct sockaddr_in addr = { 0, }; 975 socklen_t alen = sizeof(addr); 976 int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0); 977 978 g_assert_cmpint(sock, >=, 0); 979 addr.sin_family = AF_INET ; 980 addr.sin_addr.s_addr = htonl(INADDR_ANY); 981 addr.sin_port = 0; 982 ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); 983 g_assert_cmpint(ret, ==, 0); 984 ret = getsockname(sock, (struct sockaddr *)&addr, &alen); 985 g_assert_cmpint(ret, ==, 0); 986 987 *port = ntohs(addr.sin_port); 988 return sock; 989 } 990 991 static void char_udp_test_internal(Chardev *reuse_chr, int sock) 992 { 993 struct sockaddr_in other; 994 SocketIdleData d = { 0, }; 995 Chardev *chr; 996 CharBackend stack_be, *be = &stack_be; 997 socklen_t alen = sizeof(other); 998 int ret; 999 char buf[10]; 1000 char *tmp = NULL; 1001 1002 if (reuse_chr) { 1003 chr = reuse_chr; 1004 be = chr->be; 1005 } else { 1006 int port; 1007 sock = make_udp_socket(&port); 1008 tmp = g_strdup_printf("udp:127.0.0.1:%d", port); 1009 chr = qemu_chr_new("client", tmp, NULL); 1010 g_assert_nonnull(chr); 1011 1012 qemu_chr_fe_init(be, chr, &error_abort); 1013 } 1014 1015 d.chr = chr; 1016 qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello, 1017 NULL, NULL, &d, NULL, true); 1018 ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5); 1019 g_assert_cmpint(ret, ==, 5); 1020 1021 ret = recvfrom(sock, buf, sizeof(buf), 0, 1022 (struct sockaddr *)&other, &alen); 1023 g_assert_cmpint(ret, ==, 5); 1024 ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen); 1025 g_assert_cmpint(ret, ==, 5); 1026 1027 main_loop(); 1028 1029 if (!reuse_chr) { 1030 close(sock); 1031 qemu_chr_fe_deinit(be, true); 1032 } 1033 g_free(tmp); 1034 } 1035 1036 static void char_udp_test(void) 1037 { 1038 char_udp_test_internal(NULL, 0); 1039 } 1040 1041 1042 typedef struct { 1043 int event; 1044 bool got_pong; 1045 CharBackend *be; 1046 } CharSocketTestData; 1047 1048 1049 #define SOCKET_PING "Hello" 1050 #define SOCKET_PONG "World" 1051 1052 typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event); 1053 1054 static void 1055 char_socket_event(void *opaque, QEMUChrEvent event) 1056 { 1057 CharSocketTestData *data = opaque; 1058 data->event = event; 1059 } 1060 1061 static void 1062 char_socket_event_with_error(void *opaque, QEMUChrEvent event) 1063 { 1064 static bool first_error; 1065 CharSocketTestData *data = opaque; 1066 CharBackend *be = data->be; 1067 data->event = event; 1068 switch (event) { 1069 case CHR_EVENT_OPENED: 1070 if (!first_error) { 1071 first_error = true; 1072 qemu_chr_fe_disconnect(be); 1073 } 1074 return; 1075 case CHR_EVENT_CLOSED: 1076 return; 1077 default: 1078 return; 1079 } 1080 } 1081 1082 1083 static void 1084 char_socket_read(void *opaque, const uint8_t *buf, int size) 1085 { 1086 CharSocketTestData *data = opaque; 1087 g_assert_cmpint(size, ==, sizeof(SOCKET_PONG)); 1088 g_assert(memcmp(buf, SOCKET_PONG, size) == 0); 1089 data->got_pong = true; 1090 } 1091 1092 1093 static int 1094 char_socket_can_read(void *opaque) 1095 { 1096 return sizeof(SOCKET_PONG); 1097 } 1098 1099 1100 static char * 1101 char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass, 1102 const char *reconnect, bool is_listen) 1103 { 1104 if (fd_pass) { 1105 QIOChannelSocket *ioc = qio_channel_socket_new(); 1106 int fd; 1107 char *optstr; 1108 g_assert(!reconnect); 1109 if (is_listen) { 1110 qio_channel_socket_listen_sync(ioc, addr, 1, &error_abort); 1111 } else { 1112 qio_channel_socket_connect_sync(ioc, addr, &error_abort); 1113 } 1114 fd = ioc->fd; 1115 ioc->fd = -1; 1116 optstr = g_strdup_printf("socket,id=cdev0,fd=%d%s", 1117 fd, is_listen ? ",server=on,wait=off" : ""); 1118 object_unref(OBJECT(ioc)); 1119 return optstr; 1120 } else { 1121 switch (addr->type) { 1122 case SOCKET_ADDRESS_TYPE_INET: 1123 return g_strdup_printf("socket,id=cdev0,host=%s,port=%s%s%s", 1124 addr->u.inet.host, 1125 addr->u.inet.port, 1126 reconnect ? reconnect : "", 1127 is_listen ? ",server=on,wait=off" : ""); 1128 1129 case SOCKET_ADDRESS_TYPE_UNIX: 1130 return g_strdup_printf("socket,id=cdev0,path=%s%s%s", 1131 addr->u.q_unix.path, 1132 reconnect ? reconnect : "", 1133 is_listen ? ",server=on,wait=off" : ""); 1134 1135 default: 1136 g_assert_not_reached(); 1137 } 1138 } 1139 } 1140 1141 1142 static int 1143 char_socket_ping_pong(QIOChannel *ioc, Error **errp) 1144 { 1145 char greeting[sizeof(SOCKET_PING)]; 1146 const char *response = SOCKET_PONG; 1147 1148 int ret; 1149 ret = qio_channel_read_all(ioc, greeting, sizeof(greeting), errp); 1150 if (ret != 0) { 1151 object_unref(OBJECT(ioc)); 1152 return -1; 1153 } 1154 1155 g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0); 1156 1157 qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), errp); 1158 object_unref(OBJECT(ioc)); 1159 return 0; 1160 } 1161 1162 1163 static gpointer 1164 char_socket_server_client_thread(gpointer data) 1165 { 1166 SocketAddress *addr = data; 1167 QIOChannelSocket *ioc = qio_channel_socket_new(); 1168 1169 qio_channel_socket_connect_sync(ioc, addr, &error_abort); 1170 1171 char_socket_ping_pong(QIO_CHANNEL(ioc), &error_abort); 1172 1173 return NULL; 1174 } 1175 1176 1177 typedef struct { 1178 SocketAddress *addr; 1179 bool wait_connected; 1180 bool fd_pass; 1181 } CharSocketServerTestConfig; 1182 1183 1184 static void char_socket_server_test(gconstpointer opaque) 1185 { 1186 const CharSocketServerTestConfig *config = opaque; 1187 Chardev *chr; 1188 CharBackend be = {0}; 1189 CharSocketTestData data = {0}; 1190 QObject *qaddr; 1191 SocketAddress *addr; 1192 Visitor *v; 1193 QemuThread thread; 1194 int ret; 1195 bool reconnected = false; 1196 char *optstr; 1197 QemuOpts *opts; 1198 1199 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1200 /* 1201 * We rely on config->addr containing "wait=off", otherwise 1202 * qemu_chr_new() will block until a client connects. We 1203 * can't spawn our client thread though, because until 1204 * qemu_chr_new() returns we don't know what TCP port was 1205 * allocated by the OS 1206 */ 1207 optstr = char_socket_addr_to_opt_str(config->addr, 1208 config->fd_pass, 1209 NULL, 1210 true); 1211 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1212 optstr, true); 1213 g_assert_nonnull(opts); 1214 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1215 qemu_opts_del(opts); 1216 g_assert_nonnull(chr); 1217 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1218 1219 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 1220 g_assert_nonnull(qaddr); 1221 1222 v = qobject_input_visitor_new(qaddr); 1223 visit_type_SocketAddress(v, "addr", &addr, &error_abort); 1224 visit_free(v); 1225 qobject_unref(qaddr); 1226 1227 qemu_chr_fe_init(&be, chr, &error_abort); 1228 1229 reconnect: 1230 data.event = -1; 1231 data.be = &be; 1232 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1233 char_socket_event, NULL, 1234 &data, NULL, true); 1235 g_assert(data.event == -1); 1236 1237 /* 1238 * Kick off a thread to act as the "remote" client 1239 * which just plays ping-pong with us 1240 */ 1241 qemu_thread_create(&thread, "client", 1242 char_socket_server_client_thread, 1243 addr, QEMU_THREAD_JOINABLE); 1244 g_assert(data.event == -1); 1245 1246 if (config->wait_connected) { 1247 /* Synchronously accept a connection */ 1248 qemu_chr_wait_connected(chr, &error_abort); 1249 } else { 1250 /* 1251 * Asynchronously accept a connection when the evnt 1252 * loop reports the listener socket as readable 1253 */ 1254 while (data.event == -1) { 1255 main_loop_wait(false); 1256 } 1257 } 1258 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1259 g_assert(data.event == CHR_EVENT_OPENED); 1260 data.event = -1; 1261 1262 /* Send a greeting to the client */ 1263 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING, 1264 sizeof(SOCKET_PING)); 1265 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING)); 1266 g_assert(data.event == -1); 1267 1268 /* Setup a callback to receive the reply to our greeting */ 1269 qemu_chr_fe_set_handlers(&be, char_socket_can_read, 1270 char_socket_read, 1271 char_socket_event, NULL, 1272 &data, NULL, true); 1273 g_assert(data.event == CHR_EVENT_OPENED); 1274 data.event = -1; 1275 1276 /* Wait for the client to go away */ 1277 while (data.event == -1) { 1278 main_loop_wait(false); 1279 } 1280 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1281 g_assert(data.event == CHR_EVENT_CLOSED); 1282 g_assert(data.got_pong); 1283 1284 qemu_thread_join(&thread); 1285 1286 if (!reconnected) { 1287 reconnected = true; 1288 goto reconnect; 1289 } 1290 1291 qapi_free_SocketAddress(addr); 1292 object_unparent(OBJECT(chr)); 1293 g_free(optstr); 1294 g_unsetenv("QTEST_SILENT_ERRORS"); 1295 } 1296 1297 1298 static gpointer 1299 char_socket_client_server_thread(gpointer data) 1300 { 1301 QIOChannelSocket *ioc = data; 1302 QIOChannelSocket *cioc; 1303 1304 retry: 1305 cioc = qio_channel_socket_accept(ioc, &error_abort); 1306 g_assert_nonnull(cioc); 1307 1308 if (char_socket_ping_pong(QIO_CHANNEL(cioc), NULL) != 0) { 1309 goto retry; 1310 } 1311 1312 return NULL; 1313 } 1314 1315 1316 typedef struct { 1317 SocketAddress *addr; 1318 const char *reconnect; 1319 bool wait_connected; 1320 bool fd_pass; 1321 char_socket_cb event_cb; 1322 } CharSocketClientTestConfig; 1323 1324 static void char_socket_client_dupid_test(gconstpointer opaque) 1325 { 1326 const CharSocketClientTestConfig *config = opaque; 1327 QIOChannelSocket *ioc; 1328 char *optstr; 1329 Chardev *chr1, *chr2; 1330 SocketAddress *addr; 1331 QemuOpts *opts; 1332 Error *local_err = NULL; 1333 1334 /* 1335 * Setup a listener socket and determine get its address 1336 * so we know the TCP port for the client later 1337 */ 1338 ioc = qio_channel_socket_new(); 1339 g_assert_nonnull(ioc); 1340 qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); 1341 addr = qio_channel_socket_get_local_address(ioc, &error_abort); 1342 g_assert_nonnull(addr); 1343 1344 /* 1345 * Populate the chardev address based on what the server 1346 * is actually listening on 1347 */ 1348 optstr = char_socket_addr_to_opt_str(addr, 1349 config->fd_pass, 1350 config->reconnect, 1351 false); 1352 1353 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1354 optstr, true); 1355 g_assert_nonnull(opts); 1356 chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1357 g_assert_nonnull(chr1); 1358 qemu_chr_wait_connected(chr1, &error_abort); 1359 1360 chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err); 1361 g_assert_null(chr2); 1362 error_free_or_abort(&local_err); 1363 1364 object_unref(OBJECT(ioc)); 1365 qemu_opts_del(opts); 1366 object_unparent(OBJECT(chr1)); 1367 qapi_free_SocketAddress(addr); 1368 g_free(optstr); 1369 } 1370 1371 static void char_socket_client_test(gconstpointer opaque) 1372 { 1373 const CharSocketClientTestConfig *config = opaque; 1374 const char_socket_cb event_cb = config->event_cb; 1375 QIOChannelSocket *ioc; 1376 char *optstr; 1377 Chardev *chr; 1378 CharBackend be = {0}; 1379 CharSocketTestData data = {0}; 1380 SocketAddress *addr; 1381 QemuThread thread; 1382 int ret; 1383 bool reconnected = false; 1384 QemuOpts *opts; 1385 1386 /* 1387 * Setup a listener socket and determine get its address 1388 * so we know the TCP port for the client later 1389 */ 1390 ioc = qio_channel_socket_new(); 1391 g_assert_nonnull(ioc); 1392 qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); 1393 addr = qio_channel_socket_get_local_address(ioc, &error_abort); 1394 g_assert_nonnull(addr); 1395 1396 /* 1397 * Kick off a thread to act as the "remote" client 1398 * which just plays ping-pong with us 1399 */ 1400 qemu_thread_create(&thread, "client", 1401 char_socket_client_server_thread, 1402 ioc, QEMU_THREAD_JOINABLE); 1403 1404 /* 1405 * Populate the chardev address based on what the server 1406 * is actually listening on 1407 */ 1408 optstr = char_socket_addr_to_opt_str(addr, 1409 config->fd_pass, 1410 config->reconnect, 1411 false); 1412 1413 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1414 optstr, true); 1415 g_assert_nonnull(opts); 1416 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1417 qemu_opts_del(opts); 1418 g_assert_nonnull(chr); 1419 1420 if (config->reconnect) { 1421 /* 1422 * If reconnect is set, the connection will be 1423 * established in a background thread and we won't 1424 * see the "connected" status updated until we 1425 * run the main event loop, or call qemu_chr_wait_connected 1426 */ 1427 g_assert(!object_property_get_bool(OBJECT(chr), "connected", 1428 &error_abort)); 1429 } else { 1430 g_assert(object_property_get_bool(OBJECT(chr), "connected", 1431 &error_abort)); 1432 } 1433 1434 qemu_chr_fe_init(&be, chr, &error_abort); 1435 1436 reconnect: 1437 data.event = -1; 1438 data.be = &be; 1439 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1440 event_cb, NULL, 1441 &data, NULL, true); 1442 if (config->reconnect) { 1443 g_assert(data.event == -1); 1444 } else { 1445 g_assert(data.event == CHR_EVENT_OPENED); 1446 } 1447 1448 if (config->wait_connected) { 1449 /* 1450 * Synchronously wait for the connection to complete 1451 * This should be a no-op if reconnect is not set. 1452 */ 1453 qemu_chr_wait_connected(chr, &error_abort); 1454 } else { 1455 /* 1456 * Asynchronously wait for the connection to be reported 1457 * as complete when the background thread reports its 1458 * status. 1459 * The loop will short-circuit if reconnect was set 1460 */ 1461 while (data.event == -1) { 1462 main_loop_wait(false); 1463 } 1464 } 1465 g_assert(data.event == CHR_EVENT_OPENED); 1466 data.event = -1; 1467 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1468 1469 /* Send a greeting to the server */ 1470 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING, 1471 sizeof(SOCKET_PING)); 1472 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING)); 1473 g_assert(data.event == -1); 1474 1475 /* Setup a callback to receive the reply to our greeting */ 1476 qemu_chr_fe_set_handlers(&be, char_socket_can_read, 1477 char_socket_read, 1478 event_cb, NULL, 1479 &data, NULL, true); 1480 g_assert(data.event == CHR_EVENT_OPENED); 1481 data.event = -1; 1482 1483 /* Wait for the server to go away */ 1484 while (data.event == -1) { 1485 main_loop_wait(false); 1486 } 1487 g_assert(data.event == CHR_EVENT_CLOSED); 1488 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1489 g_assert(data.got_pong); 1490 qemu_thread_join(&thread); 1491 1492 if (config->reconnect && !reconnected) { 1493 reconnected = true; 1494 qemu_thread_create(&thread, "client", 1495 char_socket_client_server_thread, 1496 ioc, QEMU_THREAD_JOINABLE); 1497 goto reconnect; 1498 } 1499 1500 object_unref(OBJECT(ioc)); 1501 object_unparent(OBJECT(chr)); 1502 qapi_free_SocketAddress(addr); 1503 g_free(optstr); 1504 } 1505 1506 static void 1507 count_closed_event(void *opaque, QEMUChrEvent event) 1508 { 1509 int *count = opaque; 1510 if (event == CHR_EVENT_CLOSED) { 1511 (*count)++; 1512 } 1513 } 1514 1515 static void 1516 char_socket_discard_read(void *opaque, const uint8_t *buf, int size) 1517 { 1518 } 1519 1520 static void char_socket_server_two_clients_test(gconstpointer opaque) 1521 { 1522 SocketAddress *incoming_addr = (gpointer) opaque; 1523 Chardev *chr; 1524 CharBackend be = {0}; 1525 QObject *qaddr; 1526 SocketAddress *addr; 1527 Visitor *v; 1528 char *optstr; 1529 QemuOpts *opts; 1530 QIOChannelSocket *ioc1, *ioc2; 1531 int closed = 0; 1532 1533 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1534 /* 1535 * We rely on addr containing "wait=off", otherwise 1536 * qemu_chr_new() will block until a client connects. We 1537 * can't spawn our client thread though, because until 1538 * qemu_chr_new() returns we don't know what TCP port was 1539 * allocated by the OS 1540 */ 1541 optstr = char_socket_addr_to_opt_str(incoming_addr, 1542 false, 1543 NULL, 1544 true); 1545 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1546 optstr, true); 1547 g_assert_nonnull(opts); 1548 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1549 qemu_opts_del(opts); 1550 g_assert_nonnull(chr); 1551 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1552 1553 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 1554 g_assert_nonnull(qaddr); 1555 1556 v = qobject_input_visitor_new(qaddr); 1557 visit_type_SocketAddress(v, "addr", &addr, &error_abort); 1558 visit_free(v); 1559 qobject_unref(qaddr); 1560 1561 qemu_chr_fe_init(&be, chr, &error_abort); 1562 1563 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read, 1564 count_closed_event, NULL, 1565 &closed, NULL, true); 1566 1567 ioc1 = qio_channel_socket_new(); 1568 qio_channel_socket_connect_sync(ioc1, addr, &error_abort); 1569 qemu_chr_wait_connected(chr, &error_abort); 1570 1571 /* switch the chardev to another context */ 1572 GMainContext *ctx = g_main_context_new(); 1573 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read, 1574 count_closed_event, NULL, 1575 &closed, ctx, true); 1576 1577 /* Start a second connection while the first is still connected. 1578 * It will be placed in the listen() backlog, and connect() will 1579 * succeed immediately. 1580 */ 1581 ioc2 = qio_channel_socket_new(); 1582 qio_channel_socket_connect_sync(ioc2, addr, &error_abort); 1583 1584 object_unref(OBJECT(ioc1)); 1585 /* The two connections should now be processed serially. */ 1586 while (g_main_context_iteration(ctx, TRUE)) { 1587 if (closed == 1 && ioc2) { 1588 object_unref(OBJECT(ioc2)); 1589 ioc2 = NULL; 1590 } 1591 if (closed == 2) { 1592 break; 1593 } 1594 } 1595 1596 qapi_free_SocketAddress(addr); 1597 object_unparent(OBJECT(chr)); 1598 g_main_context_unref(ctx); 1599 g_free(optstr); 1600 g_unsetenv("QTEST_SILENT_ERRORS"); 1601 } 1602 1603 1604 #if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) 1605 static void char_serial_test(void) 1606 { 1607 QemuOpts *opts; 1608 Chardev *chr; 1609 1610 opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id", 1611 1, &error_abort); 1612 qemu_opt_set(opts, "backend", "serial", &error_abort); 1613 qemu_opt_set(opts, "path", "/dev/null", &error_abort); 1614 1615 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 1616 g_assert_nonnull(chr); 1617 /* TODO: add more tests with a pty */ 1618 object_unparent(OBJECT(chr)); 1619 1620 qemu_opts_del(opts); 1621 } 1622 #endif 1623 1624 #if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32) 1625 static void char_parallel_test(void) 1626 { 1627 QemuOpts *opts; 1628 Chardev *chr; 1629 1630 opts = qemu_opts_create(qemu_find_opts("chardev"), "parallel-id", 1631 1, &error_abort); 1632 qemu_opt_set(opts, "backend", "parallel", &error_abort); 1633 qemu_opt_set(opts, "path", "/dev/null", &error_abort); 1634 1635 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 1636 #ifdef __linux__ 1637 /* fails to PPCLAIM, see qemu_chr_open_pp_fd() */ 1638 g_assert_null(chr); 1639 #else 1640 g_assert_nonnull(chr); 1641 object_unparent(OBJECT(chr)); 1642 #endif 1643 1644 qemu_opts_del(opts); 1645 } 1646 #endif 1647 1648 #ifndef _WIN32 1649 static void char_file_fifo_test(void) 1650 { 1651 Chardev *chr; 1652 CharBackend be; 1653 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1654 char *fifo = g_build_filename(tmp_path, "fifo", NULL); 1655 char *out = g_build_filename(tmp_path, "out", NULL); 1656 ChardevFile file = { .in = fifo, 1657 .out = out }; 1658 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1659 .u.file.data = &file }; 1660 FeHandler fe = { 0, }; 1661 int fd, ret; 1662 1663 if (mkfifo(fifo, 0600) < 0) { 1664 abort(); 1665 } 1666 1667 fd = open(fifo, O_RDWR); 1668 ret = write(fd, "fifo-in", 8); 1669 g_assert_cmpint(ret, ==, 8); 1670 1671 chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend, 1672 NULL, &error_abort); 1673 1674 qemu_chr_fe_init(&be, chr, &error_abort); 1675 qemu_chr_fe_set_handlers(&be, 1676 fe_can_read, 1677 fe_read, 1678 fe_event, 1679 NULL, 1680 &fe, NULL, true); 1681 1682 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK); 1683 qmp_chardev_send_break("label-foo", NULL); 1684 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK); 1685 qmp_chardev_send_break("label-file", NULL); 1686 g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK); 1687 1688 main_loop(); 1689 1690 close(fd); 1691 1692 g_assert_cmpint(fe.read_count, ==, 8); 1693 g_assert_cmpstr(fe.read_buf, ==, "fifo-in"); 1694 1695 qemu_chr_fe_deinit(&be, true); 1696 1697 g_unlink(fifo); 1698 g_free(fifo); 1699 g_unlink(out); 1700 g_free(out); 1701 g_rmdir(tmp_path); 1702 g_free(tmp_path); 1703 } 1704 #endif 1705 1706 static void char_file_test_internal(Chardev *ext_chr, const char *filepath) 1707 { 1708 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1709 char *out; 1710 Chardev *chr; 1711 char *contents = NULL; 1712 ChardevFile file = {}; 1713 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1714 .u.file.data = &file }; 1715 gsize length; 1716 int ret; 1717 1718 if (ext_chr) { 1719 chr = ext_chr; 1720 out = g_strdup(filepath); 1721 file.out = out; 1722 } else { 1723 out = g_build_filename(tmp_path, "out", NULL); 1724 file.out = out; 1725 chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend, 1726 NULL, &error_abort); 1727 } 1728 ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6); 1729 g_assert_cmpint(ret, ==, 6); 1730 1731 ret = g_file_get_contents(out, &contents, &length, NULL); 1732 g_assert(ret == TRUE); 1733 g_assert_cmpint(length, ==, 6); 1734 g_assert(strncmp(contents, "hello!", 6) == 0); 1735 1736 if (!ext_chr) { 1737 object_unparent(OBJECT(chr)); 1738 g_unlink(out); 1739 } 1740 g_free(contents); 1741 g_rmdir(tmp_path); 1742 g_free(tmp_path); 1743 g_free(out); 1744 } 1745 1746 static void char_file_test(void) 1747 { 1748 char_file_test_internal(NULL, NULL); 1749 } 1750 1751 static void char_null_test(void) 1752 { 1753 Error *err = NULL; 1754 Chardev *chr; 1755 CharBackend be; 1756 int ret; 1757 1758 chr = qemu_chr_find("label-null"); 1759 g_assert_null(chr); 1760 1761 chr = qemu_chr_new("label-null", "null", NULL); 1762 chr = qemu_chr_find("label-null"); 1763 g_assert_nonnull(chr); 1764 1765 g_assert(qemu_chr_has_feature(chr, 1766 QEMU_CHAR_FEATURE_FD_PASS) == false); 1767 g_assert(qemu_chr_has_feature(chr, 1768 QEMU_CHAR_FEATURE_RECONNECTABLE) == false); 1769 1770 /* check max avail */ 1771 qemu_chr_fe_init(&be, chr, &error_abort); 1772 qemu_chr_fe_init(&be, chr, &err); 1773 error_free_or_abort(&err); 1774 1775 /* deinit & reinit */ 1776 qemu_chr_fe_deinit(&be, false); 1777 qemu_chr_fe_init(&be, chr, &error_abort); 1778 1779 qemu_chr_fe_set_open(&be, true); 1780 1781 qemu_chr_fe_set_handlers(&be, 1782 fe_can_read, 1783 fe_read, 1784 fe_event, 1785 NULL, 1786 NULL, NULL, true); 1787 1788 ret = qemu_chr_fe_write(&be, (void *)"buf", 4); 1789 g_assert_cmpint(ret, ==, 4); 1790 1791 qemu_chr_fe_deinit(&be, true); 1792 } 1793 1794 static void char_invalid_test(void) 1795 { 1796 Chardev *chr; 1797 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1798 chr = qemu_chr_new("label-invalid", "invalid", NULL); 1799 g_assert_null(chr); 1800 g_unsetenv("QTEST_SILENT_ERRORS"); 1801 } 1802 1803 static int chardev_change(void *opaque) 1804 { 1805 return 0; 1806 } 1807 1808 static int chardev_change_denied(void *opaque) 1809 { 1810 return -1; 1811 } 1812 1813 static void char_hotswap_test(void) 1814 { 1815 char *chr_args; 1816 Chardev *chr; 1817 CharBackend be; 1818 1819 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1820 char *filename = g_build_filename(tmp_path, "file", NULL); 1821 ChardevFile file = { .out = filename }; 1822 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1823 .u.file.data = &file }; 1824 ChardevReturn *ret; 1825 1826 int port; 1827 int sock = make_udp_socket(&port); 1828 g_assert_cmpint(sock, >=, 0); 1829 1830 chr_args = g_strdup_printf("udp:127.0.0.1:%d", port); 1831 1832 chr = qemu_chr_new("chardev", chr_args, NULL); 1833 qemu_chr_fe_init(&be, chr, &error_abort); 1834 1835 /* check that chardev operates correctly */ 1836 char_udp_test_internal(chr, sock); 1837 1838 /* set the handler that denies the hotswap */ 1839 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1840 NULL, chardev_change_denied, NULL, NULL, true); 1841 1842 /* now, change is denied and has to keep the old backend operating */ 1843 ret = qmp_chardev_change("chardev", &backend, NULL); 1844 g_assert(!ret); 1845 g_assert(be.chr == chr); 1846 1847 char_udp_test_internal(chr, sock); 1848 1849 /* now allow the change */ 1850 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1851 NULL, chardev_change, NULL, NULL, true); 1852 1853 /* has to succeed now */ 1854 ret = qmp_chardev_change("chardev", &backend, &error_abort); 1855 g_assert(be.chr != chr); 1856 1857 close(sock); 1858 chr = be.chr; 1859 1860 /* run the file chardev test */ 1861 char_file_test_internal(chr, filename); 1862 1863 object_unparent(OBJECT(chr)); 1864 1865 qapi_free_ChardevReturn(ret); 1866 g_unlink(filename); 1867 g_free(filename); 1868 g_rmdir(tmp_path); 1869 g_free(tmp_path); 1870 g_free(chr_args); 1871 } 1872 1873 static SocketAddress tcpaddr = { 1874 .type = SOCKET_ADDRESS_TYPE_INET, 1875 .u.inet.host = (char *)"127.0.0.1", 1876 .u.inet.port = (char *)"0", 1877 }; 1878 #ifndef WIN32 1879 static SocketAddress unixaddr = { 1880 .type = SOCKET_ADDRESS_TYPE_UNIX, 1881 .u.q_unix.path = (char *)"test-char.sock", 1882 }; 1883 #endif 1884 1885 int main(int argc, char **argv) 1886 { 1887 bool has_ipv4, has_ipv6; 1888 1889 qemu_init_main_loop(&error_abort); 1890 socket_init(); 1891 1892 g_test_init(&argc, &argv, NULL); 1893 1894 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 1895 g_printerr("socket_check_protocol_support() failed\n"); 1896 goto end; 1897 } 1898 1899 module_call_init(MODULE_INIT_QOM); 1900 qemu_add_opts(&qemu_chardev_opts); 1901 1902 g_test_add_func("/char/null", char_null_test); 1903 g_test_add_func("/char/invalid", char_invalid_test); 1904 g_test_add_func("/char/ringbuf", char_ringbuf_test); 1905 g_test_add_func("/char/mux", char_mux_test); 1906 g_test_add_func("/char/hub", char_hub_test); 1907 #ifdef _WIN32 1908 g_test_add_func("/char/console/subprocess", char_console_test_subprocess); 1909 g_test_add_func("/char/console", char_console_test); 1910 #endif 1911 g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess); 1912 g_test_add_func("/char/stdio", char_stdio_test); 1913 #ifndef _WIN32 1914 g_test_add_func("/char/pipe", char_pipe_test); 1915 #endif 1916 g_test_add_func("/char/file", char_file_test); 1917 #ifndef _WIN32 1918 g_test_add_func("/char/file-fifo", char_file_fifo_test); 1919 #endif 1920 1921 #define SOCKET_SERVER_TEST(name, addr) \ 1922 static CharSocketServerTestConfig server1 ## name = \ 1923 { addr, false, false }; \ 1924 static CharSocketServerTestConfig server2 ## name = \ 1925 { addr, true, false }; \ 1926 static CharSocketServerTestConfig server3 ## name = \ 1927 { addr, false, true }; \ 1928 static CharSocketServerTestConfig server4 ## name = \ 1929 { addr, true, true }; \ 1930 g_test_add_data_func("/char/socket/server/mainloop/" # name, \ 1931 &server1 ##name, char_socket_server_test); \ 1932 g_test_add_data_func("/char/socket/server/wait-conn/" # name, \ 1933 &server2 ##name, char_socket_server_test); \ 1934 g_test_add_data_func("/char/socket/server/mainloop-fdpass/" # name, \ 1935 &server3 ##name, char_socket_server_test); \ 1936 g_test_add_data_func("/char/socket/server/wait-conn-fdpass/" # name, \ 1937 &server4 ##name, char_socket_server_test) 1938 1939 #define SOCKET_CLIENT_TEST(name, addr) \ 1940 static CharSocketClientTestConfig client1 ## name = \ 1941 { addr, NULL, false, false, char_socket_event }; \ 1942 static CharSocketClientTestConfig client2 ## name = \ 1943 { addr, NULL, true, false, char_socket_event }; \ 1944 static CharSocketClientTestConfig client3 ## name = \ 1945 { addr, ",reconnect-ms=1000", false, false, char_socket_event }; \ 1946 static CharSocketClientTestConfig client4 ## name = \ 1947 { addr, ",reconnect-ms=1000", true, false, char_socket_event }; \ 1948 static CharSocketClientTestConfig client5 ## name = \ 1949 { addr, NULL, false, true, char_socket_event }; \ 1950 static CharSocketClientTestConfig client6 ## name = \ 1951 { addr, NULL, true, true, char_socket_event }; \ 1952 static CharSocketClientTestConfig client7 ## name = \ 1953 { addr, ",reconnect-ms=1000", true, false, \ 1954 char_socket_event_with_error }; \ 1955 static CharSocketClientTestConfig client8 ## name = \ 1956 { addr, ",reconnect-ms=1000", false, false, char_socket_event };\ 1957 g_test_add_data_func("/char/socket/client/mainloop/" # name, \ 1958 &client1 ##name, char_socket_client_test); \ 1959 g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ 1960 &client2 ##name, char_socket_client_test); \ 1961 g_test_add_data_func("/char/socket/client/mainloop-reconnect/" # name, \ 1962 &client3 ##name, char_socket_client_test); \ 1963 g_test_add_data_func("/char/socket/client/wait-conn-reconnect/" # name, \ 1964 &client4 ##name, char_socket_client_test); \ 1965 g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \ 1966 &client5 ##name, char_socket_client_test); \ 1967 g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ 1968 &client6 ##name, char_socket_client_test); \ 1969 g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \ 1970 &client7 ##name, char_socket_client_test); \ 1971 g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \ 1972 &client8 ##name, char_socket_client_dupid_test) 1973 1974 if (has_ipv4) { 1975 SOCKET_SERVER_TEST(tcp, &tcpaddr); 1976 SOCKET_CLIENT_TEST(tcp, &tcpaddr); 1977 g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr, 1978 char_socket_server_two_clients_test); 1979 } 1980 #ifndef WIN32 1981 SOCKET_SERVER_TEST(unix, &unixaddr); 1982 SOCKET_CLIENT_TEST(unix, &unixaddr); 1983 g_test_add_data_func("/char/socket/server/two-clients/unix", &unixaddr, 1984 char_socket_server_two_clients_test); 1985 #endif 1986 1987 g_test_add_func("/char/udp", char_udp_test); 1988 #if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) 1989 g_test_add_func("/char/serial", char_serial_test); 1990 #endif 1991 #if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32) 1992 g_test_add_func("/char/parallel", char_parallel_test); 1993 #endif 1994 g_test_add_func("/char/hotswap", char_hotswap_test); 1995 g_test_add_func("/char/websocket", char_websock_test); 1996 1997 end: 1998 return g_test_run(); 1999 } 2000