1 #include "qemu/osdep.h"
2 #include <glib/gstdio.h>
3
4 #include "qapi/error.h"
5 #include "qemu/config-file.h"
6 #include "qemu/module.h"
7 #include "qemu/option.h"
8 #include "qemu/sockets.h"
9 #include "chardev/char-fe.h"
10 #include "system/system.h"
11 #include "qapi/error.h"
12 #include "qapi/qapi-commands-char.h"
13 #include "qobject/qdict.h"
14 #include "qom/qom-qobject.h"
15 #include "io/channel-socket.h"
16 #include "qapi/qobject-input-visitor.h"
17 #include "qapi/qapi-visit-sockets.h"
18 #include "socket-helpers.h"
19
20 static bool quit;
21
22 typedef struct FeHandler {
23 int read_count;
24 bool is_open;
25 int openclose_count;
26 bool openclose_mismatch;
27 int last_event;
28 char read_buf[128];
29 } FeHandler;
30
main_loop(void)31 static void main_loop(void)
32 {
33 quit = false;
34 do {
35 main_loop_wait(false);
36 } while (!quit);
37 }
38
fe_can_read(void * opaque)39 static int fe_can_read(void *opaque)
40 {
41 FeHandler *h = opaque;
42
43 return sizeof(h->read_buf) - h->read_count;
44 }
45
fe_read(void * opaque,const uint8_t * buf,int size)46 static void fe_read(void *opaque, const uint8_t *buf, int size)
47 {
48 FeHandler *h = opaque;
49
50 g_assert_cmpint(size, <=, fe_can_read(opaque));
51
52 memcpy(h->read_buf + h->read_count, buf, size);
53 h->read_count += size;
54 quit = true;
55 }
56
fe_event(void * opaque,QEMUChrEvent event)57 static void fe_event(void *opaque, QEMUChrEvent event)
58 {
59 FeHandler *h = opaque;
60 bool new_open_state;
61
62 h->last_event = event;
63 switch (event) {
64 case CHR_EVENT_BREAK:
65 break;
66 case CHR_EVENT_OPENED:
67 case CHR_EVENT_CLOSED:
68 h->openclose_count++;
69 new_open_state = (event == CHR_EVENT_OPENED);
70 if (h->is_open == new_open_state) {
71 h->openclose_mismatch = true;
72 }
73 h->is_open = new_open_state;
74 /* fallthrough */
75 default:
76 quit = true;
77 break;
78 }
79 }
80
81 #ifdef _WIN32
char_console_test_subprocess(void)82 static void char_console_test_subprocess(void)
83 {
84 QemuOpts *opts;
85 Chardev *chr;
86
87 opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
88 1, &error_abort);
89 qemu_opt_set(opts, "backend", "console", &error_abort);
90
91 chr = qemu_chr_new_from_opts(opts, NULL, NULL);
92 g_assert_nonnull(chr);
93
94 qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
95
96 qemu_opts_del(opts);
97 object_unparent(OBJECT(chr));
98 }
99
char_console_test(void)100 static void char_console_test(void)
101 {
102 g_test_trap_subprocess("/char/console/subprocess", 0, 0);
103 g_test_trap_assert_passed();
104 g_test_trap_assert_stdout("CONSOLE");
105 }
106 #endif
char_stdio_test_subprocess(void)107 static void char_stdio_test_subprocess(void)
108 {
109 Chardev *chr;
110 CharBackend be;
111 int ret;
112
113 chr = qemu_chr_new("label", "stdio", NULL);
114 g_assert_nonnull(chr);
115
116 qemu_chr_fe_init(&be, chr, &error_abort);
117 qemu_chr_fe_set_open(&be, true);
118 ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
119 g_assert_cmpint(ret, ==, 4);
120
121 qemu_chr_fe_deinit(&be, true);
122 }
123
char_stdio_test(void)124 static void char_stdio_test(void)
125 {
126 g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
127 g_test_trap_assert_passed();
128 g_test_trap_assert_stdout("buf");
129 }
130
char_ringbuf_test(void)131 static void char_ringbuf_test(void)
132 {
133 QemuOpts *opts;
134 Chardev *chr;
135 CharBackend be;
136 char *data;
137 int ret;
138
139 opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
140 1, &error_abort);
141 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
142
143 qemu_opt_set(opts, "size", "5", &error_abort);
144 chr = qemu_chr_new_from_opts(opts, NULL, NULL);
145 g_assert_null(chr);
146 qemu_opts_del(opts);
147
148 opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
149 1, &error_abort);
150 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
151 qemu_opt_set(opts, "size", "2", &error_abort);
152 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
153 g_assert_nonnull(chr);
154 qemu_opts_del(opts);
155
156 qemu_chr_fe_init(&be, chr, &error_abort);
157 ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
158 g_assert_cmpint(ret, ==, 4);
159
160 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
161 g_assert_cmpstr(data, ==, "ff");
162 g_free(data);
163
164 data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
165 g_assert_cmpstr(data, ==, "");
166 g_free(data);
167
168 qemu_chr_fe_deinit(&be, true);
169
170 /* check alias */
171 opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
172 1, &error_abort);
173 qemu_opt_set(opts, "backend", "memory", &error_abort);
174 qemu_opt_set(opts, "size", "2", &error_abort);
175 chr = qemu_chr_new_from_opts(opts, NULL, NULL);
176 g_assert_nonnull(chr);
177 object_unparent(OBJECT(chr));
178 qemu_opts_del(opts);
179 }
180
char_mux_test(void)181 static void char_mux_test(void)
182 {
183 QemuOpts *opts;
184 Chardev *chr, *base;
185 char *data;
186 FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
187 CharBackend chr_be1, chr_be2;
188 Error *error = NULL;
189
190 /* Create mux and chardev to be immediately removed */
191 opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
192 1, &error_abort);
193 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
194 qemu_opt_set(opts, "size", "128", &error_abort);
195 qemu_opt_set(opts, "mux", "on", &error_abort);
196 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
197 g_assert_nonnull(chr);
198 qemu_opts_del(opts);
199
200 /* Remove just created mux and chardev */
201 qmp_chardev_remove("mux-label", &error_abort);
202 qmp_chardev_remove("mux-label-base", &error_abort);
203
204 opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
205 1, &error_abort);
206 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
207 qemu_opt_set(opts, "size", "128", &error_abort);
208 qemu_opt_set(opts, "mux", "on", &error_abort);
209 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
210 g_assert_nonnull(chr);
211 qemu_opts_del(opts);
212
213 qemu_chr_fe_init(&chr_be1, chr, &error_abort);
214 qemu_chr_fe_set_handlers(&chr_be1,
215 fe_can_read,
216 fe_read,
217 fe_event,
218 NULL,
219 &h1,
220 NULL, true);
221
222 qemu_chr_fe_init(&chr_be2, chr, &error_abort);
223 qemu_chr_fe_set_handlers(&chr_be2,
224 fe_can_read,
225 fe_read,
226 fe_event,
227 NULL,
228 &h2,
229 NULL, true);
230 qemu_chr_fe_take_focus(&chr_be2);
231
232 base = qemu_chr_find("mux-label-base");
233 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
234
235 qemu_chr_be_write(base, (void *)"hello", 6);
236 g_assert_cmpint(h1.read_count, ==, 0);
237 g_assert_cmpint(h2.read_count, ==, 6);
238 g_assert_cmpstr(h2.read_buf, ==, "hello");
239 h2.read_count = 0;
240
241 g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */
242 g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */
243 /* sending event on the base broadcast to all fe, historical reasons? */
244 qemu_chr_be_event(base, 42);
245 g_assert_cmpint(h1.last_event, ==, 42);
246 g_assert_cmpint(h2.last_event, ==, 42);
247 qemu_chr_be_event(chr, -1);
248 g_assert_cmpint(h1.last_event, ==, 42);
249 g_assert_cmpint(h2.last_event, ==, -1);
250
251 /* switch focus */
252 qemu_chr_be_write(base, (void *)"\1b", 2);
253 g_assert_cmpint(h1.last_event, ==, 42);
254 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK);
255
256 qemu_chr_be_write(base, (void *)"\1c", 2);
257 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
258 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
259 qemu_chr_be_event(chr, -1);
260 g_assert_cmpint(h1.last_event, ==, -1);
261 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
262
263 qemu_chr_be_write(base, (void *)"hello", 6);
264 g_assert_cmpint(h2.read_count, ==, 0);
265 g_assert_cmpint(h1.read_count, ==, 6);
266 g_assert_cmpstr(h1.read_buf, ==, "hello");
267 h1.read_count = 0;
268
269 qemu_chr_be_write(base, (void *)"\1b", 2);
270 g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK);
271 g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
272
273 /* open/close state and corresponding events */
274 g_assert_true(qemu_chr_fe_backend_open(&chr_be1));
275 g_assert_true(qemu_chr_fe_backend_open(&chr_be2));
276 g_assert_true(h1.is_open);
277 g_assert_false(h1.openclose_mismatch);
278 g_assert_true(h2.is_open);
279 g_assert_false(h2.openclose_mismatch);
280
281 h1.openclose_count = h2.openclose_count = 0;
282
283 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
284 NULL, NULL, false);
285 qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, NULL, NULL,
286 NULL, NULL, false);
287 g_assert_cmpint(h1.openclose_count, ==, 0);
288 g_assert_cmpint(h2.openclose_count, ==, 0);
289
290 h1.is_open = h2.is_open = false;
291 qemu_chr_fe_set_handlers(&chr_be1,
292 NULL,
293 NULL,
294 fe_event,
295 NULL,
296 &h1,
297 NULL, false);
298 qemu_chr_fe_set_handlers(&chr_be2,
299 NULL,
300 NULL,
301 fe_event,
302 NULL,
303 &h2,
304 NULL, false);
305 g_assert_cmpint(h1.openclose_count, ==, 1);
306 g_assert_false(h1.openclose_mismatch);
307 g_assert_cmpint(h2.openclose_count, ==, 1);
308 g_assert_false(h2.openclose_mismatch);
309
310 qemu_chr_be_event(base, CHR_EVENT_CLOSED);
311 qemu_chr_be_event(base, CHR_EVENT_OPENED);
312 g_assert_cmpint(h1.openclose_count, ==, 3);
313 g_assert_false(h1.openclose_mismatch);
314 g_assert_cmpint(h2.openclose_count, ==, 3);
315 g_assert_false(h2.openclose_mismatch);
316
317 qemu_chr_fe_set_handlers(&chr_be2,
318 fe_can_read,
319 fe_read,
320 fe_event,
321 NULL,
322 &h2,
323 NULL, false);
324 qemu_chr_fe_set_handlers(&chr_be1,
325 fe_can_read,
326 fe_read,
327 fe_event,
328 NULL,
329 &h1,
330 NULL, false);
331
332 /* remove first handler */
333 qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
334 NULL, NULL, true);
335 qemu_chr_be_write(base, (void *)"hello", 6);
336 g_assert_cmpint(h1.read_count, ==, 0);
337 g_assert_cmpint(h2.read_count, ==, 0);
338
339 qemu_chr_be_write(base, (void *)"\1c", 2);
340 qemu_chr_be_write(base, (void *)"hello", 6);
341 g_assert_cmpint(h1.read_count, ==, 0);
342 g_assert_cmpint(h2.read_count, ==, 6);
343 g_assert_cmpstr(h2.read_buf, ==, "hello");
344 h2.read_count = 0;
345
346 /* print help */
347 qemu_chr_be_write(base, (void *)"\1?", 2);
348 data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
349 g_assert_cmpint(strlen(data), !=, 0);
350 g_free(data);
351
352 qemu_chr_fe_deinit(&chr_be1, false);
353
354 qmp_chardev_remove("mux-label", &error);
355 g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'mux-label' is busy");
356 error_free(error);
357
358 qemu_chr_fe_deinit(&chr_be2, false);
359 qmp_chardev_remove("mux-label", &error_abort);
360 }
361
char_hub_test(void)362 static void char_hub_test(void)
363 {
364 QemuOpts *opts;
365 Chardev *hub, *chr1, *chr2, *base;
366 char *data;
367 FeHandler h = { 0, false, 0, false, };
368 Error *error = NULL;
369 CharBackend chr_be;
370 int ret, i;
371
372 #define RB_SIZE 128
373
374 /*
375 * Create invalid hub
376 * 1. Create hub without a 'chardevs.N' defined (expect error)
377 */
378 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
379 1, &error_abort);
380 qemu_opt_set(opts, "backend", "hub", &error_abort);
381 hub = qemu_chr_new_from_opts(opts, NULL, &error);
382 g_assert_cmpstr(error_get_pretty(error), ==,
383 "hub: 'chardevs' list is not defined");
384 error_free(error);
385 error = NULL;
386 qemu_opts_del(opts);
387
388 /*
389 * Create invalid hub
390 * 1. Create chardev with embedded mux: 'mux=on'
391 * 2. Create hub which refers mux
392 * 3. Create hub which refers chardev already attached
393 * to the mux (already in use, expect error)
394 */
395 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr0",
396 1, &error_abort);
397 qemu_opt_set(opts, "mux", "on", &error_abort);
398 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
399 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
400 base = qemu_chr_new_from_opts(opts, NULL, &error_abort);
401 g_assert_nonnull(base);
402 qemu_opts_del(opts);
403
404 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
405 1, &error_abort);
406 qemu_opt_set(opts, "backend", "hub", &error_abort);
407 qemu_opt_set(opts, "chardevs.0", "chr0", &error_abort);
408 hub = qemu_chr_new_from_opts(opts, NULL, &error);
409 g_assert_cmpstr(error_get_pretty(error), ==,
410 "hub: multiplexers and hub devices can't be "
411 "stacked, check chardev 'chr0', chardev should "
412 "not be a hub device or have 'mux=on' enabled");
413 error_free(error);
414 error = NULL;
415 qemu_opts_del(opts);
416
417 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
418 1, &error_abort);
419 qemu_opt_set(opts, "backend", "hub", &error_abort);
420 qemu_opt_set(opts, "chardevs.0", "chr0-base", &error_abort);
421 hub = qemu_chr_new_from_opts(opts, NULL, &error);
422 g_assert_cmpstr(error_get_pretty(error), ==,
423 "chardev 'chr0-base' is already in use");
424 error_free(error);
425 error = NULL;
426 qemu_opts_del(opts);
427
428 /* Finalize chr0 */
429 qmp_chardev_remove("chr0", &error_abort);
430
431 /*
432 * Create invalid hub with more than maximum allowed backends
433 * 1. Create more than maximum allowed 'chardevs.%d' options for
434 * hub (expect error)
435 */
436 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
437 1, &error_abort);
438 for (i = 0; i < 10; i++) {
439 char key[32], val[32];
440
441 snprintf(key, sizeof(key), "chardevs.%d", i);
442 snprintf(val, sizeof(val), "chr%d", i);
443 qemu_opt_set(opts, key, val, &error);
444 if (error) {
445 char buf[64];
446
447 snprintf(buf, sizeof(buf), "Invalid parameter 'chardevs.%d'", i);
448 g_assert_cmpstr(error_get_pretty(error), ==, buf);
449 error_free(error);
450 break;
451 }
452 }
453 g_assert_nonnull(error);
454 error = NULL;
455 qemu_opts_del(opts);
456
457 /*
458 * Create hub with 2 backend chardevs and 1 frontend and perform
459 * data aggregation
460 * 1. Create 2 ringbuf backend chardevs
461 * 2. Create 1 frontend
462 * 3. Create hub which refers 2 backend chardevs
463 * 4. Attach hub to a frontend
464 * 5. Attach hub to a frontend second time (expect error)
465 * 6. Perform data aggregation
466 * 7. Remove chr1 ("chr1 is busy", expect error)
467 * 8. Remove hub0 ("hub0 is busy", expect error);
468 * 9. Finilize frontend, hub and backend chardevs in correct order
469 */
470
471 /* Create first chardev */
472 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr1",
473 1, &error_abort);
474 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
475 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
476 chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
477 g_assert_nonnull(chr1);
478 qemu_opts_del(opts);
479
480 /* Create second chardev */
481 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr2",
482 1, &error_abort);
483 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
484 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
485 chr2 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
486 g_assert_nonnull(chr2);
487 qemu_opts_del(opts);
488
489 /* Create hub0 and refer 2 backend chardevs */
490 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
491 1, &error_abort);
492 qemu_opt_set(opts, "backend", "hub", &error_abort);
493 qemu_opt_set(opts, "chardevs.0", "chr1", &error_abort);
494 qemu_opt_set(opts, "chardevs.1", "chr2", &error_abort);
495 hub = qemu_chr_new_from_opts(opts, NULL, &error_abort);
496 g_assert_nonnull(hub);
497 qemu_opts_del(opts);
498
499 /* Attach hub to a frontend */
500 qemu_chr_fe_init(&chr_be, hub, &error_abort);
501 qemu_chr_fe_set_handlers(&chr_be,
502 fe_can_read,
503 fe_read,
504 fe_event,
505 NULL,
506 &h,
507 NULL, true);
508
509 /* Fails second time */
510 qemu_chr_fe_init(&chr_be, hub, &error);
511 g_assert_cmpstr(error_get_pretty(error), ==, "chardev 'hub0' is already in use");
512 error_free(error);
513 error = NULL;
514
515 /* Write to backend, chr1 */
516 base = qemu_chr_find("chr1");
517 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
518
519 qemu_chr_be_write(base, (void *)"hello", 6);
520 g_assert_cmpint(h.read_count, ==, 6);
521 g_assert_cmpstr(h.read_buf, ==, "hello");
522 h.read_count = 0;
523
524 /* Write to backend, chr2 */
525 base = qemu_chr_find("chr2");
526 g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
527
528 qemu_chr_be_write(base, (void *)"olleh", 6);
529 g_assert_cmpint(h.read_count, ==, 6);
530 g_assert_cmpstr(h.read_buf, ==, "olleh");
531 h.read_count = 0;
532
533 /* Write to frontend, chr_be */
534 ret = qemu_chr_fe_write(&chr_be, (void *)"heyhey", 6);
535 g_assert_cmpint(ret, ==, 6);
536
537 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
538 g_assert_cmpint(strlen(data), ==, 6);
539 g_assert_cmpstr(data, ==, "heyhey");
540 g_free(data);
541
542 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
543 g_assert_cmpint(strlen(data), ==, 6);
544 g_assert_cmpstr(data, ==, "heyhey");
545 g_free(data);
546
547 /* Can't be removed, depends on hub0 */
548 qmp_chardev_remove("chr1", &error);
549 g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'chr1' is busy");
550 error_free(error);
551 error = NULL;
552
553 /* Can't be removed, depends on frontend chr_be */
554 qmp_chardev_remove("hub0", &error);
555 g_assert_cmpstr(error_get_pretty(error), ==, "Chardev 'hub0' is busy");
556 error_free(error);
557 error = NULL;
558
559 /* Finalize frontend */
560 qemu_chr_fe_deinit(&chr_be, false);
561
562 /* Finalize hub0 */
563 qmp_chardev_remove("hub0", &error_abort);
564
565 /* Finalize backend chardevs */
566 qmp_chardev_remove("chr1", &error_abort);
567 qmp_chardev_remove("chr2", &error_abort);
568
569 #ifndef _WIN32
570 /*
571 * Create 3 backend chardevs to simulate EAGAIN and watcher.
572 * Mainly copied from char_pipe_test().
573 * 1. Create 2 ringbuf backend chardevs
574 * 2. Create 1 pipe backend chardev
575 * 3. Create 1 frontend
576 * 4. Create hub which refers 2 backend chardevs
577 * 5. Attach hub to a frontend
578 * 6. Perform data aggregation and check watcher
579 * 7. Finilize frontend, hub and backend chardevs in correct order
580 */
581 {
582 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
583 gchar *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
584 Chardev *chr3;
585 int fd, len;
586 char buf[128];
587
588 in = g_strdup_printf("%s.in", pipe);
589 if (mkfifo(in, 0600) < 0) {
590 abort();
591 }
592 out = g_strdup_printf("%s.out", pipe);
593 if (mkfifo(out, 0600) < 0) {
594 abort();
595 }
596
597 /* Create first chardev */
598 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr1",
599 1, &error_abort);
600 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
601 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
602 chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
603 g_assert_nonnull(chr1);
604 qemu_opts_del(opts);
605
606 /* Create second chardev */
607 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr2",
608 1, &error_abort);
609 qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
610 qemu_opt_set(opts, "size", stringify(RB_SIZE), &error_abort);
611 chr2 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
612 g_assert_nonnull(chr2);
613 qemu_opts_del(opts);
614
615 /* Create third chardev */
616 opts = qemu_opts_create(qemu_find_opts("chardev"), "chr3",
617 1, &error_abort);
618 qemu_opt_set(opts, "backend", "pipe", &error_abort);
619 qemu_opt_set(opts, "path", pipe, &error_abort);
620 chr3 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
621 g_assert_nonnull(chr3);
622
623 /* Create hub0 and refer 3 backend chardevs */
624 opts = qemu_opts_create(qemu_find_opts("chardev"), "hub0",
625 1, &error_abort);
626 qemu_opt_set(opts, "backend", "hub", &error_abort);
627 qemu_opt_set(opts, "chardevs.0", "chr1", &error_abort);
628 qemu_opt_set(opts, "chardevs.1", "chr2", &error_abort);
629 qemu_opt_set(opts, "chardevs.2", "chr3", &error_abort);
630 hub = qemu_chr_new_from_opts(opts, NULL, &error_abort);
631 g_assert_nonnull(hub);
632 qemu_opts_del(opts);
633
634 /* Attach hub to a frontend */
635 qemu_chr_fe_init(&chr_be, hub, &error_abort);
636 qemu_chr_fe_set_handlers(&chr_be,
637 fe_can_read,
638 fe_read,
639 fe_event,
640 NULL,
641 &h,
642 NULL, true);
643
644 /* Write to frontend, chr_be */
645 ret = qemu_chr_fe_write(&chr_be, (void *)"thisis", 6);
646 g_assert_cmpint(ret, ==, 6);
647
648 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
649 g_assert_cmpint(strlen(data), ==, 6);
650 g_assert_cmpstr(data, ==, "thisis");
651 g_free(data);
652
653 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
654 g_assert_cmpint(strlen(data), ==, 6);
655 g_assert_cmpstr(data, ==, "thisis");
656 g_free(data);
657
658 fd = open(out, O_RDWR);
659 ret = read(fd, buf, sizeof(buf));
660 g_assert_cmpint(ret, ==, 6);
661 buf[ret] = 0;
662 g_assert_cmpstr(buf, ==, "thisis");
663 close(fd);
664
665 /* Add watch. 0 indicates no watches if nothing to wait for */
666 ret = qemu_chr_fe_add_watch(&chr_be, G_IO_OUT | G_IO_HUP,
667 NULL, NULL);
668 g_assert_cmpint(ret, ==, 0);
669
670 /*
671 * Write to frontend, chr_be, until EAGAIN. Make sure length is
672 * power of two to fit nicely the whole pipe buffer.
673 */
674 len = 0;
675 while ((ret = qemu_chr_fe_write(&chr_be, (void *)"thisisit", 8))
676 != -1) {
677 len += ret;
678 }
679 g_assert_cmpint(errno, ==, EAGAIN);
680
681 /* Further all writes should cause EAGAIN */
682 ret = qemu_chr_fe_write(&chr_be, (void *)"b", 1);
683 g_assert_cmpint(ret, ==, -1);
684 g_assert_cmpint(errno, ==, EAGAIN);
685
686 /*
687 * Add watch. Non 0 indicates we have a blocked chardev, which
688 * can wakes us up when write is possible.
689 */
690 ret = qemu_chr_fe_add_watch(&chr_be, G_IO_OUT | G_IO_HUP,
691 NULL, NULL);
692 g_assert_cmpint(ret, !=, 0);
693 g_source_remove(ret);
694
695 /* Drain pipe and ring buffers */
696 fd = open(out, O_RDWR);
697 while ((ret = read(fd, buf, MIN(sizeof(buf), len))) != -1 && len > 0) {
698 len -= ret;
699 }
700 close(fd);
701
702 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
703 g_assert_cmpint(strlen(data), ==, 128);
704 g_free(data);
705
706 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
707 g_assert_cmpint(strlen(data), ==, 128);
708 g_free(data);
709
710 /*
711 * Now we are good to go, first repeat "lost" sequence, which
712 * was already consumed and drained by the ring buffers, but
713 * pipe have not recieved that yet.
714 */
715 ret = qemu_chr_fe_write(&chr_be, (void *)"thisisit", 8);
716 g_assert_cmpint(ret, ==, 8);
717
718 ret = qemu_chr_fe_write(&chr_be, (void *)"streamisrestored", 16);
719 g_assert_cmpint(ret, ==, 16);
720
721 data = qmp_ringbuf_read("chr1", RB_SIZE, false, 0, &error_abort);
722 g_assert_cmpint(strlen(data), ==, 16);
723 /* Only last 16 bytes, see big comment above */
724 g_assert_cmpstr(data, ==, "streamisrestored");
725 g_free(data);
726
727 data = qmp_ringbuf_read("chr2", RB_SIZE, false, 0, &error_abort);
728 g_assert_cmpint(strlen(data), ==, 16);
729 /* Only last 16 bytes, see big comment above */
730 g_assert_cmpstr(data, ==, "streamisrestored");
731 g_free(data);
732
733 fd = open(out, O_RDWR);
734 ret = read(fd, buf, sizeof(buf));
735 g_assert_cmpint(ret, ==, 24);
736 buf[ret] = 0;
737 /* Both 8 and 16 bytes */
738 g_assert_cmpstr(buf, ==, "thisisitstreamisrestored");
739 close(fd);
740
741 g_free(in);
742 g_free(out);
743 g_free(tmp_path);
744 g_free(pipe);
745
746 /* Finalize frontend */
747 qemu_chr_fe_deinit(&chr_be, false);
748
749 /* Finalize hub0 */
750 qmp_chardev_remove("hub0", &error_abort);
751
752 /* Finalize backend chardevs */
753 qmp_chardev_remove("chr1", &error_abort);
754 qmp_chardev_remove("chr2", &error_abort);
755 qmp_chardev_remove("chr3", &error_abort);
756 }
757 #endif
758 }
759
websock_server_read(void * opaque,const uint8_t * buf,int size)760 static void websock_server_read(void *opaque, const uint8_t *buf, int size)
761 {
762 g_assert_cmpint(size, ==, 5);
763 g_assert(memcmp(buf, "world", size) == 0);
764 quit = true;
765 }
766
767
websock_server_can_read(void * opaque)768 static int websock_server_can_read(void *opaque)
769 {
770 return 10;
771 }
772
773
websock_check_http_headers(char * buf,int size)774 static bool websock_check_http_headers(char *buf, int size)
775 {
776 int i;
777 const char *ans[] = { "HTTP/1.1 101 Switching Protocols\r\n",
778 "Server: QEMU VNC\r\n",
779 "Upgrade: websocket\r\n",
780 "Connection: Upgrade\r\n",
781 "Sec-WebSocket-Accept:",
782 "Sec-WebSocket-Protocol: binary\r\n" };
783
784 for (i = 0; i < 6; i++) {
785 if (g_strstr_len(buf, size, ans[i]) == NULL) {
786 return false;
787 }
788 }
789
790 return true;
791 }
792
793
websock_client_read(void * opaque,const uint8_t * buf,int size)794 static void websock_client_read(void *opaque, const uint8_t *buf, int size)
795 {
796 const uint8_t ping[] = { 0x89, 0x85, /* Ping header */
797 0x07, 0x77, 0x9e, 0xf9, /* Masking key */
798 0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ };
799
800 const uint8_t binary[] = { 0x82, 0x85, /* Binary header */
801 0x74, 0x90, 0xb9, 0xdf, /* Masking key */
802 0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ };
803 Chardev *chr_client = opaque;
804
805 if (websock_check_http_headers((char *) buf, size)) {
806 qemu_chr_fe_write(chr_client->be, ping, sizeof(ping));
807 } else if (buf[0] == 0x8a && buf[1] == 0x05) {
808 g_assert(strncmp((char *) buf + 2, "hello", 5) == 0);
809 qemu_chr_fe_write(chr_client->be, binary, sizeof(binary));
810 } else {
811 g_assert(buf[0] == 0x88 && buf[1] == 0x16);
812 g_assert(strncmp((char *) buf + 4, "peer requested close", 10) == 0);
813 quit = true;
814 }
815 }
816
817
websock_client_can_read(void * opaque)818 static int websock_client_can_read(void *opaque)
819 {
820 return 4096;
821 }
822
823
char_websock_test(void)824 static void char_websock_test(void)
825 {
826 QObject *addr;
827 QDict *qdict;
828 const char *port;
829 char *tmp;
830 char *handshake_port;
831 CharBackend be;
832 CharBackend client_be;
833 Chardev *chr_client;
834 Chardev *chr = qemu_chr_new("server",
835 "websocket:127.0.0.1:0,server=on,wait=off", NULL);
836 const char handshake[] = "GET / HTTP/1.1\r\n"
837 "Upgrade: websocket\r\n"
838 "Connection: Upgrade\r\n"
839 "Host: localhost:%s\r\n"
840 "Origin: http://localhost:%s\r\n"
841 "Sec-WebSocket-Key: o9JHNiS3/0/0zYE1wa3yIw==\r\n"
842 "Sec-WebSocket-Version: 13\r\n"
843 "Sec-WebSocket-Protocol: binary\r\n\r\n";
844 const uint8_t close[] = { 0x88, 0x82, /* Close header */
845 0xef, 0xaa, 0xc5, 0x97, /* Masking key */
846 0xec, 0x42 /* Status code */ };
847
848 addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
849 qdict = qobject_to(QDict, addr);
850 port = qdict_get_str(qdict, "port");
851 tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
852 handshake_port = g_strdup_printf(handshake, port, port);
853 qobject_unref(qdict);
854
855 qemu_chr_fe_init(&be, chr, &error_abort);
856 qemu_chr_fe_set_handlers(&be, websock_server_can_read, websock_server_read,
857 NULL, NULL, chr, NULL, true);
858
859 chr_client = qemu_chr_new("client", tmp, NULL);
860 qemu_chr_fe_init(&client_be, chr_client, &error_abort);
861 qemu_chr_fe_set_handlers(&client_be, websock_client_can_read,
862 websock_client_read,
863 NULL, NULL, chr_client, NULL, true);
864 g_free(tmp);
865
866 qemu_chr_write_all(chr_client,
867 (uint8_t *) handshake_port,
868 strlen(handshake_port));
869 g_free(handshake_port);
870 main_loop();
871
872 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
873 g_assert(object_property_get_bool(OBJECT(chr_client),
874 "connected", &error_abort));
875
876 qemu_chr_write_all(chr_client, close, sizeof(close));
877 main_loop();
878
879 object_unparent(OBJECT(chr_client));
880 object_unparent(OBJECT(chr));
881 }
882
883
884 #ifndef _WIN32
char_pipe_test(void)885 static void char_pipe_test(void)
886 {
887 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
888 gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
889 Chardev *chr;
890 CharBackend be;
891 int ret, fd;
892 char buf[10];
893 FeHandler fe = { 0, };
894
895 in = g_strdup_printf("%s.in", pipe);
896 if (mkfifo(in, 0600) < 0) {
897 abort();
898 }
899 out = g_strdup_printf("%s.out", pipe);
900 if (mkfifo(out, 0600) < 0) {
901 abort();
902 }
903
904 tmp = g_strdup_printf("pipe:%s", pipe);
905 chr = qemu_chr_new("pipe", tmp, NULL);
906 g_assert_nonnull(chr);
907 g_free(tmp);
908
909 qemu_chr_fe_init(&be, chr, &error_abort);
910
911 ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
912 g_assert_cmpint(ret, ==, 9);
913
914 fd = open(out, O_RDWR);
915 ret = read(fd, buf, sizeof(buf));
916 g_assert_cmpint(ret, ==, 9);
917 g_assert_cmpstr(buf, ==, "pipe-out");
918 close(fd);
919
920 fd = open(in, O_WRONLY);
921 ret = write(fd, "pipe-in", 8);
922 g_assert_cmpint(ret, ==, 8);
923 close(fd);
924
925 qemu_chr_fe_set_handlers(&be,
926 fe_can_read,
927 fe_read,
928 fe_event,
929 NULL,
930 &fe,
931 NULL, true);
932
933 main_loop();
934
935 g_assert_cmpint(fe.read_count, ==, 8);
936 g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
937
938 qemu_chr_fe_deinit(&be, true);
939
940 g_assert(g_unlink(in) == 0);
941 g_assert(g_unlink(out) == 0);
942 g_assert(g_rmdir(tmp_path) == 0);
943 g_free(in);
944 g_free(out);
945 g_free(tmp_path);
946 g_free(pipe);
947 }
948 #endif
949
950 typedef struct SocketIdleData {
951 GMainLoop *loop;
952 Chardev *chr;
953 bool conn_expected;
954 CharBackend *be;
955 CharBackend *client_be;
956 } SocketIdleData;
957
958
socket_read_hello(void * opaque,const uint8_t * buf,int size)959 static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
960 {
961 g_assert_cmpint(size, ==, 5);
962 g_assert(strncmp((char *)buf, "hello", 5) == 0);
963
964 quit = true;
965 }
966
socket_can_read_hello(void * opaque)967 static int socket_can_read_hello(void *opaque)
968 {
969 return 10;
970 }
971
make_udp_socket(int * port)972 static int make_udp_socket(int *port)
973 {
974 struct sockaddr_in addr = { 0, };
975 socklen_t alen = sizeof(addr);
976 int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
977
978 g_assert_cmpint(sock, >=, 0);
979 addr.sin_family = AF_INET ;
980 addr.sin_addr.s_addr = htonl(INADDR_ANY);
981 addr.sin_port = 0;
982 ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
983 g_assert_cmpint(ret, ==, 0);
984 ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
985 g_assert_cmpint(ret, ==, 0);
986
987 *port = ntohs(addr.sin_port);
988 return sock;
989 }
990
char_udp_test_internal(Chardev * reuse_chr,int sock)991 static void char_udp_test_internal(Chardev *reuse_chr, int sock)
992 {
993 struct sockaddr_in other;
994 SocketIdleData d = { 0, };
995 Chardev *chr;
996 CharBackend *be;
997 socklen_t alen = sizeof(other);
998 int ret;
999 char buf[10];
1000 char *tmp = NULL;
1001
1002 if (reuse_chr) {
1003 chr = reuse_chr;
1004 be = chr->be;
1005 } else {
1006 int port;
1007 sock = make_udp_socket(&port);
1008 tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
1009 chr = qemu_chr_new("client", tmp, NULL);
1010 g_assert_nonnull(chr);
1011
1012 be = g_alloca(sizeof(CharBackend));
1013 qemu_chr_fe_init(be, chr, &error_abort);
1014 }
1015
1016 d.chr = chr;
1017 qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
1018 NULL, NULL, &d, NULL, true);
1019 ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
1020 g_assert_cmpint(ret, ==, 5);
1021
1022 ret = recvfrom(sock, buf, sizeof(buf), 0,
1023 (struct sockaddr *)&other, &alen);
1024 g_assert_cmpint(ret, ==, 5);
1025 ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
1026 g_assert_cmpint(ret, ==, 5);
1027
1028 main_loop();
1029
1030 if (!reuse_chr) {
1031 close(sock);
1032 qemu_chr_fe_deinit(be, true);
1033 }
1034 g_free(tmp);
1035 }
1036
char_udp_test(void)1037 static void char_udp_test(void)
1038 {
1039 char_udp_test_internal(NULL, 0);
1040 }
1041
1042
1043 typedef struct {
1044 int event;
1045 bool got_pong;
1046 CharBackend *be;
1047 } CharSocketTestData;
1048
1049
1050 #define SOCKET_PING "Hello"
1051 #define SOCKET_PONG "World"
1052
1053 typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event);
1054
1055 static void
char_socket_event(void * opaque,QEMUChrEvent event)1056 char_socket_event(void *opaque, QEMUChrEvent event)
1057 {
1058 CharSocketTestData *data = opaque;
1059 data->event = event;
1060 }
1061
1062 static void
char_socket_event_with_error(void * opaque,QEMUChrEvent event)1063 char_socket_event_with_error(void *opaque, QEMUChrEvent event)
1064 {
1065 static bool first_error;
1066 CharSocketTestData *data = opaque;
1067 CharBackend *be = data->be;
1068 data->event = event;
1069 switch (event) {
1070 case CHR_EVENT_OPENED:
1071 if (!first_error) {
1072 first_error = true;
1073 qemu_chr_fe_disconnect(be);
1074 }
1075 return;
1076 case CHR_EVENT_CLOSED:
1077 return;
1078 default:
1079 return;
1080 }
1081 }
1082
1083
1084 static void
char_socket_read(void * opaque,const uint8_t * buf,int size)1085 char_socket_read(void *opaque, const uint8_t *buf, int size)
1086 {
1087 CharSocketTestData *data = opaque;
1088 g_assert_cmpint(size, ==, sizeof(SOCKET_PONG));
1089 g_assert(memcmp(buf, SOCKET_PONG, size) == 0);
1090 data->got_pong = true;
1091 }
1092
1093
1094 static int
char_socket_can_read(void * opaque)1095 char_socket_can_read(void *opaque)
1096 {
1097 return sizeof(SOCKET_PONG);
1098 }
1099
1100
1101 static char *
char_socket_addr_to_opt_str(SocketAddress * addr,bool fd_pass,const char * reconnect,bool is_listen)1102 char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass,
1103 const char *reconnect, bool is_listen)
1104 {
1105 if (fd_pass) {
1106 QIOChannelSocket *ioc = qio_channel_socket_new();
1107 int fd;
1108 char *optstr;
1109 g_assert(!reconnect);
1110 if (is_listen) {
1111 qio_channel_socket_listen_sync(ioc, addr, 1, &error_abort);
1112 } else {
1113 qio_channel_socket_connect_sync(ioc, addr, &error_abort);
1114 }
1115 fd = ioc->fd;
1116 ioc->fd = -1;
1117 optstr = g_strdup_printf("socket,id=cdev0,fd=%d%s",
1118 fd, is_listen ? ",server=on,wait=off" : "");
1119 object_unref(OBJECT(ioc));
1120 return optstr;
1121 } else {
1122 switch (addr->type) {
1123 case SOCKET_ADDRESS_TYPE_INET:
1124 return g_strdup_printf("socket,id=cdev0,host=%s,port=%s%s%s",
1125 addr->u.inet.host,
1126 addr->u.inet.port,
1127 reconnect ? reconnect : "",
1128 is_listen ? ",server=on,wait=off" : "");
1129
1130 case SOCKET_ADDRESS_TYPE_UNIX:
1131 return g_strdup_printf("socket,id=cdev0,path=%s%s%s",
1132 addr->u.q_unix.path,
1133 reconnect ? reconnect : "",
1134 is_listen ? ",server=on,wait=off" : "");
1135
1136 default:
1137 g_assert_not_reached();
1138 }
1139 }
1140 }
1141
1142
1143 static int
char_socket_ping_pong(QIOChannel * ioc,Error ** errp)1144 char_socket_ping_pong(QIOChannel *ioc, Error **errp)
1145 {
1146 char greeting[sizeof(SOCKET_PING)];
1147 const char *response = SOCKET_PONG;
1148
1149 int ret;
1150 ret = qio_channel_read_all(ioc, greeting, sizeof(greeting), errp);
1151 if (ret != 0) {
1152 object_unref(OBJECT(ioc));
1153 return -1;
1154 }
1155
1156 g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0);
1157
1158 qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), errp);
1159 object_unref(OBJECT(ioc));
1160 return 0;
1161 }
1162
1163
1164 static gpointer
char_socket_server_client_thread(gpointer data)1165 char_socket_server_client_thread(gpointer data)
1166 {
1167 SocketAddress *addr = data;
1168 QIOChannelSocket *ioc = qio_channel_socket_new();
1169
1170 qio_channel_socket_connect_sync(ioc, addr, &error_abort);
1171
1172 char_socket_ping_pong(QIO_CHANNEL(ioc), &error_abort);
1173
1174 return NULL;
1175 }
1176
1177
1178 typedef struct {
1179 SocketAddress *addr;
1180 bool wait_connected;
1181 bool fd_pass;
1182 } CharSocketServerTestConfig;
1183
1184
char_socket_server_test(gconstpointer opaque)1185 static void char_socket_server_test(gconstpointer opaque)
1186 {
1187 const CharSocketServerTestConfig *config = opaque;
1188 Chardev *chr;
1189 CharBackend be = {0};
1190 CharSocketTestData data = {0};
1191 QObject *qaddr;
1192 SocketAddress *addr;
1193 Visitor *v;
1194 QemuThread thread;
1195 int ret;
1196 bool reconnected = false;
1197 char *optstr;
1198 QemuOpts *opts;
1199
1200 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1201 /*
1202 * We rely on config->addr containing "wait=off", otherwise
1203 * qemu_chr_new() will block until a client connects. We
1204 * can't spawn our client thread though, because until
1205 * qemu_chr_new() returns we don't know what TCP port was
1206 * allocated by the OS
1207 */
1208 optstr = char_socket_addr_to_opt_str(config->addr,
1209 config->fd_pass,
1210 NULL,
1211 true);
1212 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
1213 optstr, true);
1214 g_assert_nonnull(opts);
1215 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
1216 qemu_opts_del(opts);
1217 g_assert_nonnull(chr);
1218 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
1219
1220 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
1221 g_assert_nonnull(qaddr);
1222
1223 v = qobject_input_visitor_new(qaddr);
1224 visit_type_SocketAddress(v, "addr", &addr, &error_abort);
1225 visit_free(v);
1226 qobject_unref(qaddr);
1227
1228 qemu_chr_fe_init(&be, chr, &error_abort);
1229
1230 reconnect:
1231 data.event = -1;
1232 data.be = &be;
1233 qemu_chr_fe_set_handlers(&be, NULL, NULL,
1234 char_socket_event, NULL,
1235 &data, NULL, true);
1236 g_assert(data.event == -1);
1237
1238 /*
1239 * Kick off a thread to act as the "remote" client
1240 * which just plays ping-pong with us
1241 */
1242 qemu_thread_create(&thread, "client",
1243 char_socket_server_client_thread,
1244 addr, QEMU_THREAD_JOINABLE);
1245 g_assert(data.event == -1);
1246
1247 if (config->wait_connected) {
1248 /* Synchronously accept a connection */
1249 qemu_chr_wait_connected(chr, &error_abort);
1250 } else {
1251 /*
1252 * Asynchronously accept a connection when the evnt
1253 * loop reports the listener socket as readable
1254 */
1255 while (data.event == -1) {
1256 main_loop_wait(false);
1257 }
1258 }
1259 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
1260 g_assert(data.event == CHR_EVENT_OPENED);
1261 data.event = -1;
1262
1263 /* Send a greeting to the client */
1264 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING,
1265 sizeof(SOCKET_PING));
1266 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING));
1267 g_assert(data.event == -1);
1268
1269 /* Setup a callback to receive the reply to our greeting */
1270 qemu_chr_fe_set_handlers(&be, char_socket_can_read,
1271 char_socket_read,
1272 char_socket_event, NULL,
1273 &data, NULL, true);
1274 g_assert(data.event == CHR_EVENT_OPENED);
1275 data.event = -1;
1276
1277 /* Wait for the client to go away */
1278 while (data.event == -1) {
1279 main_loop_wait(false);
1280 }
1281 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
1282 g_assert(data.event == CHR_EVENT_CLOSED);
1283 g_assert(data.got_pong);
1284
1285 qemu_thread_join(&thread);
1286
1287 if (!reconnected) {
1288 reconnected = true;
1289 goto reconnect;
1290 }
1291
1292 qapi_free_SocketAddress(addr);
1293 object_unparent(OBJECT(chr));
1294 g_free(optstr);
1295 g_unsetenv("QTEST_SILENT_ERRORS");
1296 }
1297
1298
1299 static gpointer
char_socket_client_server_thread(gpointer data)1300 char_socket_client_server_thread(gpointer data)
1301 {
1302 QIOChannelSocket *ioc = data;
1303 QIOChannelSocket *cioc;
1304
1305 retry:
1306 cioc = qio_channel_socket_accept(ioc, &error_abort);
1307 g_assert_nonnull(cioc);
1308
1309 if (char_socket_ping_pong(QIO_CHANNEL(cioc), NULL) != 0) {
1310 goto retry;
1311 }
1312
1313 return NULL;
1314 }
1315
1316
1317 typedef struct {
1318 SocketAddress *addr;
1319 const char *reconnect;
1320 bool wait_connected;
1321 bool fd_pass;
1322 char_socket_cb event_cb;
1323 } CharSocketClientTestConfig;
1324
char_socket_client_dupid_test(gconstpointer opaque)1325 static void char_socket_client_dupid_test(gconstpointer opaque)
1326 {
1327 const CharSocketClientTestConfig *config = opaque;
1328 QIOChannelSocket *ioc;
1329 char *optstr;
1330 Chardev *chr1, *chr2;
1331 SocketAddress *addr;
1332 QemuOpts *opts;
1333 Error *local_err = NULL;
1334
1335 /*
1336 * Setup a listener socket and determine get its address
1337 * so we know the TCP port for the client later
1338 */
1339 ioc = qio_channel_socket_new();
1340 g_assert_nonnull(ioc);
1341 qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort);
1342 addr = qio_channel_socket_get_local_address(ioc, &error_abort);
1343 g_assert_nonnull(addr);
1344
1345 /*
1346 * Populate the chardev address based on what the server
1347 * is actually listening on
1348 */
1349 optstr = char_socket_addr_to_opt_str(addr,
1350 config->fd_pass,
1351 config->reconnect,
1352 false);
1353
1354 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
1355 optstr, true);
1356 g_assert_nonnull(opts);
1357 chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
1358 g_assert_nonnull(chr1);
1359 qemu_chr_wait_connected(chr1, &error_abort);
1360
1361 chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err);
1362 g_assert_null(chr2);
1363 error_free_or_abort(&local_err);
1364
1365 object_unref(OBJECT(ioc));
1366 qemu_opts_del(opts);
1367 object_unparent(OBJECT(chr1));
1368 qapi_free_SocketAddress(addr);
1369 g_free(optstr);
1370 }
1371
char_socket_client_test(gconstpointer opaque)1372 static void char_socket_client_test(gconstpointer opaque)
1373 {
1374 const CharSocketClientTestConfig *config = opaque;
1375 const char_socket_cb event_cb = config->event_cb;
1376 QIOChannelSocket *ioc;
1377 char *optstr;
1378 Chardev *chr;
1379 CharBackend be = {0};
1380 CharSocketTestData data = {0};
1381 SocketAddress *addr;
1382 QemuThread thread;
1383 int ret;
1384 bool reconnected = false;
1385 QemuOpts *opts;
1386
1387 /*
1388 * Setup a listener socket and determine get its address
1389 * so we know the TCP port for the client later
1390 */
1391 ioc = qio_channel_socket_new();
1392 g_assert_nonnull(ioc);
1393 qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort);
1394 addr = qio_channel_socket_get_local_address(ioc, &error_abort);
1395 g_assert_nonnull(addr);
1396
1397 /*
1398 * Kick off a thread to act as the "remote" client
1399 * which just plays ping-pong with us
1400 */
1401 qemu_thread_create(&thread, "client",
1402 char_socket_client_server_thread,
1403 ioc, QEMU_THREAD_JOINABLE);
1404
1405 /*
1406 * Populate the chardev address based on what the server
1407 * is actually listening on
1408 */
1409 optstr = char_socket_addr_to_opt_str(addr,
1410 config->fd_pass,
1411 config->reconnect,
1412 false);
1413
1414 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
1415 optstr, true);
1416 g_assert_nonnull(opts);
1417 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
1418 qemu_opts_del(opts);
1419 g_assert_nonnull(chr);
1420
1421 if (config->reconnect) {
1422 /*
1423 * If reconnect is set, the connection will be
1424 * established in a background thread and we won't
1425 * see the "connected" status updated until we
1426 * run the main event loop, or call qemu_chr_wait_connected
1427 */
1428 g_assert(!object_property_get_bool(OBJECT(chr), "connected",
1429 &error_abort));
1430 } else {
1431 g_assert(object_property_get_bool(OBJECT(chr), "connected",
1432 &error_abort));
1433 }
1434
1435 qemu_chr_fe_init(&be, chr, &error_abort);
1436
1437 reconnect:
1438 data.event = -1;
1439 data.be = &be;
1440 qemu_chr_fe_set_handlers(&be, NULL, NULL,
1441 event_cb, NULL,
1442 &data, NULL, true);
1443 if (config->reconnect) {
1444 g_assert(data.event == -1);
1445 } else {
1446 g_assert(data.event == CHR_EVENT_OPENED);
1447 }
1448
1449 if (config->wait_connected) {
1450 /*
1451 * Synchronously wait for the connection to complete
1452 * This should be a no-op if reconnect is not set.
1453 */
1454 qemu_chr_wait_connected(chr, &error_abort);
1455 } else {
1456 /*
1457 * Asynchronously wait for the connection to be reported
1458 * as complete when the background thread reports its
1459 * status.
1460 * The loop will short-circuit if reconnect was set
1461 */
1462 while (data.event == -1) {
1463 main_loop_wait(false);
1464 }
1465 }
1466 g_assert(data.event == CHR_EVENT_OPENED);
1467 data.event = -1;
1468 g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
1469
1470 /* Send a greeting to the server */
1471 ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING,
1472 sizeof(SOCKET_PING));
1473 g_assert_cmpint(ret, ==, sizeof(SOCKET_PING));
1474 g_assert(data.event == -1);
1475
1476 /* Setup a callback to receive the reply to our greeting */
1477 qemu_chr_fe_set_handlers(&be, char_socket_can_read,
1478 char_socket_read,
1479 event_cb, NULL,
1480 &data, NULL, true);
1481 g_assert(data.event == CHR_EVENT_OPENED);
1482 data.event = -1;
1483
1484 /* Wait for the server to go away */
1485 while (data.event == -1) {
1486 main_loop_wait(false);
1487 }
1488 g_assert(data.event == CHR_EVENT_CLOSED);
1489 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
1490 g_assert(data.got_pong);
1491 qemu_thread_join(&thread);
1492
1493 if (config->reconnect && !reconnected) {
1494 reconnected = true;
1495 qemu_thread_create(&thread, "client",
1496 char_socket_client_server_thread,
1497 ioc, QEMU_THREAD_JOINABLE);
1498 goto reconnect;
1499 }
1500
1501 object_unref(OBJECT(ioc));
1502 object_unparent(OBJECT(chr));
1503 qapi_free_SocketAddress(addr);
1504 g_free(optstr);
1505 }
1506
1507 static void
count_closed_event(void * opaque,QEMUChrEvent event)1508 count_closed_event(void *opaque, QEMUChrEvent event)
1509 {
1510 int *count = opaque;
1511 if (event == CHR_EVENT_CLOSED) {
1512 (*count)++;
1513 }
1514 }
1515
1516 static void
char_socket_discard_read(void * opaque,const uint8_t * buf,int size)1517 char_socket_discard_read(void *opaque, const uint8_t *buf, int size)
1518 {
1519 }
1520
char_socket_server_two_clients_test(gconstpointer opaque)1521 static void char_socket_server_two_clients_test(gconstpointer opaque)
1522 {
1523 SocketAddress *incoming_addr = (gpointer) opaque;
1524 Chardev *chr;
1525 CharBackend be = {0};
1526 QObject *qaddr;
1527 SocketAddress *addr;
1528 Visitor *v;
1529 char *optstr;
1530 QemuOpts *opts;
1531 QIOChannelSocket *ioc1, *ioc2;
1532 int closed = 0;
1533
1534 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1535 /*
1536 * We rely on addr containing "wait=off", otherwise
1537 * qemu_chr_new() will block until a client connects. We
1538 * can't spawn our client thread though, because until
1539 * qemu_chr_new() returns we don't know what TCP port was
1540 * allocated by the OS
1541 */
1542 optstr = char_socket_addr_to_opt_str(incoming_addr,
1543 false,
1544 NULL,
1545 true);
1546 opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
1547 optstr, true);
1548 g_assert_nonnull(opts);
1549 chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
1550 qemu_opts_del(opts);
1551 g_assert_nonnull(chr);
1552 g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
1553
1554 qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
1555 g_assert_nonnull(qaddr);
1556
1557 v = qobject_input_visitor_new(qaddr);
1558 visit_type_SocketAddress(v, "addr", &addr, &error_abort);
1559 visit_free(v);
1560 qobject_unref(qaddr);
1561
1562 qemu_chr_fe_init(&be, chr, &error_abort);
1563
1564 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read,
1565 count_closed_event, NULL,
1566 &closed, NULL, true);
1567
1568 ioc1 = qio_channel_socket_new();
1569 qio_channel_socket_connect_sync(ioc1, addr, &error_abort);
1570 qemu_chr_wait_connected(chr, &error_abort);
1571
1572 /* switch the chardev to another context */
1573 GMainContext *ctx = g_main_context_new();
1574 qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read,
1575 count_closed_event, NULL,
1576 &closed, ctx, true);
1577
1578 /* Start a second connection while the first is still connected.
1579 * It will be placed in the listen() backlog, and connect() will
1580 * succeed immediately.
1581 */
1582 ioc2 = qio_channel_socket_new();
1583 qio_channel_socket_connect_sync(ioc2, addr, &error_abort);
1584
1585 object_unref(OBJECT(ioc1));
1586 /* The two connections should now be processed serially. */
1587 while (g_main_context_iteration(ctx, TRUE)) {
1588 if (closed == 1 && ioc2) {
1589 object_unref(OBJECT(ioc2));
1590 ioc2 = NULL;
1591 }
1592 if (closed == 2) {
1593 break;
1594 }
1595 }
1596
1597 qapi_free_SocketAddress(addr);
1598 object_unparent(OBJECT(chr));
1599 g_main_context_unref(ctx);
1600 g_free(optstr);
1601 g_unsetenv("QTEST_SILENT_ERRORS");
1602 }
1603
1604
1605 #if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32)
char_serial_test(void)1606 static void char_serial_test(void)
1607 {
1608 QemuOpts *opts;
1609 Chardev *chr;
1610
1611 opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
1612 1, &error_abort);
1613 qemu_opt_set(opts, "backend", "serial", &error_abort);
1614 qemu_opt_set(opts, "path", "/dev/null", &error_abort);
1615
1616 chr = qemu_chr_new_from_opts(opts, NULL, NULL);
1617 g_assert_nonnull(chr);
1618 /* TODO: add more tests with a pty */
1619 object_unparent(OBJECT(chr));
1620
1621 qemu_opts_del(opts);
1622 }
1623 #endif
1624
1625 #if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32)
char_parallel_test(void)1626 static void char_parallel_test(void)
1627 {
1628 QemuOpts *opts;
1629 Chardev *chr;
1630
1631 opts = qemu_opts_create(qemu_find_opts("chardev"), "parallel-id",
1632 1, &error_abort);
1633 qemu_opt_set(opts, "backend", "parallel", &error_abort);
1634 qemu_opt_set(opts, "path", "/dev/null", &error_abort);
1635
1636 chr = qemu_chr_new_from_opts(opts, NULL, NULL);
1637 #ifdef __linux__
1638 /* fails to PPCLAIM, see qemu_chr_open_pp_fd() */
1639 g_assert_null(chr);
1640 #else
1641 g_assert_nonnull(chr);
1642 object_unparent(OBJECT(chr));
1643 #endif
1644
1645 qemu_opts_del(opts);
1646 }
1647 #endif
1648
1649 #ifndef _WIN32
char_file_fifo_test(void)1650 static void char_file_fifo_test(void)
1651 {
1652 Chardev *chr;
1653 CharBackend be;
1654 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
1655 char *fifo = g_build_filename(tmp_path, "fifo", NULL);
1656 char *out = g_build_filename(tmp_path, "out", NULL);
1657 ChardevFile file = { .in = fifo,
1658 .out = out };
1659 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
1660 .u.file.data = &file };
1661 FeHandler fe = { 0, };
1662 int fd, ret;
1663
1664 if (mkfifo(fifo, 0600) < 0) {
1665 abort();
1666 }
1667
1668 fd = open(fifo, O_RDWR);
1669 ret = write(fd, "fifo-in", 8);
1670 g_assert_cmpint(ret, ==, 8);
1671
1672 chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
1673 NULL, &error_abort);
1674
1675 qemu_chr_fe_init(&be, chr, &error_abort);
1676 qemu_chr_fe_set_handlers(&be,
1677 fe_can_read,
1678 fe_read,
1679 fe_event,
1680 NULL,
1681 &fe, NULL, true);
1682
1683 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
1684 qmp_chardev_send_break("label-foo", NULL);
1685 g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
1686 qmp_chardev_send_break("label-file", NULL);
1687 g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
1688
1689 main_loop();
1690
1691 close(fd);
1692
1693 g_assert_cmpint(fe.read_count, ==, 8);
1694 g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
1695
1696 qemu_chr_fe_deinit(&be, true);
1697
1698 g_unlink(fifo);
1699 g_free(fifo);
1700 g_unlink(out);
1701 g_free(out);
1702 g_rmdir(tmp_path);
1703 g_free(tmp_path);
1704 }
1705 #endif
1706
char_file_test_internal(Chardev * ext_chr,const char * filepath)1707 static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
1708 {
1709 char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
1710 char *out;
1711 Chardev *chr;
1712 char *contents = NULL;
1713 ChardevFile file = {};
1714 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
1715 .u.file.data = &file };
1716 gsize length;
1717 int ret;
1718
1719 if (ext_chr) {
1720 chr = ext_chr;
1721 out = g_strdup(filepath);
1722 file.out = out;
1723 } else {
1724 out = g_build_filename(tmp_path, "out", NULL);
1725 file.out = out;
1726 chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
1727 NULL, &error_abort);
1728 }
1729 ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
1730 g_assert_cmpint(ret, ==, 6);
1731
1732 ret = g_file_get_contents(out, &contents, &length, NULL);
1733 g_assert(ret == TRUE);
1734 g_assert_cmpint(length, ==, 6);
1735 g_assert(strncmp(contents, "hello!", 6) == 0);
1736
1737 if (!ext_chr) {
1738 object_unparent(OBJECT(chr));
1739 g_unlink(out);
1740 }
1741 g_free(contents);
1742 g_rmdir(tmp_path);
1743 g_free(tmp_path);
1744 g_free(out);
1745 }
1746
char_file_test(void)1747 static void char_file_test(void)
1748 {
1749 char_file_test_internal(NULL, NULL);
1750 }
1751
char_null_test(void)1752 static void char_null_test(void)
1753 {
1754 Error *err = NULL;
1755 Chardev *chr;
1756 CharBackend be;
1757 int ret;
1758
1759 chr = qemu_chr_find("label-null");
1760 g_assert_null(chr);
1761
1762 chr = qemu_chr_new("label-null", "null", NULL);
1763 chr = qemu_chr_find("label-null");
1764 g_assert_nonnull(chr);
1765
1766 g_assert(qemu_chr_has_feature(chr,
1767 QEMU_CHAR_FEATURE_FD_PASS) == false);
1768 g_assert(qemu_chr_has_feature(chr,
1769 QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
1770
1771 /* check max avail */
1772 qemu_chr_fe_init(&be, chr, &error_abort);
1773 qemu_chr_fe_init(&be, chr, &err);
1774 error_free_or_abort(&err);
1775
1776 /* deinit & reinit */
1777 qemu_chr_fe_deinit(&be, false);
1778 qemu_chr_fe_init(&be, chr, &error_abort);
1779
1780 qemu_chr_fe_set_open(&be, true);
1781
1782 qemu_chr_fe_set_handlers(&be,
1783 fe_can_read,
1784 fe_read,
1785 fe_event,
1786 NULL,
1787 NULL, NULL, true);
1788
1789 ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
1790 g_assert_cmpint(ret, ==, 4);
1791
1792 qemu_chr_fe_deinit(&be, true);
1793 }
1794
char_invalid_test(void)1795 static void char_invalid_test(void)
1796 {
1797 Chardev *chr;
1798 g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1799 chr = qemu_chr_new("label-invalid", "invalid", NULL);
1800 g_assert_null(chr);
1801 g_unsetenv("QTEST_SILENT_ERRORS");
1802 }
1803
chardev_change(void * opaque)1804 static int chardev_change(void *opaque)
1805 {
1806 return 0;
1807 }
1808
chardev_change_denied(void * opaque)1809 static int chardev_change_denied(void *opaque)
1810 {
1811 return -1;
1812 }
1813
char_hotswap_test(void)1814 static void char_hotswap_test(void)
1815 {
1816 char *chr_args;
1817 Chardev *chr;
1818 CharBackend be;
1819
1820 gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
1821 char *filename = g_build_filename(tmp_path, "file", NULL);
1822 ChardevFile file = { .out = filename };
1823 ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
1824 .u.file.data = &file };
1825 ChardevReturn *ret;
1826
1827 int port;
1828 int sock = make_udp_socket(&port);
1829 g_assert_cmpint(sock, >=, 0);
1830
1831 chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
1832
1833 chr = qemu_chr_new("chardev", chr_args, NULL);
1834 qemu_chr_fe_init(&be, chr, &error_abort);
1835
1836 /* check that chardev operates correctly */
1837 char_udp_test_internal(chr, sock);
1838
1839 /* set the handler that denies the hotswap */
1840 qemu_chr_fe_set_handlers(&be, NULL, NULL,
1841 NULL, chardev_change_denied, NULL, NULL, true);
1842
1843 /* now, change is denied and has to keep the old backend operating */
1844 ret = qmp_chardev_change("chardev", &backend, NULL);
1845 g_assert(!ret);
1846 g_assert(be.chr == chr);
1847
1848 char_udp_test_internal(chr, sock);
1849
1850 /* now allow the change */
1851 qemu_chr_fe_set_handlers(&be, NULL, NULL,
1852 NULL, chardev_change, NULL, NULL, true);
1853
1854 /* has to succeed now */
1855 ret = qmp_chardev_change("chardev", &backend, &error_abort);
1856 g_assert(be.chr != chr);
1857
1858 close(sock);
1859 chr = be.chr;
1860
1861 /* run the file chardev test */
1862 char_file_test_internal(chr, filename);
1863
1864 object_unparent(OBJECT(chr));
1865
1866 qapi_free_ChardevReturn(ret);
1867 g_unlink(filename);
1868 g_free(filename);
1869 g_rmdir(tmp_path);
1870 g_free(tmp_path);
1871 g_free(chr_args);
1872 }
1873
1874 static SocketAddress tcpaddr = {
1875 .type = SOCKET_ADDRESS_TYPE_INET,
1876 .u.inet.host = (char *)"127.0.0.1",
1877 .u.inet.port = (char *)"0",
1878 };
1879 #ifndef WIN32
1880 static SocketAddress unixaddr = {
1881 .type = SOCKET_ADDRESS_TYPE_UNIX,
1882 .u.q_unix.path = (char *)"test-char.sock",
1883 };
1884 #endif
1885
main(int argc,char ** argv)1886 int main(int argc, char **argv)
1887 {
1888 bool has_ipv4, has_ipv6;
1889
1890 qemu_init_main_loop(&error_abort);
1891 socket_init();
1892
1893 g_test_init(&argc, &argv, NULL);
1894
1895 if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
1896 g_printerr("socket_check_protocol_support() failed\n");
1897 goto end;
1898 }
1899
1900 module_call_init(MODULE_INIT_QOM);
1901 qemu_add_opts(&qemu_chardev_opts);
1902
1903 g_test_add_func("/char/null", char_null_test);
1904 g_test_add_func("/char/invalid", char_invalid_test);
1905 g_test_add_func("/char/ringbuf", char_ringbuf_test);
1906 g_test_add_func("/char/mux", char_mux_test);
1907 g_test_add_func("/char/hub", char_hub_test);
1908 #ifdef _WIN32
1909 g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
1910 g_test_add_func("/char/console", char_console_test);
1911 #endif
1912 g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
1913 g_test_add_func("/char/stdio", char_stdio_test);
1914 #ifndef _WIN32
1915 g_test_add_func("/char/pipe", char_pipe_test);
1916 #endif
1917 g_test_add_func("/char/file", char_file_test);
1918 #ifndef _WIN32
1919 g_test_add_func("/char/file-fifo", char_file_fifo_test);
1920 #endif
1921
1922 #define SOCKET_SERVER_TEST(name, addr) \
1923 static CharSocketServerTestConfig server1 ## name = \
1924 { addr, false, false }; \
1925 static CharSocketServerTestConfig server2 ## name = \
1926 { addr, true, false }; \
1927 static CharSocketServerTestConfig server3 ## name = \
1928 { addr, false, true }; \
1929 static CharSocketServerTestConfig server4 ## name = \
1930 { addr, true, true }; \
1931 g_test_add_data_func("/char/socket/server/mainloop/" # name, \
1932 &server1 ##name, char_socket_server_test); \
1933 g_test_add_data_func("/char/socket/server/wait-conn/" # name, \
1934 &server2 ##name, char_socket_server_test); \
1935 g_test_add_data_func("/char/socket/server/mainloop-fdpass/" # name, \
1936 &server3 ##name, char_socket_server_test); \
1937 g_test_add_data_func("/char/socket/server/wait-conn-fdpass/" # name, \
1938 &server4 ##name, char_socket_server_test)
1939
1940 #define SOCKET_CLIENT_TEST(name, addr) \
1941 static CharSocketClientTestConfig client1 ## name = \
1942 { addr, NULL, false, false, char_socket_event }; \
1943 static CharSocketClientTestConfig client2 ## name = \
1944 { addr, NULL, true, false, char_socket_event }; \
1945 static CharSocketClientTestConfig client3 ## name = \
1946 { addr, ",reconnect-ms=1000", false, false, char_socket_event }; \
1947 static CharSocketClientTestConfig client4 ## name = \
1948 { addr, ",reconnect-ms=1000", true, false, char_socket_event }; \
1949 static CharSocketClientTestConfig client5 ## name = \
1950 { addr, NULL, false, true, char_socket_event }; \
1951 static CharSocketClientTestConfig client6 ## name = \
1952 { addr, NULL, true, true, char_socket_event }; \
1953 static CharSocketClientTestConfig client7 ## name = \
1954 { addr, ",reconnect-ms=1000", true, false, \
1955 char_socket_event_with_error }; \
1956 static CharSocketClientTestConfig client8 ## name = \
1957 { addr, ",reconnect-ms=1000", false, false, char_socket_event };\
1958 g_test_add_data_func("/char/socket/client/mainloop/" # name, \
1959 &client1 ##name, char_socket_client_test); \
1960 g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
1961 &client2 ##name, char_socket_client_test); \
1962 g_test_add_data_func("/char/socket/client/mainloop-reconnect/" # name, \
1963 &client3 ##name, char_socket_client_test); \
1964 g_test_add_data_func("/char/socket/client/wait-conn-reconnect/" # name, \
1965 &client4 ##name, char_socket_client_test); \
1966 g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \
1967 &client5 ##name, char_socket_client_test); \
1968 g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
1969 &client6 ##name, char_socket_client_test); \
1970 g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \
1971 &client7 ##name, char_socket_client_test); \
1972 g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
1973 &client8 ##name, char_socket_client_dupid_test)
1974
1975 if (has_ipv4) {
1976 SOCKET_SERVER_TEST(tcp, &tcpaddr);
1977 SOCKET_CLIENT_TEST(tcp, &tcpaddr);
1978 g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr,
1979 char_socket_server_two_clients_test);
1980 }
1981 #ifndef WIN32
1982 SOCKET_SERVER_TEST(unix, &unixaddr);
1983 SOCKET_CLIENT_TEST(unix, &unixaddr);
1984 g_test_add_data_func("/char/socket/server/two-clients/unix", &unixaddr,
1985 char_socket_server_two_clients_test);
1986 #endif
1987
1988 g_test_add_func("/char/udp", char_udp_test);
1989 #if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32)
1990 g_test_add_func("/char/serial", char_serial_test);
1991 #endif
1992 #if defined(HAVE_CHARDEV_PARALLEL) && !defined(WIN32)
1993 g_test_add_func("/char/parallel", char_parallel_test);
1994 #endif
1995 g_test_add_func("/char/hotswap", char_hotswap_test);
1996 g_test_add_func("/char/websocket", char_websock_test);
1997
1998 end:
1999 return g_test_run();
2000 }
2001