char: allow passing pre-opened socket file descriptor at startup
[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 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);
178
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);
187
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);
197
198 base = qemu_chr_find("mux-label-base");
199 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
200
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;
206
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);
216
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);
224
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;
230
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);
237
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;
244
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);
250
251 qemu_chr_fe_deinit(&chr_be1, false);
252 qemu_chr_fe_deinit(&chr_be2, true);
253 }
254
255 typedef struct SocketIdleData {
256 GMainLoop *loop;
257 Chardev *chr;
258 bool conn_expected;
259 CharBackend *be;
260 CharBackend *client_be;
261 } SocketIdleData;
262
263 static gboolean char_socket_test_idle(gpointer user_data)
264 {
265 SocketIdleData *data = user_data;
266
267 if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
268 == data->conn_expected) {
269 quit = true;
270 return FALSE;
271 }
272
273 return TRUE;
274 }
275
276 static void socket_read(void *opaque, const uint8_t *buf, int size)
277 {
278 SocketIdleData *data = opaque;
279
280 g_assert_cmpint(size, ==, 1);
281 g_assert_cmpint(*buf, ==, 'Z');
282
283 size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
284 g_assert_cmpint(size, ==, 5);
285 }
286
287 static int socket_can_read(void *opaque)
288 {
289 return 10;
290 }
291
292 static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
293 {
294 g_assert_cmpint(size, ==, 5);
295 g_assert(strncmp((char *)buf, "hello", 5) == 0);
296
297 quit = true;
298 }
299
300 static int socket_can_read_hello(void *opaque)
301 {
302 return 10;
303 }
304
305 static void char_socket_test_common(Chardev *chr)
306 {
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;
315
316 d.be = &be;
317 d.client_be = &be;
318
319 g_assert_nonnull(chr);
320 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
321
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);
327
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);
331
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);
338
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();
344
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));
348
349 qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
350 main_loop();
351
352 object_unparent(OBJECT(chr_client));
353
354 d.conn_expected = false;
355 g_idle_add(char_socket_test_idle, &d);
356 main_loop();
357
358 object_unparent(OBJECT(chr));
359 }
360
361
362 static void char_socket_basic_test(void)
363 {
364 Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
365
366 char_socket_test_common(chr);
367 }
368
369
370 static void char_socket_fdpass_test(void)
371 {
372 Chardev *chr;
373 char *optstr;
374 QemuOpts *opts;
375 int fd;
376 SocketAddress *addr = g_new0(SocketAddress, 1);
377
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");
381
382 fd = socket_listen(addr, &error_abort);
383 g_assert(fd >= 0);
384
385 qapi_free_SocketAddress(addr);
386
387 optstr = g_strdup_printf("socket,id=cdev,fd=%d,server,nowait", fd);
388
389 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
390 optstr, true);
391 g_free(optstr);
392 g_assert_nonnull(opts);
393
394 chr = qemu_chr_new_from_opts(opts, &error_abort);
395
396 qemu_opts_del(opts);
397
398 char_socket_test_common(chr);
399 }
400
401
402 #ifndef _WIN32
403 static void char_pipe_test(void)
404 {
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, };
412
413 in = g_strdup_printf("%s.in", pipe);
414 if (mkfifo(in, 0600) < 0) {
415 abort();
416 }
417 out = g_strdup_printf("%s.out", pipe);
418 if (mkfifo(out, 0600) < 0) {
419 abort();
420 }
421
422 tmp = g_strdup_printf("pipe:%s", pipe);
423 chr = qemu_chr_new("pipe", tmp);
424 g_assert_nonnull(chr);
425 g_free(tmp);
426
427 qemu_chr_fe_init(&be, chr, &error_abort);
428
429 ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
430 g_assert_cmpint(ret, ==, 9);
431
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);
437
438 fd = open(in, O_WRONLY);
439 ret = write(fd, "pipe-in", 8);
440 g_assert_cmpint(ret, ==, 8);
441 close(fd);
442
443 qemu_chr_fe_set_handlers(&be,
444 fe_can_read,
445 fe_read,
446 fe_event,
447 NULL,
448 &fe,
449 NULL, true);
450
451 main_loop();
452
453 g_assert_cmpint(fe.read_count, ==, 8);
454 g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
455
456 qemu_chr_fe_deinit(&be, true);
457
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);
465 }
466 #endif
467
468 static int make_udp_socket(int *port)
469 {
470 struct sockaddr_in addr = { 0, };
471 socklen_t alen = sizeof(addr);
472 int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
473
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);
482
483 *port = ntohs(addr.sin_port);
484 return sock;
485 }
486
487 static void char_udp_test_internal(Chardev *reuse_chr, int sock)
488 {
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;
497
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);
507
508 be = g_alloca(sizeof(CharBackend));
509 qemu_chr_fe_init(be, chr, &error_abort);
510 }
511
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);
517
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);
523
524 main_loop();
525
526 if (!reuse_chr) {
527 close(sock);
528 qemu_chr_fe_deinit(be, true);
529 }
530 g_free(tmp);
531 }
532
533 static void char_udp_test(void)
534 {
535 char_udp_test_internal(NULL, 0);
536 }
537
538 #ifdef HAVE_CHARDEV_SERIAL
539 static void char_serial_test(void)
540 {
541 QemuOpts *opts;
542 Chardev *chr;
543
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);
548
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));
553
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));
559
560 qemu_opts_del(opts);
561 }
562 #endif
563
564 #ifndef _WIN32
565 static void char_file_fifo_test(void)
566 {
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;
579
580 if (mkfifo(fifo, 0600) < 0) {
581 abort();
582 }
583
584 fd = open(fifo, O_RDWR);
585 ret = write(fd, "fifo-in", 8);
586 g_assert_cmpint(ret, ==, 8);
587
588 chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
589 &error_abort);
590
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);
598
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);
604
605 main_loop();
606
607 close(fd);
608
609 g_assert_cmpint(fe.read_count, ==, 8);
610 g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
611
612 qemu_chr_fe_deinit(&be, true);
613
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);
620 }
621 #endif
622
623 static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
624 {
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;
634
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);
644 }
645 ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
646 g_assert_cmpint(ret, ==, 6);
647
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);
652
653 if (!ext_chr) {
654 object_unref(OBJECT(chr));
655 g_unlink(out);
656 }
657 g_free(contents);
658 g_rmdir(tmp_path);
659 g_free(tmp_path);
660 g_free(out);
661 }
662
663 static void char_file_test(void)
664 {
665 char_file_test_internal(NULL, NULL);
666 }
667
668 static void char_null_test(void)
669 {
670 Error *err = NULL;
671 Chardev *chr;
672 CharBackend be;
673 int ret;
674
675 chr = qemu_chr_find("label-null");
676 g_assert_null(chr);
677
678 chr = qemu_chr_new("label-null", "null");
679 chr = qemu_chr_find("label-null");
680 g_assert_nonnull(chr);
681
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);
686
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);
691
692 /* deinit & reinit */
693 qemu_chr_fe_deinit(&be, false);
694 qemu_chr_fe_init(&be, chr, &error_abort);
695
696 qemu_chr_fe_set_open(&be, true);
697
698 qemu_chr_fe_set_handlers(&be,
699 fe_can_read,
700 fe_read,
701 fe_event,
702 NULL,
703 NULL, NULL, true);
704
705 ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
706 g_assert_cmpint(ret, ==, 4);
707
708 qemu_chr_fe_deinit(&be, true);
709 }
710
711 static void char_invalid_test(void)
712 {
713 Chardev *chr;
714
715 chr = qemu_chr_new("label-invalid", "invalid");
716 g_assert_null(chr);
717 }
718
719 static int chardev_change(void *opaque)
720 {
721 return 0;
722 }
723
724 static int chardev_change_denied(void *opaque)
725 {
726 return -1;
727 }
728
729 static void char_hotswap_test(void)
730 {
731 char *chr_args;
732 Chardev *chr;
733 CharBackend be;
734
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;
741
742 int port;
743 int sock = make_udp_socket(&port);
744 g_assert_cmpint(sock, >, 0);
745
746 chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
747
748 chr = qemu_chr_new("chardev", chr_args);
749 qemu_chr_fe_init(&be, chr, &error_abort);
750
751 /* check that chardev operates correctly */
752 char_udp_test_internal(chr, sock);
753
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);
757
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);
762
763 char_udp_test_internal(chr, sock);
764
765 /* now allow the change */
766 qemu_chr_fe_set_handlers(&be, NULL, NULL,
767 NULL, chardev_change, NULL, NULL, true);
768
769 /* has to succeed now */
770 ret = qmp_chardev_change("chardev", &backend, &error_abort);
771 g_assert(be.chr != chr);
772
773 close(sock);
774 chr = be.chr;
775
776 /* run the file chardev test */
777 char_file_test_internal(chr, filename);
778
779 object_unparent(OBJECT(chr));
780
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);
787 }
788
789 int main(int argc, char **argv)
790 {
791 qemu_init_main_loop(&error_abort);
792 socket_init();
793
794 g_test_init(&argc, &argv, NULL);
795
796 module_call_init(MODULE_INIT_QOM);
797 qemu_add_opts(&qemu_chardev_opts);
798
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);
825
826 return g_test_run();
827 }