char: allow passing pre-opened socket file descriptor at startup
[qemu/ar7.git] / tests / test-char.c
blobdffb3542029f61536cc0d23cffc640662e805582
1 #include "qemu/osdep.h"
2 #include <glib/gstdio.h>
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"
15 static bool quit;
17 typedef struct FeHandler {
18 int read_count;
19 int last_event;
20 char read_buf[128];
21 } FeHandler;
23 static void main_loop(void)
25 quit = false;
26 do {
27 main_loop_wait(false);
28 } while (!quit);
31 static int fe_can_read(void *opaque)
33 FeHandler *h = opaque;
35 return sizeof(h->read_buf) - h->read_count;
38 static void fe_read(void *opaque, const uint8_t *buf, int size)
40 FeHandler *h = opaque;
42 g_assert_cmpint(size, <=, fe_can_read(opaque));
44 memcpy(h->read_buf + h->read_count, buf, size);
45 h->read_count += size;
46 quit = true;
49 static void fe_event(void *opaque, int event)
51 FeHandler *h = opaque;
53 h->last_event = event;
54 if (event != CHR_EVENT_BREAK) {
55 quit = true;
59 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
60 #ifdef _WIN32
61 static void char_console_test_subprocess(void)
63 QemuOpts *opts;
64 Chardev *chr;
66 opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
67 1, &error_abort);
68 qemu_opt_set(opts, "backend", "console", &error_abort);
70 chr = qemu_chr_new_from_opts(opts, NULL);
71 g_assert_nonnull(chr);
73 qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
75 qemu_opts_del(opts);
76 object_unparent(OBJECT(chr));
79 static void char_console_test(void)
81 g_test_trap_subprocess("/char/console/subprocess", 0, 0);
82 g_test_trap_assert_passed();
83 g_test_trap_assert_stdout("CONSOLE");
85 #endif
86 static void char_stdio_test_subprocess(void)
88 Chardev *chr;
89 CharBackend be;
90 int ret;
92 chr = qemu_chr_new("label", "stdio");
93 g_assert_nonnull(chr);
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);
100 qemu_chr_fe_deinit(&be, true);
103 static void char_stdio_test(void)
105 g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
106 g_test_trap_assert_passed();
107 g_test_trap_assert_stdout("buf");
109 #endif
111 static void char_ringbuf_test(void)
113 QemuOpts *opts;
114 Chardev *chr;
115 CharBackend be;
116 char *data;
117 int ret;
119 opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
120 1, &error_abort);
121 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
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);
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);
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);
140 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
141 g_assert_cmpstr(data, ==, "ff");
142 g_free(data);
144 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
145 g_assert_cmpstr(data, ==, "");
146 g_free(data);
148 qemu_chr_fe_deinit(&be, true);
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);
161 static void char_mux_test(void)
163 QemuOpts *opts;
164 Chardev *chr, *base;
165 char *data;
166 FeHandler h1 = { 0, }, h2 = { 0, };
167 CharBackend chr_be1, chr_be2;
169 muxes_realized = true; /* done after machine init */
170 opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
171 1, &error_abort);
172 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
173 qemu_opt_set(opts, "size", "128", &error_abort);
174 qemu_opt_set(opts, "mux", "on", &error_abort);
175 chr = qemu_chr_new_from_opts(opts, &error_abort);
176 g_assert_nonnull(chr);
177 qemu_opts_del(opts);
179 qemu_chr_fe_init(&chr_be1, chr, &error_abort);
180 qemu_chr_fe_set_handlers(&chr_be1,
181 fe_can_read,
182 fe_read,
183 fe_event,
184 NULL,
185 &h1,
186 NULL, true);
188 qemu_chr_fe_init(&chr_be2, chr, &error_abort);
189 qemu_chr_fe_set_handlers(&chr_be2,
190 fe_can_read,
191 fe_read,
192 fe_event,
193 NULL,
194 &h2,
195 NULL, true);
196 qemu_chr_fe_take_focus(&chr_be2);
198 base = qemu_chr_find("mux-label-base");
199 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
201 qemu_chr_be_write(base, (void *)"hello", 6);
202 g_assert_cmpint(h1.read_count, ==, 0);
203 g_assert_cmpint(h2.read_count, ==, 6);
204 g_assert_cmpstr(h2.read_buf, ==, "hello");
205 h2.read_count = 0;
207 g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */
208 g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */
209 /* sending event on the base broadcast to all fe, historical reasons? */
210 qemu_chr_be_event(base, 42);
211 g_assert_cmpint(h1.last_event, ==, 42);
212 g_assert_cmpint(h2.last_event, ==, 42);
213 qemu_chr_be_event(chr, -1);
214 g_assert_cmpint(h1.last_event, ==, 42);
215 g_assert_cmpint(h2.last_event, ==, -1);
217 /* switch focus */
218 qemu_chr_be_write(base, (void *)"\1c", 2);
219 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
220 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
221 qemu_chr_be_event(chr, -1);
222 g_assert_cmpint(h1.last_event, ==, -1);
223 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
225 qemu_chr_be_write(base, (void *)"hello", 6);
226 g_assert_cmpint(h2.read_count, ==, 0);
227 g_assert_cmpint(h1.read_count, ==, 6);
228 g_assert_cmpstr(h1.read_buf, ==, "hello");
229 h1.read_count = 0;
231 /* remove first handler */
232 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
233 NULL, NULL, true);
234 qemu_chr_be_write(base, (void *)"hello", 6);
235 g_assert_cmpint(h1.read_count, ==, 0);
236 g_assert_cmpint(h2.read_count, ==, 0);
238 qemu_chr_be_write(base, (void *)"\1c", 2);
239 qemu_chr_be_write(base, (void *)"hello", 6);
240 g_assert_cmpint(h1.read_count, ==, 0);
241 g_assert_cmpint(h2.read_count, ==, 6);
242 g_assert_cmpstr(h2.read_buf, ==, "hello");
243 h2.read_count = 0;
245 /* print help */
246 qemu_chr_be_write(base, (void *)"\1?", 2);
247 data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
248 g_assert_cmpint(strlen(data), !=, 0);
249 g_free(data);
251 qemu_chr_fe_deinit(&chr_be1, false);
252 qemu_chr_fe_deinit(&chr_be2, true);
255 typedef struct SocketIdleData {
256 GMainLoop *loop;
257 Chardev *chr;
258 bool conn_expected;
259 CharBackend *be;
260 CharBackend *client_be;
261 } SocketIdleData;
263 static gboolean char_socket_test_idle(gpointer user_data)
265 SocketIdleData *data = user_data;
267 if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
268 == data->conn_expected) {
269 quit = true;
270 return FALSE;
273 return TRUE;
276 static void socket_read(void *opaque, const uint8_t *buf, int size)
278 SocketIdleData *data = opaque;
280 g_assert_cmpint(size, ==, 1);
281 g_assert_cmpint(*buf, ==, 'Z');
283 size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
284 g_assert_cmpint(size, ==, 5);
287 static int socket_can_read(void *opaque)
289 return 10;
292 static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
294 g_assert_cmpint(size, ==, 5);
295 g_assert(strncmp((char *)buf, "hello", 5) == 0);
297 quit = true;
300 static int socket_can_read_hello(void *opaque)
302 return 10;
305 static void char_socket_test_common(Chardev *chr)
307 Chardev *chr_client;
308 QObject *addr;
309 QDict *qdict;
310 const char *port;
311 SocketIdleData d = { .chr = chr };
312 CharBackend be;
313 CharBackend client_be;
314 char *tmp;
316 d.be = &be;
317 d.client_be = &be;
319 g_assert_nonnull(chr);
320 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
322 addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
323 qdict = qobject_to_qdict(addr);
324 port = qdict_get_str(qdict, "port");
325 tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
326 QDECREF(qdict);
328 qemu_chr_fe_init(&be, chr, &error_abort);
329 qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
330 NULL, NULL, &d, NULL, true);
332 chr_client = qemu_chr_new("client", tmp);
333 qemu_chr_fe_init(&client_be, chr_client, &error_abort);
334 qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
335 socket_read_hello,
336 NULL, NULL, &d, NULL, true);
337 g_free(tmp);
339 d.conn_expected = true;
340 guint id = g_idle_add(char_socket_test_idle, &d);
341 g_source_set_name_by_id(id, "test-idle");
342 g_assert_cmpint(id, >, 0);
343 main_loop();
345 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
346 g_assert(object_property_get_bool(OBJECT(chr_client),
347 "connected", &error_abort));
349 qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
350 main_loop();
352 object_unparent(OBJECT(chr_client));
354 d.conn_expected = false;
355 g_idle_add(char_socket_test_idle, &d);
356 main_loop();
358 object_unparent(OBJECT(chr));
362 static void char_socket_basic_test(void)
364 Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
366 char_socket_test_common(chr);
370 static void char_socket_fdpass_test(void)
372 Chardev *chr;
373 char *optstr;
374 QemuOpts *opts;
375 int fd;
376 SocketAddress *addr = g_new0(SocketAddress, 1);
378 addr->type = SOCKET_ADDRESS_TYPE_INET;
379 addr->u.inet.host = g_strdup("127.0.0.1");
380 addr->u.inet.port = g_strdup("0");
382 fd = socket_listen(addr, &error_abort);
383 g_assert(fd >= 0);
385 qapi_free_SocketAddress(addr);
387 optstr = g_strdup_printf("socket,id=cdev,fd=%d,server,nowait", fd);
389 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
390 optstr, true);
391 g_free(optstr);
392 g_assert_nonnull(opts);
394 chr = qemu_chr_new_from_opts(opts, &error_abort);
396 qemu_opts_del(opts);
398 char_socket_test_common(chr);
402 #ifndef _WIN32
403 static void char_pipe_test(void)
405 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
406 gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
407 Chardev *chr;
408 CharBackend be;
409 int ret, fd;
410 char buf[10];
411 FeHandler fe = { 0, };
413 in = g_strdup_printf("%s.in", pipe);
414 if (mkfifo(in, 0600) < 0) {
415 abort();
417 out = g_strdup_printf("%s.out", pipe);
418 if (mkfifo(out, 0600) < 0) {
419 abort();
422 tmp = g_strdup_printf("pipe:%s", pipe);
423 chr = qemu_chr_new("pipe", tmp);
424 g_assert_nonnull(chr);
425 g_free(tmp);
427 qemu_chr_fe_init(&be, chr, &error_abort);
429 ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
430 g_assert_cmpint(ret, ==, 9);
432 fd = open(out, O_RDWR);
433 ret = read(fd, buf, sizeof(buf));
434 g_assert_cmpint(ret, ==, 9);
435 g_assert_cmpstr(buf, ==, "pipe-out");
436 close(fd);
438 fd = open(in, O_WRONLY);
439 ret = write(fd, "pipe-in", 8);
440 g_assert_cmpint(ret, ==, 8);
441 close(fd);
443 qemu_chr_fe_set_handlers(&be,
444 fe_can_read,
445 fe_read,
446 fe_event,
447 NULL,
448 &fe,
449 NULL, true);
451 main_loop();
453 g_assert_cmpint(fe.read_count, ==, 8);
454 g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
456 qemu_chr_fe_deinit(&be, true);
458 g_assert(g_unlink(in) == 0);
459 g_assert(g_unlink(out) == 0);
460 g_assert(g_rmdir(tmp_path) == 0);
461 g_free(in);
462 g_free(out);
463 g_free(tmp_path);
464 g_free(pipe);
466 #endif
468 static int make_udp_socket(int *port)
470 struct sockaddr_in addr = { 0, };
471 socklen_t alen = sizeof(addr);
472 int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
474 g_assert_cmpint(sock, >, 0);
475 addr.sin_family = AF_INET ;
476 addr.sin_addr.s_addr = htonl(INADDR_ANY);
477 addr.sin_port = 0;
478 ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
479 g_assert_cmpint(ret, ==, 0);
480 ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
481 g_assert_cmpint(ret, ==, 0);
483 *port = ntohs(addr.sin_port);
484 return sock;
487 static void char_udp_test_internal(Chardev *reuse_chr, int sock)
489 struct sockaddr_in other;
490 SocketIdleData d = { 0, };
491 Chardev *chr;
492 CharBackend *be;
493 socklen_t alen = sizeof(other);
494 int ret;
495 char buf[10];
496 char *tmp = NULL;
498 if (reuse_chr) {
499 chr = reuse_chr;
500 be = chr->be;
501 } else {
502 int port;
503 sock = make_udp_socket(&port);
504 tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
505 chr = qemu_chr_new("client", tmp);
506 g_assert_nonnull(chr);
508 be = g_alloca(sizeof(CharBackend));
509 qemu_chr_fe_init(be, chr, &error_abort);
512 d.chr = chr;
513 qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
514 NULL, NULL, &d, NULL, true);
515 ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
516 g_assert_cmpint(ret, ==, 5);
518 ret = recvfrom(sock, buf, sizeof(buf), 0,
519 (struct sockaddr *)&other, &alen);
520 g_assert_cmpint(ret, ==, 5);
521 ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
522 g_assert_cmpint(ret, ==, 5);
524 main_loop();
526 if (!reuse_chr) {
527 close(sock);
528 qemu_chr_fe_deinit(be, true);
530 g_free(tmp);
533 static void char_udp_test(void)
535 char_udp_test_internal(NULL, 0);
538 #ifdef HAVE_CHARDEV_SERIAL
539 static void char_serial_test(void)
541 QemuOpts *opts;
542 Chardev *chr;
544 opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
545 1, &error_abort);
546 qemu_opt_set(opts, "backend", "serial", &error_abort);
547 qemu_opt_set(opts, "path", "/dev/null", &error_abort);
549 chr = qemu_chr_new_from_opts(opts, NULL);
550 g_assert_nonnull(chr);
551 /* TODO: add more tests with a pty */
552 object_unparent(OBJECT(chr));
554 /* test tty alias */
555 qemu_opt_set(opts, "backend", "tty", &error_abort);
556 chr = qemu_chr_new_from_opts(opts, NULL);
557 g_assert_nonnull(chr);
558 object_unparent(OBJECT(chr));
560 qemu_opts_del(opts);
562 #endif
564 #ifndef _WIN32
565 static void char_file_fifo_test(void)
567 Chardev *chr;
568 CharBackend be;
569 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
570 char *fifo = g_build_filename(tmp_path, "fifo", NULL);
571 char *out = g_build_filename(tmp_path, "out", NULL);
572 ChardevFile file = { .in = fifo,
573 .has_in = true,
574 .out = out };
575 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
576 .u.file.data = &file };
577 FeHandler fe = { 0, };
578 int fd, ret;
580 if (mkfifo(fifo, 0600) < 0) {
581 abort();
584 fd = open(fifo, O_RDWR);
585 ret = write(fd, "fifo-in", 8);
586 g_assert_cmpint(ret, ==, 8);
588 chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
589 &error_abort);
591 qemu_chr_fe_init(&be, chr, &error_abort);
592 qemu_chr_fe_set_handlers(&be,
593 fe_can_read,
594 fe_read,
595 fe_event,
596 NULL,
597 &fe, NULL, true);
599 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
600 qmp_chardev_send_break("label-foo", NULL);
601 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
602 qmp_chardev_send_break("label-file", NULL);
603 g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
605 main_loop();
607 close(fd);
609 g_assert_cmpint(fe.read_count, ==, 8);
610 g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
612 qemu_chr_fe_deinit(&be, true);
614 g_unlink(fifo);
615 g_free(fifo);
616 g_unlink(out);
617 g_free(out);
618 g_rmdir(tmp_path);
619 g_free(tmp_path);
621 #endif
623 static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
625 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
626 char *out;
627 Chardev *chr;
628 char *contents = NULL;
629 ChardevFile file = {};
630 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
631 .u.file.data = &file };
632 gsize length;
633 int ret;
635 if (ext_chr) {
636 chr = ext_chr;
637 out = g_strdup(filepath);
638 file.out = out;
639 } else {
640 out = g_build_filename(tmp_path, "out", NULL);
641 file.out = out;
642 chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
643 &error_abort);
645 ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
646 g_assert_cmpint(ret, ==, 6);
648 ret = g_file_get_contents(out, &contents, &length, NULL);
649 g_assert(ret == TRUE);
650 g_assert_cmpint(length, ==, 6);
651 g_assert(strncmp(contents, "hello!", 6) == 0);
653 if (!ext_chr) {
654 object_unref(OBJECT(chr));
655 g_unlink(out);
657 g_free(contents);
658 g_rmdir(tmp_path);
659 g_free(tmp_path);
660 g_free(out);
663 static void char_file_test(void)
665 char_file_test_internal(NULL, NULL);
668 static void char_null_test(void)
670 Error *err = NULL;
671 Chardev *chr;
672 CharBackend be;
673 int ret;
675 chr = qemu_chr_find("label-null");
676 g_assert_null(chr);
678 chr = qemu_chr_new("label-null", "null");
679 chr = qemu_chr_find("label-null");
680 g_assert_nonnull(chr);
682 g_assert(qemu_chr_has_feature(chr,
683 QEMU_CHAR_FEATURE_FD_PASS) == false);
684 g_assert(qemu_chr_has_feature(chr,
685 QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
687 /* check max avail */
688 qemu_chr_fe_init(&be, chr, &error_abort);
689 qemu_chr_fe_init(&be, chr, &err);
690 error_free_or_abort(&err);
692 /* deinit & reinit */
693 qemu_chr_fe_deinit(&be, false);
694 qemu_chr_fe_init(&be, chr, &error_abort);
696 qemu_chr_fe_set_open(&be, true);
698 qemu_chr_fe_set_handlers(&be,
699 fe_can_read,
700 fe_read,
701 fe_event,
702 NULL,
703 NULL, NULL, true);
705 ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
706 g_assert_cmpint(ret, ==, 4);
708 qemu_chr_fe_deinit(&be, true);
711 static void char_invalid_test(void)
713 Chardev *chr;
715 chr = qemu_chr_new("label-invalid", "invalid");
716 g_assert_null(chr);
719 static int chardev_change(void *opaque)
721 return 0;
724 static int chardev_change_denied(void *opaque)
726 return -1;
729 static void char_hotswap_test(void)
731 char *chr_args;
732 Chardev *chr;
733 CharBackend be;
735 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
736 char *filename = g_build_filename(tmp_path, "file", NULL);
737 ChardevFile file = { .out = filename };
738 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
739 .u.file.data = &file };
740 ChardevReturn *ret;
742 int port;
743 int sock = make_udp_socket(&port);
744 g_assert_cmpint(sock, >, 0);
746 chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
748 chr = qemu_chr_new("chardev", chr_args);
749 qemu_chr_fe_init(&be, chr, &error_abort);
751 /* check that chardev operates correctly */
752 char_udp_test_internal(chr, sock);
754 /* set the handler that denies the hotswap */
755 qemu_chr_fe_set_handlers(&be, NULL, NULL,
756 NULL, chardev_change_denied, NULL, NULL, true);
758 /* now, change is denied and has to keep the old backend operating */
759 ret = qmp_chardev_change("chardev", &backend, NULL);
760 g_assert(!ret);
761 g_assert(be.chr == chr);
763 char_udp_test_internal(chr, sock);
765 /* now allow the change */
766 qemu_chr_fe_set_handlers(&be, NULL, NULL,
767 NULL, chardev_change, NULL, NULL, true);
769 /* has to succeed now */
770 ret = qmp_chardev_change("chardev", &backend, &error_abort);
771 g_assert(be.chr != chr);
773 close(sock);
774 chr = be.chr;
776 /* run the file chardev test */
777 char_file_test_internal(chr, filename);
779 object_unparent(OBJECT(chr));
781 qapi_free_ChardevReturn(ret);
782 g_unlink(filename);
783 g_free(filename);
784 g_rmdir(tmp_path);
785 g_free(tmp_path);
786 g_free(chr_args);
789 int main(int argc, char **argv)
791 qemu_init_main_loop(&error_abort);
792 socket_init();
794 g_test_init(&argc, &argv, NULL);
796 module_call_init(MODULE_INIT_QOM);
797 qemu_add_opts(&qemu_chardev_opts);
799 g_test_add_func("/char/null", char_null_test);
800 g_test_add_func("/char/invalid", char_invalid_test);
801 g_test_add_func("/char/ringbuf", char_ringbuf_test);
802 g_test_add_func("/char/mux", char_mux_test);
803 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
804 #ifdef _WIN32
805 g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
806 g_test_add_func("/char/console", char_console_test);
807 #endif
808 g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
809 g_test_add_func("/char/stdio", char_stdio_test);
810 #endif
811 #ifndef _WIN32
812 g_test_add_func("/char/pipe", char_pipe_test);
813 #endif
814 g_test_add_func("/char/file", char_file_test);
815 #ifndef _WIN32
816 g_test_add_func("/char/file-fifo", char_file_fifo_test);
817 #endif
818 g_test_add_func("/char/socket/basic", char_socket_basic_test);
819 g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test);
820 g_test_add_func("/char/udp", char_udp_test);
821 #ifdef HAVE_CHARDEV_SERIAL
822 g_test_add_func("/char/serial", char_serial_test);
823 #endif
824 g_test_add_func("/char/hotswap", char_hotswap_test);
826 return g_test_run();