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 *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 be = g_alloca(sizeof(CharBackend)); 1013 qemu_chr_fe_init(be, chr, &error_abort); 1014 } 1015 1016 d.chr = chr; 1017 qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello, 1018 NULL, NULL, &d, NULL, true); 1019 ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5); 1020 g_assert_cmpint(ret, ==, 5); 1021 1022 ret = recvfrom(sock, buf, sizeof(buf), 0, 1023 (struct sockaddr *)&other, &alen); 1024 g_assert_cmpint(ret, ==, 5); 1025 ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen); 1026 g_assert_cmpint(ret, ==, 5); 1027 1028 main_loop(); 1029 1030 if (!reuse_chr) { 1031 close(sock); 1032 qemu_chr_fe_deinit(be, true); 1033 } 1034 g_free(tmp); 1035 } 1036 1037 static void char_udp_test(void) 1038 { 1039 char_udp_test_internal(NULL, 0); 1040 } 1041 1042 1043 typedef struct { 1044 int event; 1045 bool got_pong; 1046 CharBackend *be; 1047 } CharSocketTestData; 1048 1049 1050 #define SOCKET_PING "Hello" 1051 #define SOCKET_PONG "World" 1052 1053 typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event); 1054 1055 static void 1056 char_socket_event(void *opaque, QEMUChrEvent event) 1057 { 1058 CharSocketTestData *data = opaque; 1059 data->event = event; 1060 } 1061 1062 static void 1063 char_socket_event_with_error(void *opaque, QEMUChrEvent event) 1064 { 1065 static bool first_error; 1066 CharSocketTestData *data = opaque; 1067 CharBackend *be = data->be; 1068 data->event = event; 1069 switch (event) { 1070 case CHR_EVENT_OPENED: 1071 if (!first_error) { 1072 first_error = true; 1073 qemu_chr_fe_disconnect(be); 1074 } 1075 return; 1076 case CHR_EVENT_CLOSED: 1077 return; 1078 default: 1079 return; 1080 } 1081 } 1082 1083 1084 static void 1085 char_socket_read(void *opaque, const uint8_t *buf, int size) 1086 { 1087 CharSocketTestData *data = opaque; 1088 g_assert_cmpint(size, ==, sizeof(SOCKET_PONG)); 1089 g_assert(memcmp(buf, SOCKET_PONG, size) == 0); 1090 data->got_pong = true; 1091 } 1092 1093 1094 static int 1095 char_socket_can_read(void *opaque) 1096 { 1097 return sizeof(SOCKET_PONG); 1098 } 1099 1100 1101 static char * 1102 char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass, 1103 const char *reconnect, bool is_listen) 1104 { 1105 if (fd_pass) { 1106 QIOChannelSocket *ioc = qio_channel_socket_new(); 1107 int fd; 1108 char *optstr; 1109 g_assert(!reconnect); 1110 if (is_listen) { 1111 qio_channel_socket_listen_sync(ioc, addr, 1, &error_abort); 1112 } else { 1113 qio_channel_socket_connect_sync(ioc, addr, &error_abort); 1114 } 1115 fd = ioc->fd; 1116 ioc->fd = -1; 1117 optstr = g_strdup_printf("socket,id=cdev0,fd=%d%s", 1118 fd, is_listen ? ",server=on,wait=off" : ""); 1119 object_unref(OBJECT(ioc)); 1120 return optstr; 1121 } else { 1122 switch (addr->type) { 1123 case SOCKET_ADDRESS_TYPE_INET: 1124 return g_strdup_printf("socket,id=cdev0,host=%s,port=%s%s%s", 1125 addr->u.inet.host, 1126 addr->u.inet.port, 1127 reconnect ? reconnect : "", 1128 is_listen ? ",server=on,wait=off" : ""); 1129 1130 case SOCKET_ADDRESS_TYPE_UNIX: 1131 return g_strdup_printf("socket,id=cdev0,path=%s%s%s", 1132 addr->u.q_unix.path, 1133 reconnect ? reconnect : "", 1134 is_listen ? ",server=on,wait=off" : ""); 1135 1136 default: 1137 g_assert_not_reached(); 1138 } 1139 } 1140 } 1141 1142 1143 static int 1144 char_socket_ping_pong(QIOChannel *ioc, Error **errp) 1145 { 1146 char greeting[sizeof(SOCKET_PING)]; 1147 const char *response = SOCKET_PONG; 1148 1149 int ret; 1150 ret = qio_channel_read_all(ioc, greeting, sizeof(greeting), errp); 1151 if (ret != 0) { 1152 object_unref(OBJECT(ioc)); 1153 return -1; 1154 } 1155 1156 g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0); 1157 1158 qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), errp); 1159 object_unref(OBJECT(ioc)); 1160 return 0; 1161 } 1162 1163 1164 static gpointer 1165 char_socket_server_client_thread(gpointer data) 1166 { 1167 SocketAddress *addr = data; 1168 QIOChannelSocket *ioc = qio_channel_socket_new(); 1169 1170 qio_channel_socket_connect_sync(ioc, addr, &error_abort); 1171 1172 char_socket_ping_pong(QIO_CHANNEL(ioc), &error_abort); 1173 1174 return NULL; 1175 } 1176 1177 1178 typedef struct { 1179 SocketAddress *addr; 1180 bool wait_connected; 1181 bool fd_pass; 1182 } CharSocketServerTestConfig; 1183 1184 1185 static void char_socket_server_test(gconstpointer opaque) 1186 { 1187 const CharSocketServerTestConfig *config = opaque; 1188 Chardev *chr; 1189 CharBackend be = {0}; 1190 CharSocketTestData data = {0}; 1191 QObject *qaddr; 1192 SocketAddress *addr; 1193 Visitor *v; 1194 QemuThread thread; 1195 int ret; 1196 bool reconnected = false; 1197 char *optstr; 1198 QemuOpts *opts; 1199 1200 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1201 /* 1202 * We rely on config->addr containing "wait=off", otherwise 1203 * qemu_chr_new() will block until a client connects. We 1204 * can't spawn our client thread though, because until 1205 * qemu_chr_new() returns we don't know what TCP port was 1206 * allocated by the OS 1207 */ 1208 optstr = char_socket_addr_to_opt_str(config->addr, 1209 config->fd_pass, 1210 NULL, 1211 true); 1212 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1213 optstr, true); 1214 g_assert_nonnull(opts); 1215 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1216 qemu_opts_del(opts); 1217 g_assert_nonnull(chr); 1218 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1219 1220 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 1221 g_assert_nonnull(qaddr); 1222 1223 v = qobject_input_visitor_new(qaddr); 1224 visit_type_SocketAddress(v, "addr", &addr, &error_abort); 1225 visit_free(v); 1226 qobject_unref(qaddr); 1227 1228 qemu_chr_fe_init(&be, chr, &error_abort); 1229 1230 reconnect: 1231 data.event = -1; 1232 data.be = &be; 1233 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1234 char_socket_event, NULL, 1235 &data, NULL, true); 1236 g_assert(data.event == -1); 1237 1238 /* 1239 * Kick off a thread to act as the "remote" client 1240 * which just plays ping-pong with us 1241 */ 1242 qemu_thread_create(&thread, "client", 1243 char_socket_server_client_thread, 1244 addr, QEMU_THREAD_JOINABLE); 1245 g_assert(data.event == -1); 1246 1247 if (config->wait_connected) { 1248 /* Synchronously accept a connection */ 1249 qemu_chr_wait_connected(chr, &error_abort); 1250 } else { 1251 /* 1252 * Asynchronously accept a connection when the evnt 1253 * loop reports the listener socket as readable 1254 */ 1255 while (data.event == -1) { 1256 main_loop_wait(false); 1257 } 1258 } 1259 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1260 g_assert(data.event == CHR_EVENT_OPENED); 1261 data.event = -1; 1262 1263 /* Send a greeting to the client */ 1264 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING, 1265 sizeof(SOCKET_PING)); 1266 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING)); 1267 g_assert(data.event == -1); 1268 1269 /* Setup a callback to receive the reply to our greeting */ 1270 qemu_chr_fe_set_handlers(&be, char_socket_can_read, 1271 char_socket_read, 1272 char_socket_event, NULL, 1273 &data, NULL, true); 1274 g_assert(data.event == CHR_EVENT_OPENED); 1275 data.event = -1; 1276 1277 /* Wait for the client to go away */ 1278 while (data.event == -1) { 1279 main_loop_wait(false); 1280 } 1281 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1282 g_assert(data.event == CHR_EVENT_CLOSED); 1283 g_assert(data.got_pong); 1284 1285 qemu_thread_join(&thread); 1286 1287 if (!reconnected) { 1288 reconnected = true; 1289 goto reconnect; 1290 } 1291 1292 qapi_free_SocketAddress(addr); 1293 object_unparent(OBJECT(chr)); 1294 g_free(optstr); 1295 g_unsetenv("QTEST_SILENT_ERRORS"); 1296 } 1297 1298 1299 static gpointer 1300 char_socket_client_server_thread(gpointer data) 1301 { 1302 QIOChannelSocket *ioc = data; 1303 QIOChannelSocket *cioc; 1304 1305 retry: 1306 cioc = qio_channel_socket_accept(ioc, &error_abort); 1307 g_assert_nonnull(cioc); 1308 1309 if (char_socket_ping_pong(QIO_CHANNEL(cioc), NULL) != 0) { 1310 goto retry; 1311 } 1312 1313 return NULL; 1314 } 1315 1316 1317 typedef struct { 1318 SocketAddress *addr; 1319 const char *reconnect; 1320 bool wait_connected; 1321 bool fd_pass; 1322 char_socket_cb event_cb; 1323 } CharSocketClientTestConfig; 1324 1325 static void char_socket_client_dupid_test(gconstpointer opaque) 1326 { 1327 const CharSocketClientTestConfig *config = opaque; 1328 QIOChannelSocket *ioc; 1329 char *optstr; 1330 Chardev *chr1, *chr2; 1331 SocketAddress *addr; 1332 QemuOpts *opts; 1333 Error *local_err = NULL; 1334 1335 /* 1336 * Setup a listener socket and determine get its address 1337 * so we know the TCP port for the client later 1338 */ 1339 ioc = qio_channel_socket_new(); 1340 g_assert_nonnull(ioc); 1341 qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); 1342 addr = qio_channel_socket_get_local_address(ioc, &error_abort); 1343 g_assert_nonnull(addr); 1344 1345 /* 1346 * Populate the chardev address based on what the server 1347 * is actually listening on 1348 */ 1349 optstr = char_socket_addr_to_opt_str(addr, 1350 config->fd_pass, 1351 config->reconnect, 1352 false); 1353 1354 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1355 optstr, true); 1356 g_assert_nonnull(opts); 1357 chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1358 g_assert_nonnull(chr1); 1359 qemu_chr_wait_connected(chr1, &error_abort); 1360 1361 chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err); 1362 g_assert_null(chr2); 1363 error_free_or_abort(&local_err); 1364 1365 object_unref(OBJECT(ioc)); 1366 qemu_opts_del(opts); 1367 object_unparent(OBJECT(chr1)); 1368 qapi_free_SocketAddress(addr); 1369 g_free(optstr); 1370 } 1371 1372 static void char_socket_client_test(gconstpointer opaque) 1373 { 1374 const CharSocketClientTestConfig *config = opaque; 1375 const char_socket_cb event_cb = config->event_cb; 1376 QIOChannelSocket *ioc; 1377 char *optstr; 1378 Chardev *chr; 1379 CharBackend be = {0}; 1380 CharSocketTestData data = {0}; 1381 SocketAddress *addr; 1382 QemuThread thread; 1383 int ret; 1384 bool reconnected = false; 1385 QemuOpts *opts; 1386 1387 /* 1388 * Setup a listener socket and determine get its address 1389 * so we know the TCP port for the client later 1390 */ 1391 ioc = qio_channel_socket_new(); 1392 g_assert_nonnull(ioc); 1393 qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort); 1394 addr = qio_channel_socket_get_local_address(ioc, &error_abort); 1395 g_assert_nonnull(addr); 1396 1397 /* 1398 * Kick off a thread to act as the "remote" client 1399 * which just plays ping-pong with us 1400 */ 1401 qemu_thread_create(&thread, "client", 1402 char_socket_client_server_thread, 1403 ioc, QEMU_THREAD_JOINABLE); 1404 1405 /* 1406 * Populate the chardev address based on what the server 1407 * is actually listening on 1408 */ 1409 optstr = char_socket_addr_to_opt_str(addr, 1410 config->fd_pass, 1411 config->reconnect, 1412 false); 1413 1414 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1415 optstr, true); 1416 g_assert_nonnull(opts); 1417 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1418 qemu_opts_del(opts); 1419 g_assert_nonnull(chr); 1420 1421 if (config->reconnect) { 1422 /* 1423 * If reconnect is set, the connection will be 1424 * established in a background thread and we won't 1425 * see the "connected" status updated until we 1426 * run the main event loop, or call qemu_chr_wait_connected 1427 */ 1428 g_assert(!object_property_get_bool(OBJECT(chr), "connected", 1429 &error_abort)); 1430 } else { 1431 g_assert(object_property_get_bool(OBJECT(chr), "connected", 1432 &error_abort)); 1433 } 1434 1435 qemu_chr_fe_init(&be, chr, &error_abort); 1436 1437 reconnect: 1438 data.event = -1; 1439 data.be = &be; 1440 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1441 event_cb, NULL, 1442 &data, NULL, true); 1443 if (config->reconnect) { 1444 g_assert(data.event == -1); 1445 } else { 1446 g_assert(data.event == CHR_EVENT_OPENED); 1447 } 1448 1449 if (config->wait_connected) { 1450 /* 1451 * Synchronously wait for the connection to complete 1452 * This should be a no-op if reconnect is not set. 1453 */ 1454 qemu_chr_wait_connected(chr, &error_abort); 1455 } else { 1456 /* 1457 * Asynchronously wait for the connection to be reported 1458 * as complete when the background thread reports its 1459 * status. 1460 * The loop will short-circuit if reconnect was set 1461 */ 1462 while (data.event == -1) { 1463 main_loop_wait(false); 1464 } 1465 } 1466 g_assert(data.event == CHR_EVENT_OPENED); 1467 data.event = -1; 1468 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1469 1470 /* Send a greeting to the server */ 1471 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING, 1472 sizeof(SOCKET_PING)); 1473 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING)); 1474 g_assert(data.event == -1); 1475 1476 /* Setup a callback to receive the reply to our greeting */ 1477 qemu_chr_fe_set_handlers(&be, char_socket_can_read, 1478 char_socket_read, 1479 event_cb, NULL, 1480 &data, NULL, true); 1481 g_assert(data.event == CHR_EVENT_OPENED); 1482 data.event = -1; 1483 1484 /* Wait for the server to go away */ 1485 while (data.event == -1) { 1486 main_loop_wait(false); 1487 } 1488 g_assert(data.event == CHR_EVENT_CLOSED); 1489 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1490 g_assert(data.got_pong); 1491 qemu_thread_join(&thread); 1492 1493 if (config->reconnect && !reconnected) { 1494 reconnected = true; 1495 qemu_thread_create(&thread, "client", 1496 char_socket_client_server_thread, 1497 ioc, QEMU_THREAD_JOINABLE); 1498 goto reconnect; 1499 } 1500 1501 object_unref(OBJECT(ioc)); 1502 object_unparent(OBJECT(chr)); 1503 qapi_free_SocketAddress(addr); 1504 g_free(optstr); 1505 } 1506 1507 static void 1508 count_closed_event(void *opaque, QEMUChrEvent event) 1509 { 1510 int *count = opaque; 1511 if (event == CHR_EVENT_CLOSED) { 1512 (*count)++; 1513 } 1514 } 1515 1516 static void 1517 char_socket_discard_read(void *opaque, const uint8_t *buf, int size) 1518 { 1519 } 1520 1521 static void char_socket_server_two_clients_test(gconstpointer opaque) 1522 { 1523 SocketAddress *incoming_addr = (gpointer) opaque; 1524 Chardev *chr; 1525 CharBackend be = {0}; 1526 QObject *qaddr; 1527 SocketAddress *addr; 1528 Visitor *v; 1529 char *optstr; 1530 QemuOpts *opts; 1531 QIOChannelSocket *ioc1, *ioc2; 1532 int closed = 0; 1533 1534 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1535 /* 1536 * We rely on addr containing "wait=off", otherwise 1537 * qemu_chr_new() will block until a client connects. We 1538 * can't spawn our client thread though, because until 1539 * qemu_chr_new() returns we don't know what TCP port was 1540 * allocated by the OS 1541 */ 1542 optstr = char_socket_addr_to_opt_str(incoming_addr, 1543 false, 1544 NULL, 1545 true); 1546 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"), 1547 optstr, true); 1548 g_assert_nonnull(opts); 1549 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort); 1550 qemu_opts_del(opts); 1551 g_assert_nonnull(chr); 1552 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort)); 1553 1554 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort); 1555 g_assert_nonnull(qaddr); 1556 1557 v = qobject_input_visitor_new(qaddr); 1558 visit_type_SocketAddress(v, "addr", &addr, &error_abort); 1559 visit_free(v); 1560 qobject_unref(qaddr); 1561 1562 qemu_chr_fe_init(&be, chr, &error_abort); 1563 1564 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read, 1565 count_closed_event, NULL, 1566 &closed, NULL, true); 1567 1568 ioc1 = qio_channel_socket_new(); 1569 qio_channel_socket_connect_sync(ioc1, addr, &error_abort); 1570 qemu_chr_wait_connected(chr, &error_abort); 1571 1572 /* switch the chardev to another context */ 1573 GMainContext *ctx = g_main_context_new(); 1574 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read, 1575 count_closed_event, NULL, 1576 &closed, ctx, true); 1577 1578 /* Start a second connection while the first is still connected. 1579 * It will be placed in the listen() backlog, and connect() will 1580 * succeed immediately. 1581 */ 1582 ioc2 = qio_channel_socket_new(); 1583 qio_channel_socket_connect_sync(ioc2, addr, &error_abort); 1584 1585 object_unref(OBJECT(ioc1)); 1586 /* The two connections should now be processed serially. */ 1587 while (g_main_context_iteration(ctx, TRUE)) { 1588 if (closed == 1 && ioc2) { 1589 object_unref(OBJECT(ioc2)); 1590 ioc2 = NULL; 1591 } 1592 if (closed == 2) { 1593 break; 1594 } 1595 } 1596 1597 qapi_free_SocketAddress(addr); 1598 object_unparent(OBJECT(chr)); 1599 g_main_context_unref(ctx); 1600 g_free(optstr); 1601 g_unsetenv("QTEST_SILENT_ERRORS"); 1602 } 1603 1604 1605 #if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) 1606 static void char_serial_test(void) 1607 { 1608 QemuOpts *opts; 1609 Chardev *chr; 1610 1611 opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id", 1612 1, &error_abort); 1613 qemu_opt_set(opts, "backend", "serial", &error_abort); 1614 qemu_opt_set(opts, "path", "/dev/null", &error_abort); 1615 1616 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 1617 g_assert_nonnull(chr); 1618 /* TODO: add more tests with a pty */ 1619 object_unparent(OBJECT(chr)); 1620 1621 qemu_opts_del(opts); 1622 } 1623 #endif 1624 1625 #if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32) 1626 static void char_parallel_test(void) 1627 { 1628 QemuOpts *opts; 1629 Chardev *chr; 1630 1631 opts = qemu_opts_create(qemu_find_opts("chardev"), "parallel-id", 1632 1, &error_abort); 1633 qemu_opt_set(opts, "backend", "parallel", &error_abort); 1634 qemu_opt_set(opts, "path", "/dev/null", &error_abort); 1635 1636 chr = qemu_chr_new_from_opts(opts, NULL, NULL); 1637 #ifdef __linux__ 1638 /* fails to PPCLAIM, see qemu_chr_open_pp_fd() */ 1639 g_assert_null(chr); 1640 #else 1641 g_assert_nonnull(chr); 1642 object_unparent(OBJECT(chr)); 1643 #endif 1644 1645 qemu_opts_del(opts); 1646 } 1647 #endif 1648 1649 #ifndef _WIN32 1650 static void char_file_fifo_test(void) 1651 { 1652 Chardev *chr; 1653 CharBackend be; 1654 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1655 char *fifo = g_build_filename(tmp_path, "fifo", NULL); 1656 char *out = g_build_filename(tmp_path, "out", NULL); 1657 ChardevFile file = { .in = fifo, 1658 .out = out }; 1659 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1660 .u.file.data = &file }; 1661 FeHandler fe = { 0, }; 1662 int fd, ret; 1663 1664 if (mkfifo(fifo, 0600) < 0) { 1665 abort(); 1666 } 1667 1668 fd = open(fifo, O_RDWR); 1669 ret = write(fd, "fifo-in", 8); 1670 g_assert_cmpint(ret, ==, 8); 1671 1672 chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend, 1673 NULL, &error_abort); 1674 1675 qemu_chr_fe_init(&be, chr, &error_abort); 1676 qemu_chr_fe_set_handlers(&be, 1677 fe_can_read, 1678 fe_read, 1679 fe_event, 1680 NULL, 1681 &fe, NULL, true); 1682 1683 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK); 1684 qmp_chardev_send_break("label-foo", NULL); 1685 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK); 1686 qmp_chardev_send_break("label-file", NULL); 1687 g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK); 1688 1689 main_loop(); 1690 1691 close(fd); 1692 1693 g_assert_cmpint(fe.read_count, ==, 8); 1694 g_assert_cmpstr(fe.read_buf, ==, "fifo-in"); 1695 1696 qemu_chr_fe_deinit(&be, true); 1697 1698 g_unlink(fifo); 1699 g_free(fifo); 1700 g_unlink(out); 1701 g_free(out); 1702 g_rmdir(tmp_path); 1703 g_free(tmp_path); 1704 } 1705 #endif 1706 1707 static void char_file_test_internal(Chardev *ext_chr, const char *filepath) 1708 { 1709 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1710 char *out; 1711 Chardev *chr; 1712 char *contents = NULL; 1713 ChardevFile file = {}; 1714 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1715 .u.file.data = &file }; 1716 gsize length; 1717 int ret; 1718 1719 if (ext_chr) { 1720 chr = ext_chr; 1721 out = g_strdup(filepath); 1722 file.out = out; 1723 } else { 1724 out = g_build_filename(tmp_path, "out", NULL); 1725 file.out = out; 1726 chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend, 1727 NULL, &error_abort); 1728 } 1729 ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6); 1730 g_assert_cmpint(ret, ==, 6); 1731 1732 ret = g_file_get_contents(out, &contents, &length, NULL); 1733 g_assert(ret == TRUE); 1734 g_assert_cmpint(length, ==, 6); 1735 g_assert(strncmp(contents, "hello!", 6) == 0); 1736 1737 if (!ext_chr) { 1738 object_unparent(OBJECT(chr)); 1739 g_unlink(out); 1740 } 1741 g_free(contents); 1742 g_rmdir(tmp_path); 1743 g_free(tmp_path); 1744 g_free(out); 1745 } 1746 1747 static void char_file_test(void) 1748 { 1749 char_file_test_internal(NULL, NULL); 1750 } 1751 1752 static void char_null_test(void) 1753 { 1754 Error *err = NULL; 1755 Chardev *chr; 1756 CharBackend be; 1757 int ret; 1758 1759 chr = qemu_chr_find("label-null"); 1760 g_assert_null(chr); 1761 1762 chr = qemu_chr_new("label-null", "null", NULL); 1763 chr = qemu_chr_find("label-null"); 1764 g_assert_nonnull(chr); 1765 1766 g_assert(qemu_chr_has_feature(chr, 1767 QEMU_CHAR_FEATURE_FD_PASS) == false); 1768 g_assert(qemu_chr_has_feature(chr, 1769 QEMU_CHAR_FEATURE_RECONNECTABLE) == false); 1770 1771 /* check max avail */ 1772 qemu_chr_fe_init(&be, chr, &error_abort); 1773 qemu_chr_fe_init(&be, chr, &err); 1774 error_free_or_abort(&err); 1775 1776 /* deinit & reinit */ 1777 qemu_chr_fe_deinit(&be, false); 1778 qemu_chr_fe_init(&be, chr, &error_abort); 1779 1780 qemu_chr_fe_set_open(&be, true); 1781 1782 qemu_chr_fe_set_handlers(&be, 1783 fe_can_read, 1784 fe_read, 1785 fe_event, 1786 NULL, 1787 NULL, NULL, true); 1788 1789 ret = qemu_chr_fe_write(&be, (void *)"buf", 4); 1790 g_assert_cmpint(ret, ==, 4); 1791 1792 qemu_chr_fe_deinit(&be, true); 1793 } 1794 1795 static void char_invalid_test(void) 1796 { 1797 Chardev *chr; 1798 g_setenv("QTEST_SILENT_ERRORS", "1", 1); 1799 chr = qemu_chr_new("label-invalid", "invalid", NULL); 1800 g_assert_null(chr); 1801 g_unsetenv("QTEST_SILENT_ERRORS"); 1802 } 1803 1804 static int chardev_change(void *opaque) 1805 { 1806 return 0; 1807 } 1808 1809 static int chardev_change_denied(void *opaque) 1810 { 1811 return -1; 1812 } 1813 1814 static void char_hotswap_test(void) 1815 { 1816 char *chr_args; 1817 Chardev *chr; 1818 CharBackend be; 1819 1820 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL); 1821 char *filename = g_build_filename(tmp_path, "file", NULL); 1822 ChardevFile file = { .out = filename }; 1823 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE, 1824 .u.file.data = &file }; 1825 ChardevReturn *ret; 1826 1827 int port; 1828 int sock = make_udp_socket(&port); 1829 g_assert_cmpint(sock, >=, 0); 1830 1831 chr_args = g_strdup_printf("udp:127.0.0.1:%d", port); 1832 1833 chr = qemu_chr_new("chardev", chr_args, NULL); 1834 qemu_chr_fe_init(&be, chr, &error_abort); 1835 1836 /* check that chardev operates correctly */ 1837 char_udp_test_internal(chr, sock); 1838 1839 /* set the handler that denies the hotswap */ 1840 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1841 NULL, chardev_change_denied, NULL, NULL, true); 1842 1843 /* now, change is denied and has to keep the old backend operating */ 1844 ret = qmp_chardev_change("chardev", &backend, NULL); 1845 g_assert(!ret); 1846 g_assert(be.chr == chr); 1847 1848 char_udp_test_internal(chr, sock); 1849 1850 /* now allow the change */ 1851 qemu_chr_fe_set_handlers(&be, NULL, NULL, 1852 NULL, chardev_change, NULL, NULL, true); 1853 1854 /* has to succeed now */ 1855 ret = qmp_chardev_change("chardev", &backend, &error_abort); 1856 g_assert(be.chr != chr); 1857 1858 close(sock); 1859 chr = be.chr; 1860 1861 /* run the file chardev test */ 1862 char_file_test_internal(chr, filename); 1863 1864 object_unparent(OBJECT(chr)); 1865 1866 qapi_free_ChardevReturn(ret); 1867 g_unlink(filename); 1868 g_free(filename); 1869 g_rmdir(tmp_path); 1870 g_free(tmp_path); 1871 g_free(chr_args); 1872 } 1873 1874 static SocketAddress tcpaddr = { 1875 .type = SOCKET_ADDRESS_TYPE_INET, 1876 .u.inet.host = (char *)"127.0.0.1", 1877 .u.inet.port = (char *)"0", 1878 }; 1879 #ifndef WIN32 1880 static SocketAddress unixaddr = { 1881 .type = SOCKET_ADDRESS_TYPE_UNIX, 1882 .u.q_unix.path = (char *)"test-char.sock", 1883 }; 1884 #endif 1885 1886 int main(int argc, char **argv) 1887 { 1888 bool has_ipv4, has_ipv6; 1889 1890 qemu_init_main_loop(&error_abort); 1891 socket_init(); 1892 1893 g_test_init(&argc, &argv, NULL); 1894 1895 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { 1896 g_printerr("socket_check_protocol_support() failed\n"); 1897 goto end; 1898 } 1899 1900 module_call_init(MODULE_INIT_QOM); 1901 qemu_add_opts(&qemu_chardev_opts); 1902 1903 g_test_add_func("/char/null", char_null_test); 1904 g_test_add_func("/char/invalid", char_invalid_test); 1905 g_test_add_func("/char/ringbuf", char_ringbuf_test); 1906 g_test_add_func("/char/mux", char_mux_test); 1907 g_test_add_func("/char/hub", char_hub_test); 1908 #ifdef _WIN32 1909 g_test_add_func("/char/console/subprocess", char_console_test_subprocess); 1910 g_test_add_func("/char/console", char_console_test); 1911 #endif 1912 g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess); 1913 g_test_add_func("/char/stdio", char_stdio_test); 1914 #ifndef _WIN32 1915 g_test_add_func("/char/pipe", char_pipe_test); 1916 #endif 1917 g_test_add_func("/char/file", char_file_test); 1918 #ifndef _WIN32 1919 g_test_add_func("/char/file-fifo", char_file_fifo_test); 1920 #endif 1921 1922 #define SOCKET_SERVER_TEST(name, addr) \ 1923 static CharSocketServerTestConfig server1 ## name = \ 1924 { addr, false, false }; \ 1925 static CharSocketServerTestConfig server2 ## name = \ 1926 { addr, true, false }; \ 1927 static CharSocketServerTestConfig server3 ## name = \ 1928 { addr, false, true }; \ 1929 static CharSocketServerTestConfig server4 ## name = \ 1930 { addr, true, true }; \ 1931 g_test_add_data_func("/char/socket/server/mainloop/" # name, \ 1932 &server1 ##name, char_socket_server_test); \ 1933 g_test_add_data_func("/char/socket/server/wait-conn/" # name, \ 1934 &server2 ##name, char_socket_server_test); \ 1935 g_test_add_data_func("/char/socket/server/mainloop-fdpass/" # name, \ 1936 &server3 ##name, char_socket_server_test); \ 1937 g_test_add_data_func("/char/socket/server/wait-conn-fdpass/" # name, \ 1938 &server4 ##name, char_socket_server_test) 1939 1940 #define SOCKET_CLIENT_TEST(name, addr) \ 1941 static CharSocketClientTestConfig client1 ## name = \ 1942 { addr, NULL, false, false, char_socket_event }; \ 1943 static CharSocketClientTestConfig client2 ## name = \ 1944 { addr, NULL, true, false, char_socket_event }; \ 1945 static CharSocketClientTestConfig client3 ## name = \ 1946 { addr, ",reconnect-ms=1000", false, false, char_socket_event }; \ 1947 static CharSocketClientTestConfig client4 ## name = \ 1948 { addr, ",reconnect-ms=1000", true, false, char_socket_event }; \ 1949 static CharSocketClientTestConfig client5 ## name = \ 1950 { addr, NULL, false, true, char_socket_event }; \ 1951 static CharSocketClientTestConfig client6 ## name = \ 1952 { addr, NULL, true, true, char_socket_event }; \ 1953 static CharSocketClientTestConfig client7 ## name = \ 1954 { addr, ",reconnect-ms=1000", true, false, \ 1955 char_socket_event_with_error }; \ 1956 static CharSocketClientTestConfig client8 ## name = \ 1957 { addr, ",reconnect-ms=1000", false, false, char_socket_event };\ 1958 g_test_add_data_func("/char/socket/client/mainloop/" # name, \ 1959 &client1 ##name, char_socket_client_test); \ 1960 g_test_add_data_func("/char/socket/client/wait-conn/" # name, \ 1961 &client2 ##name, char_socket_client_test); \ 1962 g_test_add_data_func("/char/socket/client/mainloop-reconnect/" # name, \ 1963 &client3 ##name, char_socket_client_test); \ 1964 g_test_add_data_func("/char/socket/client/wait-conn-reconnect/" # name, \ 1965 &client4 ##name, char_socket_client_test); \ 1966 g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \ 1967 &client5 ##name, char_socket_client_test); \ 1968 g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \ 1969 &client6 ##name, char_socket_client_test); \ 1970 g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \ 1971 &client7 ##name, char_socket_client_test); \ 1972 g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \ 1973 &client8 ##name, char_socket_client_dupid_test) 1974 1975 if (has_ipv4) { 1976 SOCKET_SERVER_TEST(tcp, &tcpaddr); 1977 SOCKET_CLIENT_TEST(tcp, &tcpaddr); 1978 g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr, 1979 char_socket_server_two_clients_test); 1980 } 1981 #ifndef WIN32 1982 SOCKET_SERVER_TEST(unix, &unixaddr); 1983 SOCKET_CLIENT_TEST(unix, &unixaddr); 1984 g_test_add_data_func("/char/socket/server/two-clients/unix", &unixaddr, 1985 char_socket_server_two_clients_test); 1986 #endif 1987 1988 g_test_add_func("/char/udp", char_udp_test); 1989 #if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32) 1990 g_test_add_func("/char/serial", char_serial_test); 1991 #endif 1992 #if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32) 1993 g_test_add_func("/char/parallel", char_parallel_test); 1994 #endif 1995 g_test_add_func("/char/hotswap", char_hotswap_test); 1996 g_test_add_func("/char/websocket", char_websock_test); 1997 1998 end: 1999 return g_test_run(); 2000 } 2001