qemu/tests/test-char.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include <glib/gstdio.h>
   3
   4#include "qemu/config-file.h"
   5#include "qemu/option.h"
   6#include "qemu/sockets.h"
   7#include "chardev/char-fe.h"
   8#include "chardev/char-mux.h"
   9#include "sysemu/sysemu.h"
  10#include "qapi/error.h"
  11#include "qapi/qapi-commands-char.h"
  12#include "qapi/qmp/qdict.h"
  13#include "qom/qom-qobject.h"
  14
  15static bool quit;
  16
  17typedef struct FeHandler {
  18    int read_count;
  19    int last_event;
  20    char read_buf[128];
  21} FeHandler;
  22
  23static void main_loop(void)
  24{
  25    quit = false;
  26    do {
  27        main_loop_wait(false);
  28    } while (!quit);
  29}
  30
  31static int fe_can_read(void *opaque)
  32{
  33    FeHandler *h = opaque;
  34
  35    return sizeof(h->read_buf) - h->read_count;
  36}
  37
  38static void fe_read(void *opaque, const uint8_t *buf, int size)
  39{
  40    FeHandler *h = opaque;
  41
  42    g_assert_cmpint(size, <=, fe_can_read(opaque));
  43
  44    memcpy(h->read_buf + h->read_count, buf, size);
  45    h->read_count += size;
  46    quit = true;
  47}
  48
  49static void fe_event(void *opaque, int event)
  50{
  51    FeHandler *h = opaque;
  52
  53    h->last_event = event;
  54    if (event != CHR_EVENT_BREAK) {
  55        quit = true;
  56    }
  57}
  58
  59#ifdef _WIN32
  60static void char_console_test_subprocess(void)
  61{
  62    QemuOpts *opts;
  63    Chardev *chr;
  64
  65    opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
  66                            1, &error_abort);
  67    qemu_opt_set(opts, "backend", "console", &error_abort);
  68
  69    chr = qemu_chr_new_from_opts(opts, NULL);
  70    g_assert_nonnull(chr);
  71
  72    qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
  73
  74    qemu_opts_del(opts);
  75    object_unparent(OBJECT(chr));
  76}
  77
  78static void char_console_test(void)
  79{
  80    g_test_trap_subprocess("/char/console/subprocess", 0, 0);
  81    g_test_trap_assert_passed();
  82    g_test_trap_assert_stdout("CONSOLE");
  83}
  84#endif
  85static void char_stdio_test_subprocess(void)
  86{
  87    Chardev *chr;
  88    CharBackend be;
  89    int ret;
  90
  91    chr = qemu_chr_new("label", "stdio");
  92    g_assert_nonnull(chr);
  93
  94    qemu_chr_fe_init(&be, chr, &error_abort);
  95    qemu_chr_fe_set_open(&be, true);
  96    ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
  97    g_assert_cmpint(ret, ==, 4);
  98
  99    qemu_chr_fe_deinit(&be, true);
 100}
 101
 102static void char_stdio_test(void)
 103{
 104    g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
 105    g_test_trap_assert_passed();
 106    g_test_trap_assert_stdout("buf");
 107}
 108
 109static void char_ringbuf_test(void)
 110{
 111    QemuOpts *opts;
 112    Chardev *chr;
 113    CharBackend be;
 114    char *data;
 115    int ret;
 116
 117    opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
 118                            1, &error_abort);
 119    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
 120
 121    qemu_opt_set(opts, "size", "5", &error_abort);
 122    chr = qemu_chr_new_from_opts(opts, NULL);
 123    g_assert_null(chr);
 124    qemu_opts_del(opts);
 125
 126    opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
 127                            1, &error_abort);
 128    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
 129    qemu_opt_set(opts, "size", "2", &error_abort);
 130    chr = qemu_chr_new_from_opts(opts, &error_abort);
 131    g_assert_nonnull(chr);
 132    qemu_opts_del(opts);
 133
 134    qemu_chr_fe_init(&be, chr, &error_abort);
 135    ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
 136    g_assert_cmpint(ret, ==, 4);
 137
 138    data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
 139    g_assert_cmpstr(data, ==, "ff");
 140    g_free(data);
 141
 142    data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
 143    g_assert_cmpstr(data, ==, "");
 144    g_free(data);
 145
 146    qemu_chr_fe_deinit(&be, true);
 147
 148    /* check alias */
 149    opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
 150                            1, &error_abort);
 151    qemu_opt_set(opts, "backend", "memory", &error_abort);
 152    qemu_opt_set(opts, "size", "2", &error_abort);
 153    chr = qemu_chr_new_from_opts(opts, NULL);
 154    g_assert_nonnull(chr);
 155    object_unparent(OBJECT(chr));
 156    qemu_opts_del(opts);
 157}
 158
 159static void char_mux_test(void)
 160{
 161    QemuOpts *opts;
 162    Chardev *chr, *base;
 163    char *data;
 164    FeHandler h1 = { 0, }, h2 = { 0, };
 165    CharBackend chr_be1, chr_be2;
 166
 167    opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
 168                            1, &error_abort);
 169    qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
 170    qemu_opt_set(opts, "size", "128", &error_abort);
 171    qemu_opt_set(opts, "mux", "on", &error_abort);
 172    chr = qemu_chr_new_from_opts(opts, &error_abort);
 173    g_assert_nonnull(chr);
 174    qemu_opts_del(opts);
 175
 176    qemu_chr_fe_init(&chr_be1, chr, &error_abort);
 177    qemu_chr_fe_set_handlers(&chr_be1,
 178                             fe_can_read,
 179                             fe_read,
 180                             fe_event,
 181                             NULL,
 182                             &h1,
 183                             NULL, true);
 184
 185    qemu_chr_fe_init(&chr_be2, chr, &error_abort);
 186    qemu_chr_fe_set_handlers(&chr_be2,
 187                             fe_can_read,
 188                             fe_read,
 189                             fe_event,
 190                             NULL,
 191                             &h2,
 192                             NULL, true);
 193    qemu_chr_fe_take_focus(&chr_be2);
 194
 195    base = qemu_chr_find("mux-label-base");
 196    g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
 197
 198    qemu_chr_be_write(base, (void *)"hello", 6);
 199    g_assert_cmpint(h1.read_count, ==, 0);
 200    g_assert_cmpint(h2.read_count, ==, 6);
 201    g_assert_cmpstr(h2.read_buf, ==, "hello");
 202    h2.read_count = 0;
 203
 204    g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */
 205    g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */
 206    /* sending event on the base broadcast to all fe, historical reasons? */
 207    qemu_chr_be_event(base, 42);
 208    g_assert_cmpint(h1.last_event, ==, 42);
 209    g_assert_cmpint(h2.last_event, ==, 42);
 210    qemu_chr_be_event(chr, -1);
 211    g_assert_cmpint(h1.last_event, ==, 42);
 212    g_assert_cmpint(h2.last_event, ==, -1);
 213
 214    /* switch focus */
 215    qemu_chr_be_write(base, (void *)"\1b", 2);
 216    g_assert_cmpint(h1.last_event, ==, 42);
 217    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK);
 218
 219    qemu_chr_be_write(base, (void *)"\1c", 2);
 220    g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
 221    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
 222    qemu_chr_be_event(chr, -1);
 223    g_assert_cmpint(h1.last_event, ==, -1);
 224    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
 225
 226    qemu_chr_be_write(base, (void *)"hello", 6);
 227    g_assert_cmpint(h2.read_count, ==, 0);
 228    g_assert_cmpint(h1.read_count, ==, 6);
 229    g_assert_cmpstr(h1.read_buf, ==, "hello");
 230    h1.read_count = 0;
 231
 232    qemu_chr_be_write(base, (void *)"\1b", 2);
 233    g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK);
 234    g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
 235
 236    /* remove first handler */
 237    qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
 238                             NULL, NULL, true);
 239    qemu_chr_be_write(base, (void *)"hello", 6);
 240    g_assert_cmpint(h1.read_count, ==, 0);
 241    g_assert_cmpint(h2.read_count, ==, 0);
 242
 243    qemu_chr_be_write(base, (void *)"\1c", 2);
 244    qemu_chr_be_write(base, (void *)"hello", 6);
 245    g_assert_cmpint(h1.read_count, ==, 0);
 246    g_assert_cmpint(h2.read_count, ==, 6);
 247    g_assert_cmpstr(h2.read_buf, ==, "hello");
 248    h2.read_count = 0;
 249
 250    /* print help */
 251    qemu_chr_be_write(base, (void *)"\1?", 2);
 252    data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
 253    g_assert_cmpint(strlen(data), !=, 0);
 254    g_free(data);
 255
 256    qemu_chr_fe_deinit(&chr_be1, false);
 257    qemu_chr_fe_deinit(&chr_be2, true);
 258}
 259
 260typedef struct SocketIdleData {
 261    GMainLoop *loop;
 262    Chardev *chr;
 263    bool conn_expected;
 264    CharBackend *be;
 265    CharBackend *client_be;
 266} SocketIdleData;
 267
 268static gboolean char_socket_test_idle(gpointer user_data)
 269{
 270    SocketIdleData *data = user_data;
 271
 272    if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
 273        == data->conn_expected) {
 274        quit = true;
 275        return FALSE;
 276    }
 277
 278    return TRUE;
 279}
 280
 281static void socket_read(void *opaque, const uint8_t *buf, int size)
 282{
 283    SocketIdleData *data = opaque;
 284
 285    g_assert_cmpint(size, ==, 1);
 286    g_assert_cmpint(*buf, ==, 'Z');
 287
 288    size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
 289    g_assert_cmpint(size, ==, 5);
 290}
 291
 292static int socket_can_read(void *opaque)
 293{
 294    return 10;
 295}
 296
 297static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
 298{
 299    g_assert_cmpint(size, ==, 5);
 300    g_assert(strncmp((char *)buf, "hello", 5) == 0);
 301
 302    quit = true;
 303}
 304
 305static int socket_can_read_hello(void *opaque)
 306{
 307    return 10;
 308}
 309
 310static void char_socket_test_common(Chardev *chr, bool reconnect)
 311{
 312    Chardev *chr_client;
 313    QObject *addr;
 314    QDict *qdict;
 315    const char *port;
 316    SocketIdleData d = { .chr = chr };
 317    CharBackend be;
 318    CharBackend client_be;
 319    char *tmp;
 320
 321    d.be = &be;
 322    d.client_be = &be;
 323
 324    g_assert_nonnull(chr);
 325    g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
 326
 327    addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
 328    qdict = qobject_to(QDict, addr);
 329    port = qdict_get_str(qdict, "port");
 330    tmp = g_strdup_printf("tcp:127.0.0.1:%s%s", port,
 331                          reconnect ? ",reconnect=1" : "");
 332    qobject_unref(qdict);
 333
 334    qemu_chr_fe_init(&be, chr, &error_abort);
 335    qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
 336                             NULL, NULL, &d, NULL, true);
 337
 338    chr_client = qemu_chr_new("client", tmp);
 339    qemu_chr_fe_init(&client_be, chr_client, &error_abort);
 340    qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
 341                             socket_read_hello,
 342                             NULL, NULL, &d, NULL, true);
 343    g_free(tmp);
 344
 345    d.conn_expected = true;
 346    guint id = g_idle_add(char_socket_test_idle, &d);
 347    g_source_set_name_by_id(id, "test-idle");
 348    g_assert_cmpint(id, >, 0);
 349    main_loop();
 350
 351    d.chr = chr_client;
 352    id = g_idle_add(char_socket_test_idle, &d);
 353    g_source_set_name_by_id(id, "test-idle");
 354    g_assert_cmpint(id, >, 0);
 355    main_loop();
 356
 357    g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
 358    g_assert(object_property_get_bool(OBJECT(chr_client),
 359                                      "connected", &error_abort));
 360
 361    qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
 362    main_loop();
 363
 364    object_unparent(OBJECT(chr_client));
 365
 366    d.chr = chr;
 367    d.conn_expected = false;
 368    g_idle_add(char_socket_test_idle, &d);
 369    main_loop();
 370
 371    object_unparent(OBJECT(chr));
 372}
 373
 374
 375static void char_socket_basic_test(void)
 376{
 377    Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
 378
 379    char_socket_test_common(chr, false);
 380}
 381
 382
 383static void char_socket_reconnect_test(void)
 384{
 385    Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
 386
 387    char_socket_test_common(chr, true);
 388}
 389
 390
 391static void char_socket_fdpass_test(void)
 392{
 393    Chardev *chr;
 394    char *optstr;
 395    QemuOpts *opts;
 396    int fd;
 397    SocketAddress *addr = g_new0(SocketAddress, 1);
 398
 399    addr->type = SOCKET_ADDRESS_TYPE_INET;
 400    addr->u.inet.host = g_strdup("127.0.0.1");
 401    addr->u.inet.port = g_strdup("0");
 402
 403    fd = socket_listen(addr, &error_abort);
 404    g_assert(fd >= 0);
 405
 406    qapi_free_SocketAddress(addr);
 407
 408    optstr = g_strdup_printf("socket,id=cdev,fd=%d,server,nowait", fd);
 409
 410    opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
 411                                   optstr, true);
 412    g_free(optstr);
 413    g_assert_nonnull(opts);
 414
 415    chr = qemu_chr_new_from_opts(opts, &error_abort);
 416
 417    qemu_opts_del(opts);
 418
 419    char_socket_test_common(chr, false);
 420}
 421
 422
 423static void websock_server_read(void *opaque, const uint8_t *buf, int size)
 424{
 425    g_assert_cmpint(size, ==, 5);
 426    g_assert(memcmp(buf, "world", size) == 0);
 427    quit = true;
 428}
 429
 430
 431static int websock_server_can_read(void *opaque)
 432{
 433    return 10;
 434}
 435
 436
 437static bool websock_check_http_headers(char *buf, int size)
 438{
 439    int i;
 440    const char *ans[] = { "HTTP/1.1 101 Switching Protocols\r\n",
 441                          "Server: QEMU VNC\r\n",
 442                          "Upgrade: websocket\r\n",
 443                          "Connection: Upgrade\r\n",
 444                          "Sec-WebSocket-Accept:",
 445                          "Sec-WebSocket-Protocol: binary\r\n" };
 446
 447    for (i = 0; i < 6; i++) {
 448        if (g_strstr_len(buf, size, ans[i]) == NULL) {
 449            return false;
 450        }
 451    }
 452
 453    return true;
 454}
 455
 456
 457static void websock_client_read(void *opaque, const uint8_t *buf, int size)
 458{
 459    const uint8_t ping[] = { 0x89, 0x85,                  /* Ping header */
 460                             0x07, 0x77, 0x9e, 0xf9,      /* Masking key */
 461                             0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ };
 462
 463    const uint8_t binary[] = { 0x82, 0x85,                  /* Binary header */
 464                               0x74, 0x90, 0xb9, 0xdf,      /* Masking key */
 465                               0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ };
 466    Chardev *chr_client = opaque;
 467
 468    if (websock_check_http_headers((char *) buf, size)) {
 469        qemu_chr_fe_write(chr_client->be, ping, sizeof(ping));
 470    } else if (buf[0] == 0x8a && buf[1] == 0x05) {
 471        g_assert(strncmp((char *) buf + 2, "hello", 5) == 0);
 472        qemu_chr_fe_write(chr_client->be, binary, sizeof(binary));
 473    } else {
 474        g_assert(buf[0] == 0x88 && buf[1] == 0x16);
 475        g_assert(strncmp((char *) buf + 4, "peer requested close", 10) == 0);
 476        quit = true;
 477    }
 478}
 479
 480
 481static int websock_client_can_read(void *opaque)
 482{
 483    return 4096;
 484}
 485
 486
 487static void char_websock_test(void)
 488{
 489    QObject *addr;
 490    QDict *qdict;
 491    const char *port;
 492    char *tmp;
 493    char *handshake_port;
 494    CharBackend be;
 495    CharBackend client_be;
 496    Chardev *chr_client;
 497    Chardev *chr = qemu_chr_new("server",
 498                                "websocket:127.0.0.1:0,server,nowait");
 499    const char handshake[] = "GET / HTTP/1.1\r\n"
 500                             "Upgrade: websocket\r\n"
 501                             "Connection: Upgrade\r\n"
 502                             "Host: localhost:%s\r\n"
 503                             "Origin: http://localhost:%s\r\n"
 504                             "Sec-WebSocket-Key: o9JHNiS3/0/0zYE1wa3yIw==\r\n"
 505                             "Sec-WebSocket-Version: 13\r\n"
 506                             "Sec-WebSocket-Protocol: binary\r\n\r\n";
 507    const uint8_t close[] = { 0x88, 0x82,             /* Close header */
 508                              0xef, 0xaa, 0xc5, 0x97, /* Masking key */
 509                              0xec, 0x42              /* Status code */ };
 510
 511    addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
 512    qdict = qobject_to(QDict, addr);
 513    port = qdict_get_str(qdict, "port");
 514    tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
 515    handshake_port = g_strdup_printf(handshake, port, port);
 516    qobject_unref(qdict);
 517
 518    qemu_chr_fe_init(&be, chr, &error_abort);
 519    qemu_chr_fe_set_handlers(&be, websock_server_can_read, websock_server_read,
 520                             NULL, NULL, chr, NULL, true);
 521
 522    chr_client = qemu_chr_new("client", tmp);
 523    qemu_chr_fe_init(&client_be, chr_client, &error_abort);
 524    qemu_chr_fe_set_handlers(&client_be, websock_client_can_read,
 525                             websock_client_read,
 526                             NULL, NULL, chr_client, NULL, true);
 527    g_free(tmp);
 528
 529    qemu_chr_write_all(chr_client,
 530                       (uint8_t *) handshake_port,
 531                       strlen(handshake_port));
 532    g_free(handshake_port);
 533    main_loop();
 534
 535    g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
 536    g_assert(object_property_get_bool(OBJECT(chr_client),
 537                                      "connected", &error_abort));
 538
 539    qemu_chr_write_all(chr_client, close, sizeof(close));
 540    main_loop();
 541
 542    object_unparent(OBJECT(chr_client));
 543    object_unparent(OBJECT(chr));
 544}
 545
 546
 547#ifndef _WIN32
 548static void char_pipe_test(void)
 549{
 550    gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 551    gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
 552    Chardev *chr;
 553    CharBackend be;
 554    int ret, fd;
 555    char buf[10];
 556    FeHandler fe = { 0, };
 557
 558    in = g_strdup_printf("%s.in", pipe);
 559    if (mkfifo(in, 0600) < 0) {
 560        abort();
 561    }
 562    out = g_strdup_printf("%s.out", pipe);
 563    if (mkfifo(out, 0600) < 0) {
 564        abort();
 565    }
 566
 567    tmp = g_strdup_printf("pipe:%s", pipe);
 568    chr = qemu_chr_new("pipe", tmp);
 569    g_assert_nonnull(chr);
 570    g_free(tmp);
 571
 572    qemu_chr_fe_init(&be, chr, &error_abort);
 573
 574    ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
 575    g_assert_cmpint(ret, ==, 9);
 576
 577    fd = open(out, O_RDWR);
 578    ret = read(fd, buf, sizeof(buf));
 579    g_assert_cmpint(ret, ==, 9);
 580    g_assert_cmpstr(buf, ==, "pipe-out");
 581    close(fd);
 582
 583    fd = open(in, O_WRONLY);
 584    ret = write(fd, "pipe-in", 8);
 585    g_assert_cmpint(ret, ==, 8);
 586    close(fd);
 587
 588    qemu_chr_fe_set_handlers(&be,
 589                             fe_can_read,
 590                             fe_read,
 591                             fe_event,
 592                             NULL,
 593                             &fe,
 594                             NULL, true);
 595
 596    main_loop();
 597
 598    g_assert_cmpint(fe.read_count, ==, 8);
 599    g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
 600
 601    qemu_chr_fe_deinit(&be, true);
 602
 603    g_assert(g_unlink(in) == 0);
 604    g_assert(g_unlink(out) == 0);
 605    g_assert(g_rmdir(tmp_path) == 0);
 606    g_free(in);
 607    g_free(out);
 608    g_free(tmp_path);
 609    g_free(pipe);
 610}
 611#endif
 612
 613static int make_udp_socket(int *port)
 614{
 615    struct sockaddr_in addr = { 0, };
 616    socklen_t alen = sizeof(addr);
 617    int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
 618
 619    g_assert_cmpint(sock, >, 0);
 620    addr.sin_family = AF_INET ;
 621    addr.sin_addr.s_addr = htonl(INADDR_ANY);
 622    addr.sin_port = 0;
 623    ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
 624    g_assert_cmpint(ret, ==, 0);
 625    ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
 626    g_assert_cmpint(ret, ==, 0);
 627
 628    *port = ntohs(addr.sin_port);
 629    return sock;
 630}
 631
 632static void char_udp_test_internal(Chardev *reuse_chr, int sock)
 633{
 634    struct sockaddr_in other;
 635    SocketIdleData d = { 0, };
 636    Chardev *chr;
 637    CharBackend *be;
 638    socklen_t alen = sizeof(other);
 639    int ret;
 640    char buf[10];
 641    char *tmp = NULL;
 642
 643    if (reuse_chr) {
 644        chr = reuse_chr;
 645        be = chr->be;
 646    } else {
 647        int port;
 648        sock = make_udp_socket(&port);
 649        tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
 650        chr = qemu_chr_new("client", tmp);
 651        g_assert_nonnull(chr);
 652
 653        be = g_alloca(sizeof(CharBackend));
 654        qemu_chr_fe_init(be, chr, &error_abort);
 655    }
 656
 657    d.chr = chr;
 658    qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
 659                             NULL, NULL, &d, NULL, true);
 660    ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
 661    g_assert_cmpint(ret, ==, 5);
 662
 663    ret = recvfrom(sock, buf, sizeof(buf), 0,
 664                   (struct sockaddr *)&other, &alen);
 665    g_assert_cmpint(ret, ==, 5);
 666    ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
 667    g_assert_cmpint(ret, ==, 5);
 668
 669    main_loop();
 670
 671    if (!reuse_chr) {
 672        close(sock);
 673        qemu_chr_fe_deinit(be, true);
 674    }
 675    g_free(tmp);
 676}
 677
 678static void char_udp_test(void)
 679{
 680    char_udp_test_internal(NULL, 0);
 681}
 682
 683#ifdef HAVE_CHARDEV_SERIAL
 684static void char_serial_test(void)
 685{
 686    QemuOpts *opts;
 687    Chardev *chr;
 688
 689    opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
 690                            1, &error_abort);
 691    qemu_opt_set(opts, "backend", "serial", &error_abort);
 692    qemu_opt_set(opts, "path", "/dev/null", &error_abort);
 693
 694    chr = qemu_chr_new_from_opts(opts, NULL);
 695    g_assert_nonnull(chr);
 696    /* TODO: add more tests with a pty */
 697    object_unparent(OBJECT(chr));
 698
 699    /* test tty alias */
 700    qemu_opt_set(opts, "backend", "tty", &error_abort);
 701    chr = qemu_chr_new_from_opts(opts, NULL);
 702    g_assert_nonnull(chr);
 703    object_unparent(OBJECT(chr));
 704
 705    qemu_opts_del(opts);
 706}
 707#endif
 708
 709#ifndef _WIN32
 710static void char_file_fifo_test(void)
 711{
 712    Chardev *chr;
 713    CharBackend be;
 714    char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 715    char *fifo = g_build_filename(tmp_path, "fifo", NULL);
 716    char *out = g_build_filename(tmp_path, "out", NULL);
 717    ChardevFile file = { .in = fifo,
 718                         .has_in = true,
 719                         .out = out };
 720    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
 721                               .u.file.data = &file };
 722    FeHandler fe = { 0, };
 723    int fd, ret;
 724
 725    if (mkfifo(fifo, 0600) < 0) {
 726        abort();
 727    }
 728
 729    fd = open(fifo, O_RDWR);
 730    ret = write(fd, "fifo-in", 8);
 731    g_assert_cmpint(ret, ==, 8);
 732
 733    chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
 734                           &error_abort);
 735
 736    qemu_chr_fe_init(&be, chr, &error_abort);
 737    qemu_chr_fe_set_handlers(&be,
 738                             fe_can_read,
 739                             fe_read,
 740                             fe_event,
 741                             NULL,
 742                             &fe, NULL, true);
 743
 744    g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
 745    qmp_chardev_send_break("label-foo", NULL);
 746    g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
 747    qmp_chardev_send_break("label-file", NULL);
 748    g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
 749
 750    main_loop();
 751
 752    close(fd);
 753
 754    g_assert_cmpint(fe.read_count, ==, 8);
 755    g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
 756
 757    qemu_chr_fe_deinit(&be, true);
 758
 759    g_unlink(fifo);
 760    g_free(fifo);
 761    g_unlink(out);
 762    g_free(out);
 763    g_rmdir(tmp_path);
 764    g_free(tmp_path);
 765}
 766#endif
 767
 768static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
 769{
 770    char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 771    char *out;
 772    Chardev *chr;
 773    char *contents = NULL;
 774    ChardevFile file = {};
 775    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
 776                               .u.file.data = &file };
 777    gsize length;
 778    int ret;
 779
 780    if (ext_chr) {
 781        chr = ext_chr;
 782        out = g_strdup(filepath);
 783        file.out = out;
 784    } else {
 785        out = g_build_filename(tmp_path, "out", NULL);
 786        file.out = out;
 787        chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
 788                               &error_abort);
 789    }
 790    ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
 791    g_assert_cmpint(ret, ==, 6);
 792
 793    ret = g_file_get_contents(out, &contents, &length, NULL);
 794    g_assert(ret == TRUE);
 795    g_assert_cmpint(length, ==, 6);
 796    g_assert(strncmp(contents, "hello!", 6) == 0);
 797
 798    if (!ext_chr) {
 799        object_unref(OBJECT(chr));
 800        g_unlink(out);
 801    }
 802    g_free(contents);
 803    g_rmdir(tmp_path);
 804    g_free(tmp_path);
 805    g_free(out);
 806}
 807
 808static void char_file_test(void)
 809{
 810    char_file_test_internal(NULL, NULL);
 811}
 812
 813static void char_null_test(void)
 814{
 815    Error *err = NULL;
 816    Chardev *chr;
 817    CharBackend be;
 818    int ret;
 819
 820    chr = qemu_chr_find("label-null");
 821    g_assert_null(chr);
 822
 823    chr = qemu_chr_new("label-null", "null");
 824    chr = qemu_chr_find("label-null");
 825    g_assert_nonnull(chr);
 826
 827    g_assert(qemu_chr_has_feature(chr,
 828                 QEMU_CHAR_FEATURE_FD_PASS) == false);
 829    g_assert(qemu_chr_has_feature(chr,
 830                 QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
 831
 832    /* check max avail */
 833    qemu_chr_fe_init(&be, chr, &error_abort);
 834    qemu_chr_fe_init(&be, chr, &err);
 835    error_free_or_abort(&err);
 836
 837    /* deinit & reinit */
 838    qemu_chr_fe_deinit(&be, false);
 839    qemu_chr_fe_init(&be, chr, &error_abort);
 840
 841    qemu_chr_fe_set_open(&be, true);
 842
 843    qemu_chr_fe_set_handlers(&be,
 844                             fe_can_read,
 845                             fe_read,
 846                             fe_event,
 847                             NULL,
 848                             NULL, NULL, true);
 849
 850    ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
 851    g_assert_cmpint(ret, ==, 4);
 852
 853    qemu_chr_fe_deinit(&be, true);
 854}
 855
 856static void char_invalid_test(void)
 857{
 858    Chardev *chr;
 859
 860    chr = qemu_chr_new("label-invalid", "invalid");
 861    g_assert_null(chr);
 862}
 863
 864static int chardev_change(void *opaque)
 865{
 866    return 0;
 867}
 868
 869static int chardev_change_denied(void *opaque)
 870{
 871    return -1;
 872}
 873
 874static void char_hotswap_test(void)
 875{
 876    char *chr_args;
 877    Chardev *chr;
 878    CharBackend be;
 879
 880    gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
 881    char *filename = g_build_filename(tmp_path, "file", NULL);
 882    ChardevFile file = { .out = filename };
 883    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
 884                               .u.file.data = &file };
 885    ChardevReturn *ret;
 886
 887    int port;
 888    int sock = make_udp_socket(&port);
 889    g_assert_cmpint(sock, >, 0);
 890
 891    chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
 892
 893    chr = qemu_chr_new("chardev", chr_args);
 894    qemu_chr_fe_init(&be, chr, &error_abort);
 895
 896    /* check that chardev operates correctly */
 897    char_udp_test_internal(chr, sock);
 898
 899    /* set the handler that denies the hotswap */
 900    qemu_chr_fe_set_handlers(&be, NULL, NULL,
 901                             NULL, chardev_change_denied, NULL, NULL, true);
 902
 903    /* now, change is denied and has to keep the old backend operating */
 904    ret = qmp_chardev_change("chardev", &backend, NULL);
 905    g_assert(!ret);
 906    g_assert(be.chr == chr);
 907
 908    char_udp_test_internal(chr, sock);
 909
 910    /* now allow the change */
 911    qemu_chr_fe_set_handlers(&be, NULL, NULL,
 912                             NULL, chardev_change, NULL, NULL, true);
 913
 914    /* has to succeed now */
 915    ret = qmp_chardev_change("chardev", &backend, &error_abort);
 916    g_assert(be.chr != chr);
 917
 918    close(sock);
 919    chr = be.chr;
 920
 921    /* run the file chardev test */
 922    char_file_test_internal(chr, filename);
 923
 924    object_unparent(OBJECT(chr));
 925
 926    qapi_free_ChardevReturn(ret);
 927    g_unlink(filename);
 928    g_free(filename);
 929    g_rmdir(tmp_path);
 930    g_free(tmp_path);
 931    g_free(chr_args);
 932}
 933
 934int main(int argc, char **argv)
 935{
 936    qemu_init_main_loop(&error_abort);
 937    socket_init();
 938
 939    g_test_init(&argc, &argv, NULL);
 940
 941    module_call_init(MODULE_INIT_QOM);
 942    qemu_add_opts(&qemu_chardev_opts);
 943
 944    g_test_add_func("/char/null", char_null_test);
 945    g_test_add_func("/char/invalid", char_invalid_test);
 946    g_test_add_func("/char/ringbuf", char_ringbuf_test);
 947    g_test_add_func("/char/mux", char_mux_test);
 948#ifdef _WIN32
 949    g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
 950    g_test_add_func("/char/console", char_console_test);
 951#endif
 952    g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
 953    g_test_add_func("/char/stdio", char_stdio_test);
 954#ifndef _WIN32
 955    g_test_add_func("/char/pipe", char_pipe_test);
 956#endif
 957    g_test_add_func("/char/file", char_file_test);
 958#ifndef _WIN32
 959    g_test_add_func("/char/file-fifo", char_file_fifo_test);
 960#endif
 961    g_test_add_func("/char/socket/basic", char_socket_basic_test);
 962    g_test_add_func("/char/socket/reconnect", char_socket_reconnect_test);
 963    g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test);
 964    g_test_add_func("/char/udp", char_udp_test);
 965#ifdef HAVE_CHARDEV_SERIAL
 966    g_test_add_func("/char/serial", char_serial_test);
 967#endif
 968    g_test_add_func("/char/hotswap", char_hotswap_test);
 969    g_test_add_func("/char/websocket", char_websock_test);
 970
 971    return g_test_run();
 972}
 973