OSDN Git Service

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