]> Git Repo - qemu.git/blob - tests/test-char.c
migration/multifd: sync packet_num after all thread are done
[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/module.h"
6 #include "qemu/option.h"
7 #include "qemu/sockets.h"
8 #include "chardev/char-fe.h"
9 #include "chardev/char-mux.h"
10 #include "sysemu/sysemu.h"
11 #include "qapi/error.h"
12 #include "qapi/qapi-commands-char.h"
13 #include "qapi/qmp/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
19 static bool quit;
20
21 typedef struct FeHandler {
22     int read_count;
23     bool is_open;
24     int openclose_count;
25     bool openclose_mismatch;
26     int last_event;
27     char read_buf[128];
28 } FeHandler;
29
30 static void main_loop(void)
31 {
32     quit = false;
33     do {
34         main_loop_wait(false);
35     } while (!quit);
36 }
37
38 static int fe_can_read(void *opaque)
39 {
40     FeHandler *h = opaque;
41
42     return sizeof(h->read_buf) - h->read_count;
43 }
44
45 static void fe_read(void *opaque, const uint8_t *buf, int size)
46 {
47     FeHandler *h = opaque;
48
49     g_assert_cmpint(size, <=, fe_can_read(opaque));
50
51     memcpy(h->read_buf + h->read_count, buf, size);
52     h->read_count += size;
53     quit = true;
54 }
55
56 static void fe_event(void *opaque, int event)
57 {
58     FeHandler *h = opaque;
59     bool new_open_state;
60
61     h->last_event = event;
62     switch (event) {
63     case CHR_EVENT_BREAK:
64         break;
65     case CHR_EVENT_OPENED:
66     case CHR_EVENT_CLOSED:
67         h->openclose_count++;
68         new_open_state = (event == CHR_EVENT_OPENED);
69         if (h->is_open == new_open_state) {
70             h->openclose_mismatch = true;
71         }
72         h->is_open = new_open_state;
73         /* no break */
74     default:
75         quit = true;
76         break;
77     }
78 }
79
80 #ifdef _WIN32
81 static void char_console_test_subprocess(void)
82 {
83     QemuOpts *opts;
84     Chardev *chr;
85
86     opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
87                             1, &error_abort);
88     qemu_opt_set(opts, "backend", "console", &error_abort);
89
90     chr = qemu_chr_new_from_opts(opts, NULL, NULL);
91     g_assert_nonnull(chr);
92
93     qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
94
95     qemu_opts_del(opts);
96     object_unparent(OBJECT(chr));
97 }
98
99 static void char_console_test(void)
100 {
101     g_test_trap_subprocess("/char/console/subprocess", 0, 0);
102     g_test_trap_assert_passed();
103     g_test_trap_assert_stdout("CONSOLE");
104 }
105 #endif
106 static void char_stdio_test_subprocess(void)
107 {
108     Chardev *chr;
109     CharBackend be;
110     int ret;
111
112     chr = qemu_chr_new("label", "stdio", NULL);
113     g_assert_nonnull(chr);
114
115     qemu_chr_fe_init(&be, chr, &error_abort);
116     qemu_chr_fe_set_open(&be, true);
117     ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
118     g_assert_cmpint(ret, ==, 4);
119
120     qemu_chr_fe_deinit(&be, true);
121 }
122
123 static void char_stdio_test(void)
124 {
125     g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
126     g_test_trap_assert_passed();
127     g_test_trap_assert_stdout("buf");
128 }
129
130 static void char_ringbuf_test(void)
131 {
132     QemuOpts *opts;
133     Chardev *chr;
134     CharBackend be;
135     char *data;
136     int ret;
137
138     opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
139                             1, &error_abort);
140     qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
141
142     qemu_opt_set(opts, "size", "5", &error_abort);
143     chr = qemu_chr_new_from_opts(opts, NULL, NULL);
144     g_assert_null(chr);
145     qemu_opts_del(opts);
146
147     opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
148                             1, &error_abort);
149     qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
150     qemu_opt_set(opts, "size", "2", &error_abort);
151     chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
152     g_assert_nonnull(chr);
153     qemu_opts_del(opts);
154
155     qemu_chr_fe_init(&be, chr, &error_abort);
156     ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
157     g_assert_cmpint(ret, ==, 4);
158
159     data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
160     g_assert_cmpstr(data, ==, "ff");
161     g_free(data);
162
163     data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
164     g_assert_cmpstr(data, ==, "");
165     g_free(data);
166
167     qemu_chr_fe_deinit(&be, true);
168
169     /* check alias */
170     opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
171                             1, &error_abort);
172     qemu_opt_set(opts, "backend", "memory", &error_abort);
173     qemu_opt_set(opts, "size", "2", &error_abort);
174     chr = qemu_chr_new_from_opts(opts, NULL, NULL);
175     g_assert_nonnull(chr);
176     object_unparent(OBJECT(chr));
177     qemu_opts_del(opts);
178 }
179
180 static void char_mux_test(void)
181 {
182     QemuOpts *opts;
183     Chardev *chr, *base;
184     char *data;
185     FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
186     CharBackend chr_be1, chr_be2;
187
188     opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
189                             1, &error_abort);
190     qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
191     qemu_opt_set(opts, "size", "128", &error_abort);
192     qemu_opt_set(opts, "mux", "on", &error_abort);
193     chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
194     g_assert_nonnull(chr);
195     qemu_opts_del(opts);
196
197     qemu_chr_fe_init(&chr_be1, chr, &error_abort);
198     qemu_chr_fe_set_handlers(&chr_be1,
199                              fe_can_read,
200                              fe_read,
201                              fe_event,
202                              NULL,
203                              &h1,
204                              NULL, true);
205
206     qemu_chr_fe_init(&chr_be2, chr, &error_abort);
207     qemu_chr_fe_set_handlers(&chr_be2,
208                              fe_can_read,
209                              fe_read,
210                              fe_event,
211                              NULL,
212                              &h2,
213                              NULL, true);
214     qemu_chr_fe_take_focus(&chr_be2);
215
216     base = qemu_chr_find("mux-label-base");
217     g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
218
219     qemu_chr_be_write(base, (void *)"hello", 6);
220     g_assert_cmpint(h1.read_count, ==, 0);
221     g_assert_cmpint(h2.read_count, ==, 6);
222     g_assert_cmpstr(h2.read_buf, ==, "hello");
223     h2.read_count = 0;
224
225     g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */
226     g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */
227     /* sending event on the base broadcast to all fe, historical reasons? */
228     qemu_chr_be_event(base, 42);
229     g_assert_cmpint(h1.last_event, ==, 42);
230     g_assert_cmpint(h2.last_event, ==, 42);
231     qemu_chr_be_event(chr, -1);
232     g_assert_cmpint(h1.last_event, ==, 42);
233     g_assert_cmpint(h2.last_event, ==, -1);
234
235     /* switch focus */
236     qemu_chr_be_write(base, (void *)"\1b", 2);
237     g_assert_cmpint(h1.last_event, ==, 42);
238     g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK);
239
240     qemu_chr_be_write(base, (void *)"\1c", 2);
241     g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
242     g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
243     qemu_chr_be_event(chr, -1);
244     g_assert_cmpint(h1.last_event, ==, -1);
245     g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
246
247     qemu_chr_be_write(base, (void *)"hello", 6);
248     g_assert_cmpint(h2.read_count, ==, 0);
249     g_assert_cmpint(h1.read_count, ==, 6);
250     g_assert_cmpstr(h1.read_buf, ==, "hello");
251     h1.read_count = 0;
252
253     qemu_chr_be_write(base, (void *)"\1b", 2);
254     g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK);
255     g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
256
257     /* open/close state and corresponding events */
258     g_assert_true(qemu_chr_fe_backend_open(&chr_be1));
259     g_assert_true(qemu_chr_fe_backend_open(&chr_be2));
260     g_assert_true(h1.is_open);
261     g_assert_false(h1.openclose_mismatch);
262     g_assert_true(h2.is_open);
263     g_assert_false(h2.openclose_mismatch);
264
265     h1.openclose_count = h2.openclose_count = 0;
266
267     qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
268                              NULL, NULL, false);
269     qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, NULL, NULL,
270                              NULL, NULL, false);
271     g_assert_cmpint(h1.openclose_count, ==, 0);
272     g_assert_cmpint(h2.openclose_count, ==, 0);
273
274     h1.is_open = h2.is_open = false;
275     qemu_chr_fe_set_handlers(&chr_be1,
276                              NULL,
277                              NULL,
278                              fe_event,
279                              NULL,
280                              &h1,
281                              NULL, false);
282     qemu_chr_fe_set_handlers(&chr_be2,
283                              NULL,
284                              NULL,
285                              fe_event,
286                              NULL,
287                              &h2,
288                              NULL, false);
289     g_assert_cmpint(h1.openclose_count, ==, 1);
290     g_assert_false(h1.openclose_mismatch);
291     g_assert_cmpint(h2.openclose_count, ==, 1);
292     g_assert_false(h2.openclose_mismatch);
293
294     qemu_chr_be_event(base, CHR_EVENT_CLOSED);
295     qemu_chr_be_event(base, CHR_EVENT_OPENED);
296     g_assert_cmpint(h1.openclose_count, ==, 3);
297     g_assert_false(h1.openclose_mismatch);
298     g_assert_cmpint(h2.openclose_count, ==, 3);
299     g_assert_false(h2.openclose_mismatch);
300
301     qemu_chr_fe_set_handlers(&chr_be2,
302                              fe_can_read,
303                              fe_read,
304                              fe_event,
305                              NULL,
306                              &h2,
307                              NULL, false);
308     qemu_chr_fe_set_handlers(&chr_be1,
309                              fe_can_read,
310                              fe_read,
311                              fe_event,
312                              NULL,
313                              &h1,
314                              NULL, false);
315
316     /* remove first handler */
317     qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
318                              NULL, NULL, true);
319     qemu_chr_be_write(base, (void *)"hello", 6);
320     g_assert_cmpint(h1.read_count, ==, 0);
321     g_assert_cmpint(h2.read_count, ==, 0);
322
323     qemu_chr_be_write(base, (void *)"\1c", 2);
324     qemu_chr_be_write(base, (void *)"hello", 6);
325     g_assert_cmpint(h1.read_count, ==, 0);
326     g_assert_cmpint(h2.read_count, ==, 6);
327     g_assert_cmpstr(h2.read_buf, ==, "hello");
328     h2.read_count = 0;
329
330     /* print help */
331     qemu_chr_be_write(base, (void *)"\1?", 2);
332     data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
333     g_assert_cmpint(strlen(data), !=, 0);
334     g_free(data);
335
336     qemu_chr_fe_deinit(&chr_be1, false);
337     qemu_chr_fe_deinit(&chr_be2, true);
338 }
339
340
341 static void websock_server_read(void *opaque, const uint8_t *buf, int size)
342 {
343     g_assert_cmpint(size, ==, 5);
344     g_assert(memcmp(buf, "world", size) == 0);
345     quit = true;
346 }
347
348
349 static int websock_server_can_read(void *opaque)
350 {
351     return 10;
352 }
353
354
355 static bool websock_check_http_headers(char *buf, int size)
356 {
357     int i;
358     const char *ans[] = { "HTTP/1.1 101 Switching Protocols\r\n",
359                           "Server: QEMU VNC\r\n",
360                           "Upgrade: websocket\r\n",
361                           "Connection: Upgrade\r\n",
362                           "Sec-WebSocket-Accept:",
363                           "Sec-WebSocket-Protocol: binary\r\n" };
364
365     for (i = 0; i < 6; i++) {
366         if (g_strstr_len(buf, size, ans[i]) == NULL) {
367             return false;
368         }
369     }
370
371     return true;
372 }
373
374
375 static void websock_client_read(void *opaque, const uint8_t *buf, int size)
376 {
377     const uint8_t ping[] = { 0x89, 0x85,                  /* Ping header */
378                              0x07, 0x77, 0x9e, 0xf9,      /* Masking key */
379                              0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ };
380
381     const uint8_t binary[] = { 0x82, 0x85,                  /* Binary header */
382                                0x74, 0x90, 0xb9, 0xdf,      /* Masking key */
383                                0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ };
384     Chardev *chr_client = opaque;
385
386     if (websock_check_http_headers((char *) buf, size)) {
387         qemu_chr_fe_write(chr_client->be, ping, sizeof(ping));
388     } else if (buf[0] == 0x8a && buf[1] == 0x05) {
389         g_assert(strncmp((char *) buf + 2, "hello", 5) == 0);
390         qemu_chr_fe_write(chr_client->be, binary, sizeof(binary));
391     } else {
392         g_assert(buf[0] == 0x88 && buf[1] == 0x16);
393         g_assert(strncmp((char *) buf + 4, "peer requested close", 10) == 0);
394         quit = true;
395     }
396 }
397
398
399 static int websock_client_can_read(void *opaque)
400 {
401     return 4096;
402 }
403
404
405 static void char_websock_test(void)
406 {
407     QObject *addr;
408     QDict *qdict;
409     const char *port;
410     char *tmp;
411     char *handshake_port;
412     CharBackend be;
413     CharBackend client_be;
414     Chardev *chr_client;
415     Chardev *chr = qemu_chr_new("server",
416                                 "websocket:127.0.0.1:0,server,nowait", NULL);
417     const char handshake[] = "GET / HTTP/1.1\r\n"
418                              "Upgrade: websocket\r\n"
419                              "Connection: Upgrade\r\n"
420                              "Host: localhost:%s\r\n"
421                              "Origin: http://localhost:%s\r\n"
422                              "Sec-WebSocket-Key: o9JHNiS3/0/0zYE1wa3yIw==\r\n"
423                              "Sec-WebSocket-Version: 13\r\n"
424                              "Sec-WebSocket-Protocol: binary\r\n\r\n";
425     const uint8_t close[] = { 0x88, 0x82,             /* Close header */
426                               0xef, 0xaa, 0xc5, 0x97, /* Masking key */
427                               0xec, 0x42              /* Status code */ };
428
429     addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
430     qdict = qobject_to(QDict, addr);
431     port = qdict_get_str(qdict, "port");
432     tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
433     handshake_port = g_strdup_printf(handshake, port, port);
434     qobject_unref(qdict);
435
436     qemu_chr_fe_init(&be, chr, &error_abort);
437     qemu_chr_fe_set_handlers(&be, websock_server_can_read, websock_server_read,
438                              NULL, NULL, chr, NULL, true);
439
440     chr_client = qemu_chr_new("client", tmp, NULL);
441     qemu_chr_fe_init(&client_be, chr_client, &error_abort);
442     qemu_chr_fe_set_handlers(&client_be, websock_client_can_read,
443                              websock_client_read,
444                              NULL, NULL, chr_client, NULL, true);
445     g_free(tmp);
446
447     qemu_chr_write_all(chr_client,
448                        (uint8_t *) handshake_port,
449                        strlen(handshake_port));
450     g_free(handshake_port);
451     main_loop();
452
453     g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
454     g_assert(object_property_get_bool(OBJECT(chr_client),
455                                       "connected", &error_abort));
456
457     qemu_chr_write_all(chr_client, close, sizeof(close));
458     main_loop();
459
460     object_unparent(OBJECT(chr_client));
461     object_unparent(OBJECT(chr));
462 }
463
464
465 #ifndef _WIN32
466 static void char_pipe_test(void)
467 {
468     gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
469     gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
470     Chardev *chr;
471     CharBackend be;
472     int ret, fd;
473     char buf[10];
474     FeHandler fe = { 0, };
475
476     in = g_strdup_printf("%s.in", pipe);
477     if (mkfifo(in, 0600) < 0) {
478         abort();
479     }
480     out = g_strdup_printf("%s.out", pipe);
481     if (mkfifo(out, 0600) < 0) {
482         abort();
483     }
484
485     tmp = g_strdup_printf("pipe:%s", pipe);
486     chr = qemu_chr_new("pipe", tmp, NULL);
487     g_assert_nonnull(chr);
488     g_free(tmp);
489
490     qemu_chr_fe_init(&be, chr, &error_abort);
491
492     ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
493     g_assert_cmpint(ret, ==, 9);
494
495     fd = open(out, O_RDWR);
496     ret = read(fd, buf, sizeof(buf));
497     g_assert_cmpint(ret, ==, 9);
498     g_assert_cmpstr(buf, ==, "pipe-out");
499     close(fd);
500
501     fd = open(in, O_WRONLY);
502     ret = write(fd, "pipe-in", 8);
503     g_assert_cmpint(ret, ==, 8);
504     close(fd);
505
506     qemu_chr_fe_set_handlers(&be,
507                              fe_can_read,
508                              fe_read,
509                              fe_event,
510                              NULL,
511                              &fe,
512                              NULL, true);
513
514     main_loop();
515
516     g_assert_cmpint(fe.read_count, ==, 8);
517     g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
518
519     qemu_chr_fe_deinit(&be, true);
520
521     g_assert(g_unlink(in) == 0);
522     g_assert(g_unlink(out) == 0);
523     g_assert(g_rmdir(tmp_path) == 0);
524     g_free(in);
525     g_free(out);
526     g_free(tmp_path);
527     g_free(pipe);
528 }
529 #endif
530
531 typedef struct SocketIdleData {
532     GMainLoop *loop;
533     Chardev *chr;
534     bool conn_expected;
535     CharBackend *be;
536     CharBackend *client_be;
537 } SocketIdleData;
538
539
540 static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
541 {
542     g_assert_cmpint(size, ==, 5);
543     g_assert(strncmp((char *)buf, "hello", 5) == 0);
544
545     quit = true;
546 }
547
548 static int socket_can_read_hello(void *opaque)
549 {
550     return 10;
551 }
552
553 static int make_udp_socket(int *port)
554 {
555     struct sockaddr_in addr = { 0, };
556     socklen_t alen = sizeof(addr);
557     int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
558
559     g_assert_cmpint(sock, >, 0);
560     addr.sin_family = AF_INET ;
561     addr.sin_addr.s_addr = htonl(INADDR_ANY);
562     addr.sin_port = 0;
563     ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
564     g_assert_cmpint(ret, ==, 0);
565     ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
566     g_assert_cmpint(ret, ==, 0);
567
568     *port = ntohs(addr.sin_port);
569     return sock;
570 }
571
572 static void char_udp_test_internal(Chardev *reuse_chr, int sock)
573 {
574     struct sockaddr_in other;
575     SocketIdleData d = { 0, };
576     Chardev *chr;
577     CharBackend *be;
578     socklen_t alen = sizeof(other);
579     int ret;
580     char buf[10];
581     char *tmp = NULL;
582
583     if (reuse_chr) {
584         chr = reuse_chr;
585         be = chr->be;
586     } else {
587         int port;
588         sock = make_udp_socket(&port);
589         tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
590         chr = qemu_chr_new("client", tmp, NULL);
591         g_assert_nonnull(chr);
592
593         be = g_alloca(sizeof(CharBackend));
594         qemu_chr_fe_init(be, chr, &error_abort);
595     }
596
597     d.chr = chr;
598     qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
599                              NULL, NULL, &d, NULL, true);
600     ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
601     g_assert_cmpint(ret, ==, 5);
602
603     ret = recvfrom(sock, buf, sizeof(buf), 0,
604                    (struct sockaddr *)&other, &alen);
605     g_assert_cmpint(ret, ==, 5);
606     ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
607     g_assert_cmpint(ret, ==, 5);
608
609     main_loop();
610
611     if (!reuse_chr) {
612         close(sock);
613         qemu_chr_fe_deinit(be, true);
614     }
615     g_free(tmp);
616 }
617
618 static void char_udp_test(void)
619 {
620     char_udp_test_internal(NULL, 0);
621 }
622
623
624 typedef struct {
625     int event;
626     bool got_pong;
627 } CharSocketTestData;
628
629
630 #define SOCKET_PING "Hello"
631 #define SOCKET_PONG "World"
632
633
634 static void
635 char_socket_event(void *opaque, int event)
636 {
637     CharSocketTestData *data = opaque;
638     data->event = event;
639 }
640
641
642 static void
643 char_socket_read(void *opaque, const uint8_t *buf, int size)
644 {
645     CharSocketTestData *data = opaque;
646     g_assert_cmpint(size, ==, sizeof(SOCKET_PONG));
647     g_assert(memcmp(buf, SOCKET_PONG, size) == 0);
648     data->got_pong = true;
649 }
650
651
652 static int
653 char_socket_can_read(void *opaque)
654 {
655     return sizeof(SOCKET_PONG);
656 }
657
658
659 static char *
660 char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass,
661                             const char *reconnect, bool is_listen)
662 {
663     if (fd_pass) {
664         QIOChannelSocket *ioc = qio_channel_socket_new();
665         int fd;
666         char *optstr;
667         g_assert(!reconnect);
668         if (is_listen) {
669             qio_channel_socket_listen_sync(ioc, addr, &error_abort);
670         } else {
671             qio_channel_socket_connect_sync(ioc, addr, &error_abort);
672         }
673         fd = ioc->fd;
674         ioc->fd = -1;
675         optstr = g_strdup_printf("socket,id=cdev0,fd=%d%s",
676                                  fd, is_listen ? ",server,nowait" : "");
677         object_unref(OBJECT(ioc));
678         return optstr;
679     } else {
680         switch (addr->type) {
681         case SOCKET_ADDRESS_TYPE_INET:
682             return g_strdup_printf("socket,id=cdev0,host=%s,port=%s%s%s",
683                                    addr->u.inet.host,
684                                    addr->u.inet.port,
685                                    reconnect ? reconnect : "",
686                                    is_listen ? ",server,nowait" : "");
687
688         case SOCKET_ADDRESS_TYPE_UNIX:
689             return g_strdup_printf("socket,id=cdev0,path=%s%s%s",
690                                    addr->u.q_unix.path,
691                                    reconnect ? reconnect : "",
692                                    is_listen ? ",server,nowait" : "");
693
694         default:
695             g_assert_not_reached();
696         }
697     }
698 }
699
700
701 static void
702 char_socket_ping_pong(QIOChannel *ioc)
703 {
704     char greeting[sizeof(SOCKET_PING)];
705     const char *response = SOCKET_PONG;
706
707     qio_channel_read_all(ioc, greeting, sizeof(greeting), &error_abort);
708
709     g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0);
710
711     qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), &error_abort);
712
713     object_unref(OBJECT(ioc));
714 }
715
716
717 static gpointer
718 char_socket_server_client_thread(gpointer data)
719 {
720     SocketAddress *addr = data;
721     QIOChannelSocket *ioc = qio_channel_socket_new();
722
723     qio_channel_socket_connect_sync(ioc, addr, &error_abort);
724
725     char_socket_ping_pong(QIO_CHANNEL(ioc));
726
727     return NULL;
728 }
729
730
731 typedef struct {
732     SocketAddress *addr;
733     bool wait_connected;
734     bool fd_pass;
735 } CharSocketServerTestConfig;
736
737
738 static void char_socket_server_test(gconstpointer opaque)
739 {
740     const CharSocketServerTestConfig *config = opaque;
741     Chardev *chr;
742     CharBackend be = {0};
743     CharSocketTestData data = {0};
744     QObject *qaddr;
745     SocketAddress *addr;
746     Visitor *v;
747     QemuThread thread;
748     int ret;
749     bool reconnected = false;
750     char *optstr;
751     QemuOpts *opts;
752
753     g_setenv("QTEST_SILENT_ERRORS", "1", 1);
754     /*
755      * We rely on config->addr containing "nowait", otherwise
756      * qemu_chr_new() will block until a client connects. We
757      * can't spawn our client thread though, because until
758      * qemu_chr_new() returns we don't know what TCP port was
759      * allocated by the OS
760      */
761     optstr = char_socket_addr_to_opt_str(config->addr,
762                                          config->fd_pass,
763                                          NULL,
764                                          true);
765     opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
766                                    optstr, true);
767     g_assert_nonnull(opts);
768     chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
769     qemu_opts_del(opts);
770     g_assert_nonnull(chr);
771     g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
772
773     qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
774     g_assert_nonnull(qaddr);
775
776     v = qobject_input_visitor_new(qaddr);
777     visit_type_SocketAddress(v, "addr", &addr, &error_abort);
778     visit_free(v);
779     qobject_unref(qaddr);
780
781     qemu_chr_fe_init(&be, chr, &error_abort);
782
783  reconnect:
784     data.event = -1;
785     qemu_chr_fe_set_handlers(&be, NULL, NULL,
786                              char_socket_event, NULL,
787                              &data, NULL, true);
788     g_assert(data.event == -1);
789
790     /*
791      * Kick off a thread to act as the "remote" client
792      * which just plays ping-pong with us
793      */
794     qemu_thread_create(&thread, "client",
795                        char_socket_server_client_thread,
796                        addr, QEMU_THREAD_JOINABLE);
797     g_assert(data.event == -1);
798
799     if (config->wait_connected) {
800         /* Synchronously accept a connection */
801         qemu_chr_wait_connected(chr, &error_abort);
802     } else {
803         /*
804          * Asynchronously accept a connection when the evnt
805          * loop reports the listener socket as readable
806          */
807         while (data.event == -1) {
808             main_loop_wait(false);
809         }
810     }
811     g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
812     g_assert(data.event == CHR_EVENT_OPENED);
813     data.event = -1;
814
815     /* Send a greeting to the client */
816     ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING,
817                                 sizeof(SOCKET_PING));
818     g_assert_cmpint(ret, ==, sizeof(SOCKET_PING));
819     g_assert(data.event == -1);
820
821     /* Setup a callback to receive the reply to our greeting */
822     qemu_chr_fe_set_handlers(&be, char_socket_can_read,
823                              char_socket_read,
824                              char_socket_event, NULL,
825                              &data, NULL, true);
826     g_assert(data.event == CHR_EVENT_OPENED);
827     data.event = -1;
828
829     /* Wait for the client to go away */
830     while (data.event == -1) {
831         main_loop_wait(false);
832     }
833     g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
834     g_assert(data.event == CHR_EVENT_CLOSED);
835     g_assert(data.got_pong);
836
837     qemu_thread_join(&thread);
838
839     if (!reconnected) {
840         reconnected = true;
841         goto reconnect;
842     }
843
844     qapi_free_SocketAddress(addr);
845     object_unparent(OBJECT(chr));
846     g_free(optstr);
847     g_unsetenv("QTEST_SILENT_ERRORS");
848 }
849
850
851 static gpointer
852 char_socket_client_server_thread(gpointer data)
853 {
854     QIOChannelSocket *ioc = data;
855     QIOChannelSocket *cioc;
856
857     cioc = qio_channel_socket_accept(ioc, &error_abort);
858     g_assert_nonnull(cioc);
859
860     char_socket_ping_pong(QIO_CHANNEL(cioc));
861
862     return NULL;
863 }
864
865
866 typedef struct {
867     SocketAddress *addr;
868     const char *reconnect;
869     bool wait_connected;
870     bool fd_pass;
871 } CharSocketClientTestConfig;
872
873
874 static void char_socket_client_test(gconstpointer opaque)
875 {
876     const CharSocketClientTestConfig *config = opaque;
877     QIOChannelSocket *ioc;
878     char *optstr;
879     Chardev *chr;
880     CharBackend be = {0};
881     CharSocketTestData data = {0};
882     SocketAddress *addr;
883     QemuThread thread;
884     int ret;
885     bool reconnected = false;
886     QemuOpts *opts;
887
888     /*
889      * Setup a listener socket and determine get its address
890      * so we know the TCP port for the client later
891      */
892     ioc = qio_channel_socket_new();
893     g_assert_nonnull(ioc);
894     qio_channel_socket_listen_sync(ioc, config->addr, &error_abort);
895     addr = qio_channel_socket_get_local_address(ioc, &error_abort);
896     g_assert_nonnull(addr);
897
898     /*
899      * Kick off a thread to act as the "remote" client
900      * which just plays ping-pong with us
901      */
902     qemu_thread_create(&thread, "client",
903                        char_socket_client_server_thread,
904                        ioc, QEMU_THREAD_JOINABLE);
905
906     /*
907      * Populate the chardev address based on what the server
908      * is actually listening on
909      */
910     optstr = char_socket_addr_to_opt_str(addr,
911                                          config->fd_pass,
912                                          config->reconnect,
913                                          false);
914
915     opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
916                                    optstr, true);
917     g_assert_nonnull(opts);
918     chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
919     qemu_opts_del(opts);
920     g_assert_nonnull(chr);
921
922     if (config->reconnect) {
923         /*
924          * If reconnect is set, the connection will be
925          * established in a background thread and we won't
926          * see the "connected" status updated until we
927          * run the main event loop, or call qemu_chr_wait_connected
928          */
929         g_assert(!object_property_get_bool(OBJECT(chr), "connected",
930                                            &error_abort));
931     } else {
932         g_assert(object_property_get_bool(OBJECT(chr), "connected",
933                                           &error_abort));
934     }
935
936     qemu_chr_fe_init(&be, chr, &error_abort);
937
938  reconnect:
939     data.event = -1;
940     qemu_chr_fe_set_handlers(&be, NULL, NULL,
941                              char_socket_event, NULL,
942                              &data, NULL, true);
943     if (config->reconnect) {
944         g_assert(data.event == -1);
945     } else {
946         g_assert(data.event == CHR_EVENT_OPENED);
947     }
948
949     if (config->wait_connected) {
950         /*
951          * Synchronously wait for the connection to complete
952          * This should be a no-op if reconnect is not set.
953          */
954         qemu_chr_wait_connected(chr, &error_abort);
955     } else {
956         /*
957          * Asynchronously wait for the connection to be reported
958          * as complete when the background thread reports its
959          * status.
960          * The loop will short-circuit if reconnect was set
961          */
962         while (data.event == -1) {
963             main_loop_wait(false);
964         }
965     }
966     g_assert(data.event == CHR_EVENT_OPENED);
967     data.event = -1;
968     g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
969
970     /* Send a greeting to the server */
971     ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING,
972                                 sizeof(SOCKET_PING));
973     g_assert_cmpint(ret, ==, sizeof(SOCKET_PING));
974     g_assert(data.event == -1);
975
976     /* Setup a callback to receive the reply to our greeting */
977     qemu_chr_fe_set_handlers(&be, char_socket_can_read,
978                              char_socket_read,
979                              char_socket_event, NULL,
980                              &data, NULL, true);
981     g_assert(data.event == CHR_EVENT_OPENED);
982     data.event = -1;
983
984     /* Wait for the server to go away */
985     while (data.event == -1) {
986         main_loop_wait(false);
987     }
988     g_assert(data.event == CHR_EVENT_CLOSED);
989     g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
990     g_assert(data.got_pong);
991     qemu_thread_join(&thread);
992
993     if (config->reconnect && !reconnected) {
994         reconnected = true;
995         qemu_thread_create(&thread, "client",
996                            char_socket_client_server_thread,
997                            ioc, QEMU_THREAD_JOINABLE);
998         goto reconnect;
999     }
1000
1001     object_unref(OBJECT(ioc));
1002     object_unparent(OBJECT(chr));
1003     qapi_free_SocketAddress(addr);
1004     g_free(optstr);
1005 }
1006
1007 static void
1008 count_closed_event(void *opaque, int event)
1009 {
1010     int *count = opaque;
1011     if (event == CHR_EVENT_CLOSED) {
1012         (*count)++;
1013     }
1014 }
1015
1016 static void
1017 char_socket_discard_read(void *opaque, const uint8_t *buf, int size)
1018 {
1019 }
1020
1021 static void char_socket_server_two_clients_test(gconstpointer opaque)
1022 {
1023     SocketAddress *incoming_addr = (gpointer) opaque;
1024     Chardev *chr;
1025     CharBackend be = {0};
1026     QObject *qaddr;
1027     SocketAddress *addr;
1028     Visitor *v;
1029     char *optstr;
1030     QemuOpts *opts;
1031     QIOChannelSocket *ioc1, *ioc2;
1032     int closed = 0;
1033
1034     g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1035     /*
1036      * We rely on addr containing "nowait", otherwise
1037      * qemu_chr_new() will block until a client connects. We
1038      * can't spawn our client thread though, because until
1039      * qemu_chr_new() returns we don't know what TCP port was
1040      * allocated by the OS
1041      */
1042     optstr = char_socket_addr_to_opt_str(incoming_addr,
1043                                          false,
1044                                          NULL,
1045                                          true);
1046     opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
1047                                    optstr, true);
1048     g_assert_nonnull(opts);
1049     chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
1050     qemu_opts_del(opts);
1051     g_assert_nonnull(chr);
1052     g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
1053
1054     qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
1055     g_assert_nonnull(qaddr);
1056
1057     v = qobject_input_visitor_new(qaddr);
1058     visit_type_SocketAddress(v, "addr", &addr, &error_abort);
1059     visit_free(v);
1060     qobject_unref(qaddr);
1061
1062     qemu_chr_fe_init(&be, chr, &error_abort);
1063
1064     qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read,
1065                              count_closed_event, NULL,
1066                              &closed, NULL, true);
1067
1068     ioc1 = qio_channel_socket_new();
1069     qio_channel_socket_connect_sync(ioc1, addr, &error_abort);
1070     qemu_chr_wait_connected(chr, &error_abort);
1071
1072     /* switch the chardev to another context */
1073     GMainContext *ctx = g_main_context_new();
1074     qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read,
1075                              count_closed_event, NULL,
1076                              &closed, ctx, true);
1077
1078     /* Start a second connection while the first is still connected.
1079      * It will be placed in the listen() backlog, and connect() will
1080      * succeed immediately.
1081      */
1082     ioc2 = qio_channel_socket_new();
1083     qio_channel_socket_connect_sync(ioc2, addr, &error_abort);
1084
1085     object_unref(OBJECT(ioc1));
1086     /* The two connections should now be processed serially.  */
1087     while (g_main_context_iteration(ctx, TRUE)) {
1088         if (closed == 1 && ioc2) {
1089             object_unref(OBJECT(ioc2));
1090             ioc2 = NULL;
1091         }
1092         if (closed == 2) {
1093             break;
1094         }
1095     }
1096
1097     qapi_free_SocketAddress(addr);
1098     object_unparent(OBJECT(chr));
1099     g_main_context_unref(ctx);
1100     g_free(optstr);
1101     g_unsetenv("QTEST_SILENT_ERRORS");
1102 }
1103
1104
1105 #ifdef HAVE_CHARDEV_SERIAL
1106 static void char_serial_test(void)
1107 {
1108     QemuOpts *opts;
1109     Chardev *chr;
1110
1111     opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
1112                             1, &error_abort);
1113     qemu_opt_set(opts, "backend", "serial", &error_abort);
1114     qemu_opt_set(opts, "path", "/dev/null", &error_abort);
1115
1116     chr = qemu_chr_new_from_opts(opts, NULL, NULL);
1117     g_assert_nonnull(chr);
1118     /* TODO: add more tests with a pty */
1119     object_unparent(OBJECT(chr));
1120
1121     /* test tty alias */
1122     qemu_opt_set(opts, "backend", "tty", &error_abort);
1123     chr = qemu_chr_new_from_opts(opts, NULL, NULL);
1124     g_assert_nonnull(chr);
1125     object_unparent(OBJECT(chr));
1126
1127     qemu_opts_del(opts);
1128 }
1129 #endif
1130
1131 #ifndef _WIN32
1132 static void char_file_fifo_test(void)
1133 {
1134     Chardev *chr;
1135     CharBackend be;
1136     char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
1137     char *fifo = g_build_filename(tmp_path, "fifo", NULL);
1138     char *out = g_build_filename(tmp_path, "out", NULL);
1139     ChardevFile file = { .in = fifo,
1140                          .has_in = true,
1141                          .out = out };
1142     ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
1143                                .u.file.data = &file };
1144     FeHandler fe = { 0, };
1145     int fd, ret;
1146
1147     if (mkfifo(fifo, 0600) < 0) {
1148         abort();
1149     }
1150
1151     fd = open(fifo, O_RDWR);
1152     ret = write(fd, "fifo-in", 8);
1153     g_assert_cmpint(ret, ==, 8);
1154
1155     chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
1156                            NULL, &error_abort);
1157
1158     qemu_chr_fe_init(&be, chr, &error_abort);
1159     qemu_chr_fe_set_handlers(&be,
1160                              fe_can_read,
1161                              fe_read,
1162                              fe_event,
1163                              NULL,
1164                              &fe, NULL, true);
1165
1166     g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
1167     qmp_chardev_send_break("label-foo", NULL);
1168     g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
1169     qmp_chardev_send_break("label-file", NULL);
1170     g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
1171
1172     main_loop();
1173
1174     close(fd);
1175
1176     g_assert_cmpint(fe.read_count, ==, 8);
1177     g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
1178
1179     qemu_chr_fe_deinit(&be, true);
1180
1181     g_unlink(fifo);
1182     g_free(fifo);
1183     g_unlink(out);
1184     g_free(out);
1185     g_rmdir(tmp_path);
1186     g_free(tmp_path);
1187 }
1188 #endif
1189
1190 static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
1191 {
1192     char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
1193     char *out;
1194     Chardev *chr;
1195     char *contents = NULL;
1196     ChardevFile file = {};
1197     ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
1198                                .u.file.data = &file };
1199     gsize length;
1200     int ret;
1201
1202     if (ext_chr) {
1203         chr = ext_chr;
1204         out = g_strdup(filepath);
1205         file.out = out;
1206     } else {
1207         out = g_build_filename(tmp_path, "out", NULL);
1208         file.out = out;
1209         chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
1210                                NULL, &error_abort);
1211     }
1212     ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
1213     g_assert_cmpint(ret, ==, 6);
1214
1215     ret = g_file_get_contents(out, &contents, &length, NULL);
1216     g_assert(ret == TRUE);
1217     g_assert_cmpint(length, ==, 6);
1218     g_assert(strncmp(contents, "hello!", 6) == 0);
1219
1220     if (!ext_chr) {
1221         object_unref(OBJECT(chr));
1222         g_unlink(out);
1223     }
1224     g_free(contents);
1225     g_rmdir(tmp_path);
1226     g_free(tmp_path);
1227     g_free(out);
1228 }
1229
1230 static void char_file_test(void)
1231 {
1232     char_file_test_internal(NULL, NULL);
1233 }
1234
1235 static void char_null_test(void)
1236 {
1237     Error *err = NULL;
1238     Chardev *chr;
1239     CharBackend be;
1240     int ret;
1241
1242     chr = qemu_chr_find("label-null");
1243     g_assert_null(chr);
1244
1245     chr = qemu_chr_new("label-null", "null", NULL);
1246     chr = qemu_chr_find("label-null");
1247     g_assert_nonnull(chr);
1248
1249     g_assert(qemu_chr_has_feature(chr,
1250                  QEMU_CHAR_FEATURE_FD_PASS) == false);
1251     g_assert(qemu_chr_has_feature(chr,
1252                  QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
1253
1254     /* check max avail */
1255     qemu_chr_fe_init(&be, chr, &error_abort);
1256     qemu_chr_fe_init(&be, chr, &err);
1257     error_free_or_abort(&err);
1258
1259     /* deinit & reinit */
1260     qemu_chr_fe_deinit(&be, false);
1261     qemu_chr_fe_init(&be, chr, &error_abort);
1262
1263     qemu_chr_fe_set_open(&be, true);
1264
1265     qemu_chr_fe_set_handlers(&be,
1266                              fe_can_read,
1267                              fe_read,
1268                              fe_event,
1269                              NULL,
1270                              NULL, NULL, true);
1271
1272     ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
1273     g_assert_cmpint(ret, ==, 4);
1274
1275     qemu_chr_fe_deinit(&be, true);
1276 }
1277
1278 static void char_invalid_test(void)
1279 {
1280     Chardev *chr;
1281     g_setenv("QTEST_SILENT_ERRORS", "1", 1);
1282     chr = qemu_chr_new("label-invalid", "invalid", NULL);
1283     g_assert_null(chr);
1284     g_unsetenv("QTEST_SILENT_ERRORS");
1285 }
1286
1287 static int chardev_change(void *opaque)
1288 {
1289     return 0;
1290 }
1291
1292 static int chardev_change_denied(void *opaque)
1293 {
1294     return -1;
1295 }
1296
1297 static void char_hotswap_test(void)
1298 {
1299     char *chr_args;
1300     Chardev *chr;
1301     CharBackend be;
1302
1303     gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
1304     char *filename = g_build_filename(tmp_path, "file", NULL);
1305     ChardevFile file = { .out = filename };
1306     ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
1307                                .u.file.data = &file };
1308     ChardevReturn *ret;
1309
1310     int port;
1311     int sock = make_udp_socket(&port);
1312     g_assert_cmpint(sock, >, 0);
1313
1314     chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
1315
1316     chr = qemu_chr_new("chardev", chr_args, NULL);
1317     qemu_chr_fe_init(&be, chr, &error_abort);
1318
1319     /* check that chardev operates correctly */
1320     char_udp_test_internal(chr, sock);
1321
1322     /* set the handler that denies the hotswap */
1323     qemu_chr_fe_set_handlers(&be, NULL, NULL,
1324                              NULL, chardev_change_denied, NULL, NULL, true);
1325
1326     /* now, change is denied and has to keep the old backend operating */
1327     ret = qmp_chardev_change("chardev", &backend, NULL);
1328     g_assert(!ret);
1329     g_assert(be.chr == chr);
1330
1331     char_udp_test_internal(chr, sock);
1332
1333     /* now allow the change */
1334     qemu_chr_fe_set_handlers(&be, NULL, NULL,
1335                              NULL, chardev_change, NULL, NULL, true);
1336
1337     /* has to succeed now */
1338     ret = qmp_chardev_change("chardev", &backend, &error_abort);
1339     g_assert(be.chr != chr);
1340
1341     close(sock);
1342     chr = be.chr;
1343
1344     /* run the file chardev test */
1345     char_file_test_internal(chr, filename);
1346
1347     object_unparent(OBJECT(chr));
1348
1349     qapi_free_ChardevReturn(ret);
1350     g_unlink(filename);
1351     g_free(filename);
1352     g_rmdir(tmp_path);
1353     g_free(tmp_path);
1354     g_free(chr_args);
1355 }
1356
1357 int main(int argc, char **argv)
1358 {
1359     qemu_init_main_loop(&error_abort);
1360     socket_init();
1361
1362     g_test_init(&argc, &argv, NULL);
1363
1364     module_call_init(MODULE_INIT_QOM);
1365     qemu_add_opts(&qemu_chardev_opts);
1366
1367     g_test_add_func("/char/null", char_null_test);
1368     g_test_add_func("/char/invalid", char_invalid_test);
1369     g_test_add_func("/char/ringbuf", char_ringbuf_test);
1370     g_test_add_func("/char/mux", char_mux_test);
1371 #ifdef _WIN32
1372     g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
1373     g_test_add_func("/char/console", char_console_test);
1374 #endif
1375     g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
1376     g_test_add_func("/char/stdio", char_stdio_test);
1377 #ifndef _WIN32
1378     g_test_add_func("/char/pipe", char_pipe_test);
1379 #endif
1380     g_test_add_func("/char/file", char_file_test);
1381 #ifndef _WIN32
1382     g_test_add_func("/char/file-fifo", char_file_fifo_test);
1383 #endif
1384
1385     SocketAddress tcpaddr = {
1386         .type = SOCKET_ADDRESS_TYPE_INET,
1387         .u.inet.host = (char *)"127.0.0.1",
1388         .u.inet.port = (char *)"0",
1389     };
1390 #ifndef WIN32
1391     SocketAddress unixaddr = {
1392         .type = SOCKET_ADDRESS_TYPE_UNIX,
1393         .u.q_unix.path = (char *)"test-char.sock",
1394     };
1395 #endif
1396
1397 #define SOCKET_SERVER_TEST(name, addr)                                  \
1398     CharSocketServerTestConfig server1 ## name =                        \
1399         { addr, false, false };                                         \
1400     CharSocketServerTestConfig server2 ## name =                        \
1401         { addr, true, false };                                          \
1402     CharSocketServerTestConfig server3 ## name =                        \
1403         { addr, false, true };                                          \
1404     CharSocketServerTestConfig server4 ## name =                        \
1405         { addr, true, true };                                           \
1406     g_test_add_data_func("/char/socket/server/mainloop/" # name,        \
1407                          &server1 ##name, char_socket_server_test);     \
1408     g_test_add_data_func("/char/socket/server/wait-conn/" # name,       \
1409                          &server2 ##name, char_socket_server_test);     \
1410     g_test_add_data_func("/char/socket/server/mainloop-fdpass/" # name, \
1411                          &server3 ##name, char_socket_server_test);     \
1412     g_test_add_data_func("/char/socket/server/wait-conn-fdpass/" # name, \
1413                          &server4 ##name, char_socket_server_test)
1414
1415 #define SOCKET_CLIENT_TEST(name, addr)                                  \
1416     CharSocketClientTestConfig client1 ## name =                        \
1417         { addr, NULL, false, false };                                   \
1418     CharSocketClientTestConfig client2 ## name =                        \
1419         { addr, NULL, true, false };                                    \
1420     CharSocketClientTestConfig client3 ## name =                        \
1421         { addr, ",reconnect=1", false };                                \
1422     CharSocketClientTestConfig client4 ## name =                        \
1423         { addr, ",reconnect=1", true };                                 \
1424     CharSocketClientTestConfig client5 ## name =                        \
1425         { addr, NULL, false, true };                                    \
1426     CharSocketClientTestConfig client6 ## name =                        \
1427         { addr, NULL, true, true };                                     \
1428     g_test_add_data_func("/char/socket/client/mainloop/" # name,        \
1429                          &client1 ##name, char_socket_client_test);     \
1430     g_test_add_data_func("/char/socket/client/wait-conn/" # name,       \
1431                          &client2 ##name, char_socket_client_test);     \
1432     g_test_add_data_func("/char/socket/client/mainloop-reconnect/" # name, \
1433                          &client3 ##name, char_socket_client_test);     \
1434     g_test_add_data_func("/char/socket/client/wait-conn-reconnect/" # name, \
1435                          &client4 ##name, char_socket_client_test);     \
1436     g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \
1437                          &client5 ##name, char_socket_client_test);     \
1438     g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
1439                          &client6 ##name, char_socket_client_test)
1440
1441     SOCKET_SERVER_TEST(tcp, &tcpaddr);
1442     SOCKET_CLIENT_TEST(tcp, &tcpaddr);
1443     g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr,
1444                          char_socket_server_two_clients_test);
1445 #ifndef WIN32
1446     SOCKET_SERVER_TEST(unix, &unixaddr);
1447     SOCKET_CLIENT_TEST(unix, &unixaddr);
1448     g_test_add_data_func("/char/socket/server/two-clients/unix", &unixaddr,
1449                          char_socket_server_two_clients_test);
1450 #endif
1451
1452     g_test_add_func("/char/udp", char_udp_test);
1453 #ifdef HAVE_CHARDEV_SERIAL
1454     g_test_add_func("/char/serial", char_serial_test);
1455 #endif
1456     g_test_add_func("/char/hotswap", char_hotswap_test);
1457     g_test_add_func("/char/websocket", char_websock_test);
1458
1459     return g_test_run();
1460 }
This page took 0.112125 seconds and 4 git commands to generate.