chardev: split tcp_chr_wait_connected into two methods
[qemu/ar7.git] / tests / test-char.c
blob45203f5d7a43f74b47ade47aea66651c2adc7691
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 bool is_open;
20 int openclose_count;
21 bool openclose_mismatch;
22 int last_event;
23 char read_buf[128];
24 } FeHandler;
26 static void main_loop(void)
28 quit = false;
29 do {
30 main_loop_wait(false);
31 } while (!quit);
34 static int fe_can_read(void *opaque)
36 FeHandler *h = opaque;
38 return sizeof(h->read_buf) - h->read_count;
41 static void fe_read(void *opaque, const uint8_t *buf, int size)
43 FeHandler *h = opaque;
45 g_assert_cmpint(size, <=, fe_can_read(opaque));
47 memcpy(h->read_buf + h->read_count, buf, size);
48 h->read_count += size;
49 quit = true;
52 static void fe_event(void *opaque, int event)
54 FeHandler *h = opaque;
55 bool new_open_state;
57 h->last_event = event;
58 switch (event) {
59 case CHR_EVENT_BREAK:
60 break;
61 case CHR_EVENT_OPENED:
62 case CHR_EVENT_CLOSED:
63 h->openclose_count++;
64 new_open_state = (event == CHR_EVENT_OPENED);
65 if (h->is_open == new_open_state) {
66 h->openclose_mismatch = true;
68 h->is_open = new_open_state;
69 /* no break */
70 default:
71 quit = true;
72 break;
76 #ifdef _WIN32
77 static void char_console_test_subprocess(void)
79 QemuOpts *opts;
80 Chardev *chr;
82 opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
83 1, &error_abort);
84 qemu_opt_set(opts, "backend", "console", &error_abort);
86 chr = qemu_chr_new_from_opts(opts, NULL);
87 g_assert_nonnull(chr);
89 qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
91 qemu_opts_del(opts);
92 object_unparent(OBJECT(chr));
95 static void char_console_test(void)
97 g_test_trap_subprocess("/char/console/subprocess", 0, 0);
98 g_test_trap_assert_passed();
99 g_test_trap_assert_stdout("CONSOLE");
101 #endif
102 static void char_stdio_test_subprocess(void)
104 Chardev *chr;
105 CharBackend be;
106 int ret;
108 chr = qemu_chr_new("label", "stdio");
109 g_assert_nonnull(chr);
111 qemu_chr_fe_init(&be, chr, &error_abort);
112 qemu_chr_fe_set_open(&be, true);
113 ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
114 g_assert_cmpint(ret, ==, 4);
116 qemu_chr_fe_deinit(&be, true);
119 static void char_stdio_test(void)
121 g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
122 g_test_trap_assert_passed();
123 g_test_trap_assert_stdout("buf");
126 static void char_ringbuf_test(void)
128 QemuOpts *opts;
129 Chardev *chr;
130 CharBackend be;
131 char *data;
132 int ret;
134 opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
135 1, &error_abort);
136 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
138 qemu_opt_set(opts, "size", "5", &error_abort);
139 chr = qemu_chr_new_from_opts(opts, NULL);
140 g_assert_null(chr);
141 qemu_opts_del(opts);
143 opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
144 1, &error_abort);
145 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
146 qemu_opt_set(opts, "size", "2", &error_abort);
147 chr = qemu_chr_new_from_opts(opts, &error_abort);
148 g_assert_nonnull(chr);
149 qemu_opts_del(opts);
151 qemu_chr_fe_init(&be, chr, &error_abort);
152 ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
153 g_assert_cmpint(ret, ==, 4);
155 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
156 g_assert_cmpstr(data, ==, "ff");
157 g_free(data);
159 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
160 g_assert_cmpstr(data, ==, "");
161 g_free(data);
163 qemu_chr_fe_deinit(&be, true);
165 /* check alias */
166 opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
167 1, &error_abort);
168 qemu_opt_set(opts, "backend", "memory", &error_abort);
169 qemu_opt_set(opts, "size", "2", &error_abort);
170 chr = qemu_chr_new_from_opts(opts, NULL);
171 g_assert_nonnull(chr);
172 object_unparent(OBJECT(chr));
173 qemu_opts_del(opts);
176 static void char_mux_test(void)
178 QemuOpts *opts;
179 Chardev *chr, *base;
180 char *data;
181 FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
182 CharBackend chr_be1, chr_be2;
184 opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
185 1, &error_abort);
186 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
187 qemu_opt_set(opts, "size", "128", &error_abort);
188 qemu_opt_set(opts, "mux", "on", &error_abort);
189 chr = qemu_chr_new_from_opts(opts, &error_abort);
190 g_assert_nonnull(chr);
191 qemu_opts_del(opts);
193 qemu_chr_fe_init(&chr_be1, chr, &error_abort);
194 qemu_chr_fe_set_handlers(&chr_be1,
195 fe_can_read,
196 fe_read,
197 fe_event,
198 NULL,
199 &h1,
200 NULL, true);
202 qemu_chr_fe_init(&chr_be2, chr, &error_abort);
203 qemu_chr_fe_set_handlers(&chr_be2,
204 fe_can_read,
205 fe_read,
206 fe_event,
207 NULL,
208 &h2,
209 NULL, true);
210 qemu_chr_fe_take_focus(&chr_be2);
212 base = qemu_chr_find("mux-label-base");
213 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
215 qemu_chr_be_write(base, (void *)"hello", 6);
216 g_assert_cmpint(h1.read_count, ==, 0);
217 g_assert_cmpint(h2.read_count, ==, 6);
218 g_assert_cmpstr(h2.read_buf, ==, "hello");
219 h2.read_count = 0;
221 g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */
222 g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */
223 /* sending event on the base broadcast to all fe, historical reasons? */
224 qemu_chr_be_event(base, 42);
225 g_assert_cmpint(h1.last_event, ==, 42);
226 g_assert_cmpint(h2.last_event, ==, 42);
227 qemu_chr_be_event(chr, -1);
228 g_assert_cmpint(h1.last_event, ==, 42);
229 g_assert_cmpint(h2.last_event, ==, -1);
231 /* switch focus */
232 qemu_chr_be_write(base, (void *)"\1b", 2);
233 g_assert_cmpint(h1.last_event, ==, 42);
234 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK);
236 qemu_chr_be_write(base, (void *)"\1c", 2);
237 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
238 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
239 qemu_chr_be_event(chr, -1);
240 g_assert_cmpint(h1.last_event, ==, -1);
241 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
243 qemu_chr_be_write(base, (void *)"hello", 6);
244 g_assert_cmpint(h2.read_count, ==, 0);
245 g_assert_cmpint(h1.read_count, ==, 6);
246 g_assert_cmpstr(h1.read_buf, ==, "hello");
247 h1.read_count = 0;
249 qemu_chr_be_write(base, (void *)"\1b", 2);
250 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK);
251 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
253 /* open/close state and corresponding events */
254 g_assert_true(qemu_chr_fe_backend_open(&chr_be1));
255 g_assert_true(qemu_chr_fe_backend_open(&chr_be2));
256 g_assert_true(h1.is_open);
257 g_assert_false(h1.openclose_mismatch);
258 g_assert_true(h2.is_open);
259 g_assert_false(h2.openclose_mismatch);
261 h1.openclose_count = h2.openclose_count = 0;
263 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
264 NULL, NULL, false);
265 qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, NULL, NULL,
266 NULL, NULL, false);
267 g_assert_cmpint(h1.openclose_count, ==, 0);
268 g_assert_cmpint(h2.openclose_count, ==, 0);
270 h1.is_open = h2.is_open = false;
271 qemu_chr_fe_set_handlers(&chr_be1,
272 NULL,
273 NULL,
274 fe_event,
275 NULL,
276 &h1,
277 NULL, false);
278 qemu_chr_fe_set_handlers(&chr_be2,
279 NULL,
280 NULL,
281 fe_event,
282 NULL,
283 &h2,
284 NULL, false);
285 g_assert_cmpint(h1.openclose_count, ==, 1);
286 g_assert_false(h1.openclose_mismatch);
287 g_assert_cmpint(h2.openclose_count, ==, 1);
288 g_assert_false(h2.openclose_mismatch);
290 qemu_chr_be_event(base, CHR_EVENT_CLOSED);
291 qemu_chr_be_event(base, CHR_EVENT_OPENED);
292 g_assert_cmpint(h1.openclose_count, ==, 3);
293 g_assert_false(h1.openclose_mismatch);
294 g_assert_cmpint(h2.openclose_count, ==, 3);
295 g_assert_false(h2.openclose_mismatch);
297 qemu_chr_fe_set_handlers(&chr_be2,
298 fe_can_read,
299 fe_read,
300 fe_event,
301 NULL,
302 &h2,
303 NULL, false);
304 qemu_chr_fe_set_handlers(&chr_be1,
305 fe_can_read,
306 fe_read,
307 fe_event,
308 NULL,
309 &h1,
310 NULL, false);
312 /* remove first handler */
313 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
314 NULL, NULL, true);
315 qemu_chr_be_write(base, (void *)"hello", 6);
316 g_assert_cmpint(h1.read_count, ==, 0);
317 g_assert_cmpint(h2.read_count, ==, 0);
319 qemu_chr_be_write(base, (void *)"\1c", 2);
320 qemu_chr_be_write(base, (void *)"hello", 6);
321 g_assert_cmpint(h1.read_count, ==, 0);
322 g_assert_cmpint(h2.read_count, ==, 6);
323 g_assert_cmpstr(h2.read_buf, ==, "hello");
324 h2.read_count = 0;
326 /* print help */
327 qemu_chr_be_write(base, (void *)"\1?", 2);
328 data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
329 g_assert_cmpint(strlen(data), !=, 0);
330 g_free(data);
332 qemu_chr_fe_deinit(&chr_be1, false);
333 qemu_chr_fe_deinit(&chr_be2, true);
336 typedef struct SocketIdleData {
337 GMainLoop *loop;
338 Chardev *chr;
339 bool conn_expected;
340 CharBackend *be;
341 CharBackend *client_be;
342 } SocketIdleData;
344 static gboolean char_socket_test_idle(gpointer user_data)
346 SocketIdleData *data = user_data;
348 if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
349 == data->conn_expected) {
350 quit = true;
351 return FALSE;
354 return TRUE;
357 static void socket_read(void *opaque, const uint8_t *buf, int size)
359 SocketIdleData *data = opaque;
361 g_assert_cmpint(size, ==, 1);
362 g_assert_cmpint(*buf, ==, 'Z');
364 size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
365 g_assert_cmpint(size, ==, 5);
368 static int socket_can_read(void *opaque)
370 return 10;
373 static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
375 g_assert_cmpint(size, ==, 5);
376 g_assert(strncmp((char *)buf, "hello", 5) == 0);
378 quit = true;
381 static int socket_can_read_hello(void *opaque)
383 return 10;
386 static void char_socket_test_common(Chardev *chr, bool reconnect)
388 Chardev *chr_client;
389 QObject *addr;
390 QDict *qdict;
391 const char *port;
392 SocketIdleData d = { .chr = chr };
393 CharBackend be;
394 CharBackend client_be;
395 char *tmp;
397 d.be = &be;
398 d.client_be = &be;
400 g_assert_nonnull(chr);
401 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
403 addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
404 qdict = qobject_to(QDict, addr);
405 port = qdict_get_str(qdict, "port");
406 tmp = g_strdup_printf("tcp:127.0.0.1:%s%s", port,
407 reconnect ? ",reconnect=1" : "");
408 qobject_unref(qdict);
410 qemu_chr_fe_init(&be, chr, &error_abort);
411 qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
412 NULL, NULL, &d, NULL, true);
414 chr_client = qemu_chr_new("client", tmp);
415 qemu_chr_fe_init(&client_be, chr_client, &error_abort);
416 qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
417 socket_read_hello,
418 NULL, NULL, &d, NULL, true);
419 g_free(tmp);
421 d.conn_expected = true;
422 guint id = g_idle_add(char_socket_test_idle, &d);
423 g_source_set_name_by_id(id, "test-idle");
424 g_assert_cmpint(id, >, 0);
425 main_loop();
427 d.chr = chr_client;
428 id = g_idle_add(char_socket_test_idle, &d);
429 g_source_set_name_by_id(id, "test-idle");
430 g_assert_cmpint(id, >, 0);
431 main_loop();
433 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
434 g_assert(object_property_get_bool(OBJECT(chr_client),
435 "connected", &error_abort));
437 qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
438 main_loop();
440 object_unparent(OBJECT(chr_client));
442 d.chr = chr;
443 d.conn_expected = false;
444 g_idle_add(char_socket_test_idle, &d);
445 main_loop();
447 object_unparent(OBJECT(chr));
451 static void char_socket_basic_test(void)
453 Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
455 char_socket_test_common(chr, false);
459 static void char_socket_reconnect_test(void)
461 Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
463 char_socket_test_common(chr, true);
467 static void char_socket_fdpass_test(void)
469 Chardev *chr;
470 char *optstr;
471 QemuOpts *opts;
472 int fd;
473 SocketAddress *addr = g_new0(SocketAddress, 1);
475 addr->type = SOCKET_ADDRESS_TYPE_INET;
476 addr->u.inet.host = g_strdup("127.0.0.1");
477 addr->u.inet.port = g_strdup("0");
479 fd = socket_listen(addr, &error_abort);
480 g_assert(fd >= 0);
482 qapi_free_SocketAddress(addr);
484 optstr = g_strdup_printf("socket,id=cdev,fd=%d,server,nowait", fd);
486 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
487 optstr, true);
488 g_free(optstr);
489 g_assert_nonnull(opts);
491 chr = qemu_chr_new_from_opts(opts, &error_abort);
493 qemu_opts_del(opts);
495 char_socket_test_common(chr, false);
499 static void websock_server_read(void *opaque, const uint8_t *buf, int size)
501 g_assert_cmpint(size, ==, 5);
502 g_assert(memcmp(buf, "world", size) == 0);
503 quit = true;
507 static int websock_server_can_read(void *opaque)
509 return 10;
513 static bool websock_check_http_headers(char *buf, int size)
515 int i;
516 const char *ans[] = { "HTTP/1.1 101 Switching Protocols\r\n",
517 "Server: QEMU VNC\r\n",
518 "Upgrade: websocket\r\n",
519 "Connection: Upgrade\r\n",
520 "Sec-WebSocket-Accept:",
521 "Sec-WebSocket-Protocol: binary\r\n" };
523 for (i = 0; i < 6; i++) {
524 if (g_strstr_len(buf, size, ans[i]) == NULL) {
525 return false;
529 return true;
533 static void websock_client_read(void *opaque, const uint8_t *buf, int size)
535 const uint8_t ping[] = { 0x89, 0x85, /* Ping header */
536 0x07, 0x77, 0x9e, 0xf9, /* Masking key */
537 0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ };
539 const uint8_t binary[] = { 0x82, 0x85, /* Binary header */
540 0x74, 0x90, 0xb9, 0xdf, /* Masking key */
541 0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ };
542 Chardev *chr_client = opaque;
544 if (websock_check_http_headers((char *) buf, size)) {
545 qemu_chr_fe_write(chr_client->be, ping, sizeof(ping));
546 } else if (buf[0] == 0x8a && buf[1] == 0x05) {
547 g_assert(strncmp((char *) buf + 2, "hello", 5) == 0);
548 qemu_chr_fe_write(chr_client->be, binary, sizeof(binary));
549 } else {
550 g_assert(buf[0] == 0x88 && buf[1] == 0x16);
551 g_assert(strncmp((char *) buf + 4, "peer requested close", 10) == 0);
552 quit = true;
557 static int websock_client_can_read(void *opaque)
559 return 4096;
563 static void char_websock_test(void)
565 QObject *addr;
566 QDict *qdict;
567 const char *port;
568 char *tmp;
569 char *handshake_port;
570 CharBackend be;
571 CharBackend client_be;
572 Chardev *chr_client;
573 Chardev *chr = qemu_chr_new("server",
574 "websocket:127.0.0.1:0,server,nowait");
575 const char handshake[] = "GET / HTTP/1.1\r\n"
576 "Upgrade: websocket\r\n"
577 "Connection: Upgrade\r\n"
578 "Host: localhost:%s\r\n"
579 "Origin: http://localhost:%s\r\n"
580 "Sec-WebSocket-Key: o9JHNiS3/0/0zYE1wa3yIw==\r\n"
581 "Sec-WebSocket-Version: 13\r\n"
582 "Sec-WebSocket-Protocol: binary\r\n\r\n";
583 const uint8_t close[] = { 0x88, 0x82, /* Close header */
584 0xef, 0xaa, 0xc5, 0x97, /* Masking key */
585 0xec, 0x42 /* Status code */ };
587 addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
588 qdict = qobject_to(QDict, addr);
589 port = qdict_get_str(qdict, "port");
590 tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
591 handshake_port = g_strdup_printf(handshake, port, port);
592 qobject_unref(qdict);
594 qemu_chr_fe_init(&be, chr, &error_abort);
595 qemu_chr_fe_set_handlers(&be, websock_server_can_read, websock_server_read,
596 NULL, NULL, chr, NULL, true);
598 chr_client = qemu_chr_new("client", tmp);
599 qemu_chr_fe_init(&client_be, chr_client, &error_abort);
600 qemu_chr_fe_set_handlers(&client_be, websock_client_can_read,
601 websock_client_read,
602 NULL, NULL, chr_client, NULL, true);
603 g_free(tmp);
605 qemu_chr_write_all(chr_client,
606 (uint8_t *) handshake_port,
607 strlen(handshake_port));
608 g_free(handshake_port);
609 main_loop();
611 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
612 g_assert(object_property_get_bool(OBJECT(chr_client),
613 "connected", &error_abort));
615 qemu_chr_write_all(chr_client, close, sizeof(close));
616 main_loop();
618 object_unparent(OBJECT(chr_client));
619 object_unparent(OBJECT(chr));
623 #ifndef _WIN32
624 static void char_pipe_test(void)
626 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
627 gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
628 Chardev *chr;
629 CharBackend be;
630 int ret, fd;
631 char buf[10];
632 FeHandler fe = { 0, };
634 in = g_strdup_printf("%s.in", pipe);
635 if (mkfifo(in, 0600) < 0) {
636 abort();
638 out = g_strdup_printf("%s.out", pipe);
639 if (mkfifo(out, 0600) < 0) {
640 abort();
643 tmp = g_strdup_printf("pipe:%s", pipe);
644 chr = qemu_chr_new("pipe", tmp);
645 g_assert_nonnull(chr);
646 g_free(tmp);
648 qemu_chr_fe_init(&be, chr, &error_abort);
650 ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
651 g_assert_cmpint(ret, ==, 9);
653 fd = open(out, O_RDWR);
654 ret = read(fd, buf, sizeof(buf));
655 g_assert_cmpint(ret, ==, 9);
656 g_assert_cmpstr(buf, ==, "pipe-out");
657 close(fd);
659 fd = open(in, O_WRONLY);
660 ret = write(fd, "pipe-in", 8);
661 g_assert_cmpint(ret, ==, 8);
662 close(fd);
664 qemu_chr_fe_set_handlers(&be,
665 fe_can_read,
666 fe_read,
667 fe_event,
668 NULL,
669 &fe,
670 NULL, true);
672 main_loop();
674 g_assert_cmpint(fe.read_count, ==, 8);
675 g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
677 qemu_chr_fe_deinit(&be, true);
679 g_assert(g_unlink(in) == 0);
680 g_assert(g_unlink(out) == 0);
681 g_assert(g_rmdir(tmp_path) == 0);
682 g_free(in);
683 g_free(out);
684 g_free(tmp_path);
685 g_free(pipe);
687 #endif
689 static int make_udp_socket(int *port)
691 struct sockaddr_in addr = { 0, };
692 socklen_t alen = sizeof(addr);
693 int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
695 g_assert_cmpint(sock, >, 0);
696 addr.sin_family = AF_INET ;
697 addr.sin_addr.s_addr = htonl(INADDR_ANY);
698 addr.sin_port = 0;
699 ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
700 g_assert_cmpint(ret, ==, 0);
701 ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
702 g_assert_cmpint(ret, ==, 0);
704 *port = ntohs(addr.sin_port);
705 return sock;
708 static void char_udp_test_internal(Chardev *reuse_chr, int sock)
710 struct sockaddr_in other;
711 SocketIdleData d = { 0, };
712 Chardev *chr;
713 CharBackend *be;
714 socklen_t alen = sizeof(other);
715 int ret;
716 char buf[10];
717 char *tmp = NULL;
719 if (reuse_chr) {
720 chr = reuse_chr;
721 be = chr->be;
722 } else {
723 int port;
724 sock = make_udp_socket(&port);
725 tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
726 chr = qemu_chr_new("client", tmp);
727 g_assert_nonnull(chr);
729 be = g_alloca(sizeof(CharBackend));
730 qemu_chr_fe_init(be, chr, &error_abort);
733 d.chr = chr;
734 qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
735 NULL, NULL, &d, NULL, true);
736 ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
737 g_assert_cmpint(ret, ==, 5);
739 ret = recvfrom(sock, buf, sizeof(buf), 0,
740 (struct sockaddr *)&other, &alen);
741 g_assert_cmpint(ret, ==, 5);
742 ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
743 g_assert_cmpint(ret, ==, 5);
745 main_loop();
747 if (!reuse_chr) {
748 close(sock);
749 qemu_chr_fe_deinit(be, true);
751 g_free(tmp);
754 static void char_udp_test(void)
756 char_udp_test_internal(NULL, 0);
759 #ifdef HAVE_CHARDEV_SERIAL
760 static void char_serial_test(void)
762 QemuOpts *opts;
763 Chardev *chr;
765 opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
766 1, &error_abort);
767 qemu_opt_set(opts, "backend", "serial", &error_abort);
768 qemu_opt_set(opts, "path", "/dev/null", &error_abort);
770 chr = qemu_chr_new_from_opts(opts, NULL);
771 g_assert_nonnull(chr);
772 /* TODO: add more tests with a pty */
773 object_unparent(OBJECT(chr));
775 /* test tty alias */
776 qemu_opt_set(opts, "backend", "tty", &error_abort);
777 chr = qemu_chr_new_from_opts(opts, NULL);
778 g_assert_nonnull(chr);
779 object_unparent(OBJECT(chr));
781 qemu_opts_del(opts);
783 #endif
785 #ifndef _WIN32
786 static void char_file_fifo_test(void)
788 Chardev *chr;
789 CharBackend be;
790 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
791 char *fifo = g_build_filename(tmp_path, "fifo", NULL);
792 char *out = g_build_filename(tmp_path, "out", NULL);
793 ChardevFile file = { .in = fifo,
794 .has_in = true,
795 .out = out };
796 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
797 .u.file.data = &file };
798 FeHandler fe = { 0, };
799 int fd, ret;
801 if (mkfifo(fifo, 0600) < 0) {
802 abort();
805 fd = open(fifo, O_RDWR);
806 ret = write(fd, "fifo-in", 8);
807 g_assert_cmpint(ret, ==, 8);
809 chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
810 &error_abort);
812 qemu_chr_fe_init(&be, chr, &error_abort);
813 qemu_chr_fe_set_handlers(&be,
814 fe_can_read,
815 fe_read,
816 fe_event,
817 NULL,
818 &fe, NULL, true);
820 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
821 qmp_chardev_send_break("label-foo", NULL);
822 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
823 qmp_chardev_send_break("label-file", NULL);
824 g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
826 main_loop();
828 close(fd);
830 g_assert_cmpint(fe.read_count, ==, 8);
831 g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
833 qemu_chr_fe_deinit(&be, true);
835 g_unlink(fifo);
836 g_free(fifo);
837 g_unlink(out);
838 g_free(out);
839 g_rmdir(tmp_path);
840 g_free(tmp_path);
842 #endif
844 static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
846 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
847 char *out;
848 Chardev *chr;
849 char *contents = NULL;
850 ChardevFile file = {};
851 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
852 .u.file.data = &file };
853 gsize length;
854 int ret;
856 if (ext_chr) {
857 chr = ext_chr;
858 out = g_strdup(filepath);
859 file.out = out;
860 } else {
861 out = g_build_filename(tmp_path, "out", NULL);
862 file.out = out;
863 chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
864 &error_abort);
866 ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
867 g_assert_cmpint(ret, ==, 6);
869 ret = g_file_get_contents(out, &contents, &length, NULL);
870 g_assert(ret == TRUE);
871 g_assert_cmpint(length, ==, 6);
872 g_assert(strncmp(contents, "hello!", 6) == 0);
874 if (!ext_chr) {
875 object_unref(OBJECT(chr));
876 g_unlink(out);
878 g_free(contents);
879 g_rmdir(tmp_path);
880 g_free(tmp_path);
881 g_free(out);
884 static void char_file_test(void)
886 char_file_test_internal(NULL, NULL);
889 static void char_null_test(void)
891 Error *err = NULL;
892 Chardev *chr;
893 CharBackend be;
894 int ret;
896 chr = qemu_chr_find("label-null");
897 g_assert_null(chr);
899 chr = qemu_chr_new("label-null", "null");
900 chr = qemu_chr_find("label-null");
901 g_assert_nonnull(chr);
903 g_assert(qemu_chr_has_feature(chr,
904 QEMU_CHAR_FEATURE_FD_PASS) == false);
905 g_assert(qemu_chr_has_feature(chr,
906 QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
908 /* check max avail */
909 qemu_chr_fe_init(&be, chr, &error_abort);
910 qemu_chr_fe_init(&be, chr, &err);
911 error_free_or_abort(&err);
913 /* deinit & reinit */
914 qemu_chr_fe_deinit(&be, false);
915 qemu_chr_fe_init(&be, chr, &error_abort);
917 qemu_chr_fe_set_open(&be, true);
919 qemu_chr_fe_set_handlers(&be,
920 fe_can_read,
921 fe_read,
922 fe_event,
923 NULL,
924 NULL, NULL, true);
926 ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
927 g_assert_cmpint(ret, ==, 4);
929 qemu_chr_fe_deinit(&be, true);
932 static void char_invalid_test(void)
934 Chardev *chr;
935 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
936 chr = qemu_chr_new("label-invalid", "invalid");
937 g_assert_null(chr);
938 g_unsetenv("QTEST_SILENT_ERRORS");
941 static int chardev_change(void *opaque)
943 return 0;
946 static int chardev_change_denied(void *opaque)
948 return -1;
951 static void char_hotswap_test(void)
953 char *chr_args;
954 Chardev *chr;
955 CharBackend be;
957 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
958 char *filename = g_build_filename(tmp_path, "file", NULL);
959 ChardevFile file = { .out = filename };
960 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
961 .u.file.data = &file };
962 ChardevReturn *ret;
964 int port;
965 int sock = make_udp_socket(&port);
966 g_assert_cmpint(sock, >, 0);
968 chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
970 chr = qemu_chr_new("chardev", chr_args);
971 qemu_chr_fe_init(&be, chr, &error_abort);
973 /* check that chardev operates correctly */
974 char_udp_test_internal(chr, sock);
976 /* set the handler that denies the hotswap */
977 qemu_chr_fe_set_handlers(&be, NULL, NULL,
978 NULL, chardev_change_denied, NULL, NULL, true);
980 /* now, change is denied and has to keep the old backend operating */
981 ret = qmp_chardev_change("chardev", &backend, NULL);
982 g_assert(!ret);
983 g_assert(be.chr == chr);
985 char_udp_test_internal(chr, sock);
987 /* now allow the change */
988 qemu_chr_fe_set_handlers(&be, NULL, NULL,
989 NULL, chardev_change, NULL, NULL, true);
991 /* has to succeed now */
992 ret = qmp_chardev_change("chardev", &backend, &error_abort);
993 g_assert(be.chr != chr);
995 close(sock);
996 chr = be.chr;
998 /* run the file chardev test */
999 char_file_test_internal(chr, filename);
1001 object_unparent(OBJECT(chr));
1003 qapi_free_ChardevReturn(ret);
1004 g_unlink(filename);
1005 g_free(filename);
1006 g_rmdir(tmp_path);
1007 g_free(tmp_path);
1008 g_free(chr_args);
1011 int main(int argc, char **argv)
1013 qemu_init_main_loop(&error_abort);
1014 socket_init();
1016 g_test_init(&argc, &argv, NULL);
1018 module_call_init(MODULE_INIT_QOM);
1019 qemu_add_opts(&qemu_chardev_opts);
1021 g_test_add_func("/char/null", char_null_test);
1022 g_test_add_func("/char/invalid", char_invalid_test);
1023 g_test_add_func("/char/ringbuf", char_ringbuf_test);
1024 g_test_add_func("/char/mux", char_mux_test);
1025 #ifdef _WIN32
1026 g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
1027 g_test_add_func("/char/console", char_console_test);
1028 #endif
1029 g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
1030 g_test_add_func("/char/stdio", char_stdio_test);
1031 #ifndef _WIN32
1032 g_test_add_func("/char/pipe", char_pipe_test);
1033 #endif
1034 g_test_add_func("/char/file", char_file_test);
1035 #ifndef _WIN32
1036 g_test_add_func("/char/file-fifo", char_file_fifo_test);
1037 #endif
1038 g_test_add_func("/char/socket/basic", char_socket_basic_test);
1039 g_test_add_func("/char/socket/reconnect", char_socket_reconnect_test);
1040 g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test);
1041 g_test_add_func("/char/udp", char_udp_test);
1042 #ifdef HAVE_CHARDEV_SERIAL
1043 g_test_add_func("/char/serial", char_serial_test);
1044 #endif
1045 g_test_add_func("/char/hotswap", char_hotswap_test);
1046 g_test_add_func("/char/websocket", char_websock_test);
1048 return g_test_run();