qemu-e2k/tests/unit/test-char.c

1555 lines
47 KiB
C
Raw Permalink Normal View History

#include "qemu/osdep.h"
#include <glib/gstdio.h>
#include "qemu/config-file.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/sockets.h"
#include "chardev/char-fe.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-char.h"
#include "qapi/qmp/qdict.h"
#include "qom/qom-qobject.h"
#include "io/channel-socket.h"
#include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-sockets.h"
#include "socket-helpers.h"
static bool quit;
typedef struct FeHandler {
int read_count;
bool is_open;
int openclose_count;
bool openclose_mismatch;
int last_event;
char read_buf[128];
} FeHandler;
static void main_loop(void)
{
quit = false;
do {
main_loop_wait(false);
} while (!quit);
}
static int fe_can_read(void *opaque)
{
FeHandler *h = opaque;
return sizeof(h->read_buf) - h->read_count;
}
static void fe_read(void *opaque, const uint8_t *buf, int size)
{
FeHandler *h = opaque;
g_assert_cmpint(size, <=, fe_can_read(opaque));
memcpy(h->read_buf + h->read_count, buf, size);
h->read_count += size;
quit = true;
}
static void fe_event(void *opaque, QEMUChrEvent event)
{
FeHandler *h = opaque;
bool new_open_state;
h->last_event = event;
switch (event) {
case CHR_EVENT_BREAK:
break;
case CHR_EVENT_OPENED:
case CHR_EVENT_CLOSED:
h->openclose_count++;
new_open_state = (event == CHR_EVENT_OPENED);
if (h->is_open == new_open_state) {
h->openclose_mismatch = true;
}
h->is_open = new_open_state;
/* fallthrough */
default:
quit = true;
break;
}
}
#ifdef _WIN32
static void char_console_test_subprocess(void)
{
QemuOpts *opts;
Chardev *chr;
opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "console", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL, NULL);
g_assert_nonnull(chr);
qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
qemu_opts_del(opts);
object_unparent(OBJECT(chr));
}
static void char_console_test(void)
{
g_test_trap_subprocess("/char/console/subprocess", 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stdout("CONSOLE");
}
#endif
static void char_stdio_test_subprocess(void)
{
Chardev *chr;
CharBackend be;
int ret;
chr = qemu_chr_new("label", "stdio", NULL);
g_assert_nonnull(chr);
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_open(&be, true);
ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
g_assert_cmpint(ret, ==, 4);
qemu_chr_fe_deinit(&be, true);
}
static void char_stdio_test(void)
{
g_test_trap_subprocess("/char/stdio/subprocess", 0, 0);
g_test_trap_assert_passed();
g_test_trap_assert_stdout("buf");
}
static void char_ringbuf_test(void)
{
QemuOpts *opts;
Chardev *chr;
CharBackend be;
char *data;
int ret;
opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "5", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL, NULL);
g_assert_null(chr);
qemu_opts_del(opts);
opts = qemu_opts_create(qemu_find_opts("chardev"), "ringbuf-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "2", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
g_assert_nonnull(chr);
qemu_opts_del(opts);
qemu_chr_fe_init(&be, chr, &error_abort);
ret = qemu_chr_fe_write(&be, (void *)"buff", 4);
g_assert_cmpint(ret, ==, 4);
data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
g_assert_cmpstr(data, ==, "ff");
g_free(data);
data = qmp_ringbuf_read("ringbuf-label", 4, false, 0, &error_abort);
g_assert_cmpstr(data, ==, "");
g_free(data);
qemu_chr_fe_deinit(&be, true);
/* check alias */
opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "memory", &error_abort);
qemu_opt_set(opts, "size", "2", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL, NULL);
g_assert_nonnull(chr);
object_unparent(OBJECT(chr));
qemu_opts_del(opts);
}
static void char_mux_test(void)
{
QemuOpts *opts;
Chardev *chr, *base;
char *data;
FeHandler h1 = { 0, false, 0, false, }, h2 = { 0, false, 0, false, };
CharBackend chr_be1, chr_be2;
opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label",
1, &error_abort);
qemu_opt_set(opts, "backend", "ringbuf", &error_abort);
qemu_opt_set(opts, "size", "128", &error_abort);
qemu_opt_set(opts, "mux", "on", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
g_assert_nonnull(chr);
qemu_opts_del(opts);
qemu_chr_fe_init(&chr_be1, chr, &error_abort);
qemu_chr_fe_set_handlers(&chr_be1,
fe_can_read,
fe_read,
fe_event,
NULL,
&h1,
NULL, true);
qemu_chr_fe_init(&chr_be2, chr, &error_abort);
qemu_chr_fe_set_handlers(&chr_be2,
fe_can_read,
fe_read,
fe_event,
NULL,
&h2,
NULL, true);
qemu_chr_fe_take_focus(&chr_be2);
base = qemu_chr_find("mux-label-base");
g_assert_cmpint(qemu_chr_be_can_write(base), !=, 0);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 6);
g_assert_cmpstr(h2.read_buf, ==, "hello");
h2.read_count = 0;
g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */
g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */
/* sending event on the base broadcast to all fe, historical reasons? */
qemu_chr_be_event(base, 42);
g_assert_cmpint(h1.last_event, ==, 42);
g_assert_cmpint(h2.last_event, ==, 42);
qemu_chr_be_event(chr, -1);
g_assert_cmpint(h1.last_event, ==, 42);
g_assert_cmpint(h2.last_event, ==, -1);
/* switch focus */
qemu_chr_be_write(base, (void *)"\1b", 2);
g_assert_cmpint(h1.last_event, ==, 42);
g_assert_cmpint(h2.last_event, ==, CHR_EVENT_BREAK);
qemu_chr_be_write(base, (void *)"\1c", 2);
g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN);
g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
qemu_chr_be_event(chr, -1);
g_assert_cmpint(h1.last_event, ==, -1);
g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h2.read_count, ==, 0);
g_assert_cmpint(h1.read_count, ==, 6);
g_assert_cmpstr(h1.read_buf, ==, "hello");
h1.read_count = 0;
qemu_chr_be_write(base, (void *)"\1b", 2);
g_assert_cmpint(h1.last_event, ==, CHR_EVENT_BREAK);
g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT);
/* open/close state and corresponding events */
g_assert_true(qemu_chr_fe_backend_open(&chr_be1));
g_assert_true(qemu_chr_fe_backend_open(&chr_be2));
g_assert_true(h1.is_open);
g_assert_false(h1.openclose_mismatch);
g_assert_true(h2.is_open);
g_assert_false(h2.openclose_mismatch);
h1.openclose_count = h2.openclose_count = 0;
qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
NULL, NULL, false);
qemu_chr_fe_set_handlers(&chr_be2, NULL, NULL, NULL, NULL,
NULL, NULL, false);
g_assert_cmpint(h1.openclose_count, ==, 0);
g_assert_cmpint(h2.openclose_count, ==, 0);
h1.is_open = h2.is_open = false;
qemu_chr_fe_set_handlers(&chr_be1,
NULL,
NULL,
fe_event,
NULL,
&h1,
NULL, false);
qemu_chr_fe_set_handlers(&chr_be2,
NULL,
NULL,
fe_event,
NULL,
&h2,
NULL, false);
g_assert_cmpint(h1.openclose_count, ==, 1);
g_assert_false(h1.openclose_mismatch);
g_assert_cmpint(h2.openclose_count, ==, 1);
g_assert_false(h2.openclose_mismatch);
qemu_chr_be_event(base, CHR_EVENT_CLOSED);
qemu_chr_be_event(base, CHR_EVENT_OPENED);
g_assert_cmpint(h1.openclose_count, ==, 3);
g_assert_false(h1.openclose_mismatch);
g_assert_cmpint(h2.openclose_count, ==, 3);
g_assert_false(h2.openclose_mismatch);
qemu_chr_fe_set_handlers(&chr_be2,
fe_can_read,
fe_read,
fe_event,
NULL,
&h2,
NULL, false);
qemu_chr_fe_set_handlers(&chr_be1,
fe_can_read,
fe_read,
fe_event,
NULL,
&h1,
NULL, false);
/* remove first handler */
qemu_chr_fe_set_handlers(&chr_be1, NULL, NULL, NULL, NULL,
NULL, NULL, true);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 0);
qemu_chr_be_write(base, (void *)"\1c", 2);
qemu_chr_be_write(base, (void *)"hello", 6);
g_assert_cmpint(h1.read_count, ==, 0);
g_assert_cmpint(h2.read_count, ==, 6);
g_assert_cmpstr(h2.read_buf, ==, "hello");
h2.read_count = 0;
/* print help */
qemu_chr_be_write(base, (void *)"\1?", 2);
data = qmp_ringbuf_read("mux-label-base", 128, false, 0, &error_abort);
g_assert_cmpint(strlen(data), !=, 0);
g_free(data);
qemu_chr_fe_deinit(&chr_be1, false);
qemu_chr_fe_deinit(&chr_be2, true);
}
char: allow passing pre-opened socket file descriptor at startup When starting QEMU management apps will usually setup a monitor socket, and then open it immediately after startup. If not using QEMU's own -daemonize arg, this process can be troublesome to handle correctly. The mgmt app will need to repeatedly call connect() until it succeeds, because it does not know when QEMU has created the listener socket. If can't retry connect() forever though, because an error might have caused QEMU to exit before it even creates the monitor. The obvious way to fix this kind of problem is to just pass in a pre-opened socket file descriptor for the QEMU monitor to listen on. The management app can now immediately call connect() just once. If connect() fails it knows that QEMU has exited with an error. The SocketAddress(Legacy) structs allow for FD passing via the monitor, and now via inherited file descriptors from the process that spawned QEMU. The final missing piece is adding a 'fd' parameter in the socket chardev options. This allows both HMP usage, pass any FD number with SCM_RIGHTS, then running HMP commands: getfd myfd chardev-add socket,fd=myfd Note that numeric FDs cannot be referenced directly in HMP, only named FDs. And also CLI usage, by leak FD 3 from parent by clearing O_CLOEXEC, then spawning QEMU with -chardev socket,fd=3,id=mon -mon chardev=mon,mode=control Note that named FDs cannot be referenced in CLI args, only numeric FDs. We do not wire this up in the legacy chardev syntax, so you cannot use FD passing with '-qmp', you must use the modern '-mon' + '-chardev' pair. When passing pre-opened FDs there is a restriction on use of TLS encryption. It can be used on a server socket chardev, but cannot be used for a client socket chardev. This is because when validating a server's certificate, the client needs to have a hostname available to match against the certificate identity. An illustrative example of usage is: #!/usr/bin/perl use IO::Socket::UNIX; use Fcntl; unlink "/tmp/qmp"; my $srv = IO::Socket::UNIX->new( Type => SOCK_STREAM(), Local => "/tmp/qmp", Listen => 1, ); my $flags = fcntl $srv, F_GETFD, 0; fcntl $srv, F_SETFD, $flags & ~FD_CLOEXEC; my $fd = $srv->fileno(); exec "qemu-system-x86_64", \ "-chardev", "socket,fd=$fd,server,nowait,id=mon", \ "-mon", "chardev=mon,mode=control"; Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2017-12-21 13:57:54 +01:00
static void websock_server_read(void *opaque, const uint8_t *buf, int size)
{
g_assert_cmpint(size, ==, 5);
g_assert(memcmp(buf, "world", size) == 0);
quit = true;
}
static int websock_server_can_read(void *opaque)
{
return 10;
}
static bool websock_check_http_headers(char *buf, int size)
{
int i;
const char *ans[] = { "HTTP/1.1 101 Switching Protocols\r\n",
"Server: QEMU VNC\r\n",
"Upgrade: websocket\r\n",
"Connection: Upgrade\r\n",
"Sec-WebSocket-Accept:",
"Sec-WebSocket-Protocol: binary\r\n" };
for (i = 0; i < 6; i++) {
if (g_strstr_len(buf, size, ans[i]) == NULL) {
return false;
}
}
return true;
}
static void websock_client_read(void *opaque, const uint8_t *buf, int size)
{
const uint8_t ping[] = { 0x89, 0x85, /* Ping header */
0x07, 0x77, 0x9e, 0xf9, /* Masking key */
0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ };
const uint8_t binary[] = { 0x82, 0x85, /* Binary header */
0x74, 0x90, 0xb9, 0xdf, /* Masking key */
0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ };
Chardev *chr_client = opaque;
if (websock_check_http_headers((char *) buf, size)) {
qemu_chr_fe_write(chr_client->be, ping, sizeof(ping));
} else if (buf[0] == 0x8a && buf[1] == 0x05) {
g_assert(strncmp((char *) buf + 2, "hello", 5) == 0);
qemu_chr_fe_write(chr_client->be, binary, sizeof(binary));
} else {
g_assert(buf[0] == 0x88 && buf[1] == 0x16);
g_assert(strncmp((char *) buf + 4, "peer requested close", 10) == 0);
quit = true;
}
}
static int websock_client_can_read(void *opaque)
{
return 4096;
}
static void char_websock_test(void)
{
QObject *addr;
QDict *qdict;
const char *port;
char *tmp;
char *handshake_port;
CharBackend be;
CharBackend client_be;
Chardev *chr_client;
Chardev *chr = qemu_chr_new("server",
"websocket:127.0.0.1:0,server=on,wait=off", NULL);
const char handshake[] = "GET / HTTP/1.1\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Host: localhost:%s\r\n"
"Origin: http://localhost:%s\r\n"
"Sec-WebSocket-Key: o9JHNiS3/0/0zYE1wa3yIw==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Protocol: binary\r\n\r\n";
const uint8_t close[] = { 0x88, 0x82, /* Close header */
0xef, 0xaa, 0xc5, 0x97, /* Masking key */
0xec, 0x42 /* Status code */ };
addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
qdict = qobject_to(QDict, addr);
port = qdict_get_str(qdict, "port");
tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
handshake_port = g_strdup_printf(handshake, port, port);
qobject_unref(qdict);
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_handlers(&be, websock_server_can_read, websock_server_read,
NULL, NULL, chr, NULL, true);
chr_client = qemu_chr_new("client", tmp, NULL);
qemu_chr_fe_init(&client_be, chr_client, &error_abort);
qemu_chr_fe_set_handlers(&client_be, websock_client_can_read,
websock_client_read,
NULL, NULL, chr_client, NULL, true);
g_free(tmp);
qemu_chr_write_all(chr_client,
(uint8_t *) handshake_port,
strlen(handshake_port));
g_free(handshake_port);
main_loop();
g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
g_assert(object_property_get_bool(OBJECT(chr_client),
"connected", &error_abort));
qemu_chr_write_all(chr_client, close, sizeof(close));
main_loop();
object_unparent(OBJECT(chr_client));
object_unparent(OBJECT(chr));
}
#ifndef _WIN32
static void char_pipe_test(void)
{
gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
Chardev *chr;
CharBackend be;
int ret, fd;
char buf[10];
FeHandler fe = { 0, };
in = g_strdup_printf("%s.in", pipe);
if (mkfifo(in, 0600) < 0) {
abort();
}
out = g_strdup_printf("%s.out", pipe);
if (mkfifo(out, 0600) < 0) {
abort();
}
tmp = g_strdup_printf("pipe:%s", pipe);
chr = qemu_chr_new("pipe", tmp, NULL);
g_assert_nonnull(chr);
g_free(tmp);
qemu_chr_fe_init(&be, chr, &error_abort);
ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
g_assert_cmpint(ret, ==, 9);
fd = open(out, O_RDWR);
ret = read(fd, buf, sizeof(buf));
g_assert_cmpint(ret, ==, 9);
g_assert_cmpstr(buf, ==, "pipe-out");
close(fd);
fd = open(in, O_WRONLY);
ret = write(fd, "pipe-in", 8);
g_assert_cmpint(ret, ==, 8);
close(fd);
qemu_chr_fe_set_handlers(&be,
fe_can_read,
fe_read,
fe_event,
NULL,
&fe,
NULL, true);
main_loop();
g_assert_cmpint(fe.read_count, ==, 8);
g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
qemu_chr_fe_deinit(&be, true);
g_assert(g_unlink(in) == 0);
g_assert(g_unlink(out) == 0);
g_assert(g_rmdir(tmp_path) == 0);
g_free(in);
g_free(out);
g_free(tmp_path);
g_free(pipe);
}
#endif
typedef struct SocketIdleData {
GMainLoop *loop;
Chardev *chr;
bool conn_expected;
CharBackend *be;
CharBackend *client_be;
} SocketIdleData;
static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
{
g_assert_cmpint(size, ==, 5);
g_assert(strncmp((char *)buf, "hello", 5) == 0);
quit = true;
}
static int socket_can_read_hello(void *opaque)
{
return 10;
}
static int make_udp_socket(int *port)
{
struct sockaddr_in addr = { 0, };
socklen_t alen = sizeof(addr);
int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
g_assert_cmpint(sock, >, 0);
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = 0;
ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
g_assert_cmpint(ret, ==, 0);
ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
g_assert_cmpint(ret, ==, 0);
*port = ntohs(addr.sin_port);
return sock;
}
static void char_udp_test_internal(Chardev *reuse_chr, int sock)
{
struct sockaddr_in other;
SocketIdleData d = { 0, };
Chardev *chr;
CharBackend *be;
socklen_t alen = sizeof(other);
int ret;
char buf[10];
char *tmp = NULL;
if (reuse_chr) {
chr = reuse_chr;
be = chr->be;
} else {
int port;
sock = make_udp_socket(&port);
tmp = g_strdup_printf("udp:127.0.0.1:%d", port);
chr = qemu_chr_new("client", tmp, NULL);
g_assert_nonnull(chr);
be = g_alloca(sizeof(CharBackend));
qemu_chr_fe_init(be, chr, &error_abort);
}
d.chr = chr;
qemu_chr_fe_set_handlers(be, socket_can_read_hello, socket_read_hello,
NULL, NULL, &d, NULL, true);
ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
g_assert_cmpint(ret, ==, 5);
ret = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *)&other, &alen);
g_assert_cmpint(ret, ==, 5);
ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
g_assert_cmpint(ret, ==, 5);
main_loop();
if (!reuse_chr) {
close(sock);
qemu_chr_fe_deinit(be, true);
}
g_free(tmp);
}
static void char_udp_test(void)
{
char_udp_test_internal(NULL, 0);
}
typedef struct {
int event;
bool got_pong;
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
CharBackend *be;
} CharSocketTestData;
#define SOCKET_PING "Hello"
#define SOCKET_PONG "World"
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event);
static void
char_socket_event(void *opaque, QEMUChrEvent event)
{
CharSocketTestData *data = opaque;
data->event = event;
}
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
static void
char_socket_event_with_error(void *opaque, QEMUChrEvent event)
{
static bool first_error;
CharSocketTestData *data = opaque;
CharBackend *be = data->be;
data->event = event;
switch (event) {
case CHR_EVENT_OPENED:
if (!first_error) {
first_error = true;
qemu_chr_fe_disconnect(be);
}
return;
case CHR_EVENT_CLOSED:
return;
default:
return;
}
}
static void
char_socket_read(void *opaque, const uint8_t *buf, int size)
{
CharSocketTestData *data = opaque;
g_assert_cmpint(size, ==, sizeof(SOCKET_PONG));
g_assert(memcmp(buf, SOCKET_PONG, size) == 0);
data->got_pong = true;
}
static int
char_socket_can_read(void *opaque)
{
return sizeof(SOCKET_PONG);
}
static char *
char_socket_addr_to_opt_str(SocketAddress *addr, bool fd_pass,
const char *reconnect, bool is_listen)
{
if (fd_pass) {
QIOChannelSocket *ioc = qio_channel_socket_new();
int fd;
char *optstr;
g_assert(!reconnect);
if (is_listen) {
qio_channel_socket_listen_sync(ioc, addr, 1, &error_abort);
} else {
qio_channel_socket_connect_sync(ioc, addr, &error_abort);
}
fd = ioc->fd;
ioc->fd = -1;
optstr = g_strdup_printf("socket,id=cdev0,fd=%d%s",
fd, is_listen ? ",server=on,wait=off" : "");
object_unref(OBJECT(ioc));
return optstr;
} else {
switch (addr->type) {
case SOCKET_ADDRESS_TYPE_INET:
return g_strdup_printf("socket,id=cdev0,host=%s,port=%s%s%s",
addr->u.inet.host,
addr->u.inet.port,
reconnect ? reconnect : "",
is_listen ? ",server=on,wait=off" : "");
case SOCKET_ADDRESS_TYPE_UNIX:
return g_strdup_printf("socket,id=cdev0,path=%s%s%s",
addr->u.q_unix.path,
reconnect ? reconnect : "",
is_listen ? ",server=on,wait=off" : "");
default:
g_assert_not_reached();
}
}
}
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
static int
char_socket_ping_pong(QIOChannel *ioc, Error **errp)
{
char greeting[sizeof(SOCKET_PING)];
const char *response = SOCKET_PONG;
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
int ret;
ret = qio_channel_read_all(ioc, greeting, sizeof(greeting), errp);
if (ret != 0) {
object_unref(OBJECT(ioc));
return -1;
}
g_assert(memcmp(greeting, SOCKET_PING, sizeof(greeting)) == 0);
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
qio_channel_write_all(ioc, response, sizeof(SOCKET_PONG), errp);
object_unref(OBJECT(ioc));
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
return 0;
}
static gpointer
char_socket_server_client_thread(gpointer data)
{
SocketAddress *addr = data;
QIOChannelSocket *ioc = qio_channel_socket_new();
qio_channel_socket_connect_sync(ioc, addr, &error_abort);
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
char_socket_ping_pong(QIO_CHANNEL(ioc), &error_abort);
return NULL;
}
typedef struct {
SocketAddress *addr;
bool wait_connected;
bool fd_pass;
} CharSocketServerTestConfig;
static void char_socket_server_test(gconstpointer opaque)
{
const CharSocketServerTestConfig *config = opaque;
Chardev *chr;
CharBackend be = {0};
CharSocketTestData data = {0};
QObject *qaddr;
SocketAddress *addr;
Visitor *v;
QemuThread thread;
int ret;
bool reconnected = false;
char *optstr;
QemuOpts *opts;
g_setenv("QTEST_SILENT_ERRORS", "1", 1);
/*
* We rely on config->addr containing "wait=off", otherwise
* qemu_chr_new() will block until a client connects. We
* can't spawn our client thread though, because until
* qemu_chr_new() returns we don't know what TCP port was
* allocated by the OS
*/
optstr = char_socket_addr_to_opt_str(config->addr,
config->fd_pass,
NULL,
true);
opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
optstr, true);
g_assert_nonnull(opts);
chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
qemu_opts_del(opts);
g_assert_nonnull(chr);
g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
g_assert_nonnull(qaddr);
v = qobject_input_visitor_new(qaddr);
visit_type_SocketAddress(v, "addr", &addr, &error_abort);
visit_free(v);
qobject_unref(qaddr);
qemu_chr_fe_init(&be, chr, &error_abort);
reconnect:
data.event = -1;
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
data.be = &be;
qemu_chr_fe_set_handlers(&be, NULL, NULL,
char_socket_event, NULL,
&data, NULL, true);
g_assert(data.event == -1);
/*
* Kick off a thread to act as the "remote" client
* which just plays ping-pong with us
*/
qemu_thread_create(&thread, "client",
char_socket_server_client_thread,
addr, QEMU_THREAD_JOINABLE);
g_assert(data.event == -1);
if (config->wait_connected) {
/* Synchronously accept a connection */
qemu_chr_wait_connected(chr, &error_abort);
} else {
/*
* Asynchronously accept a connection when the evnt
* loop reports the listener socket as readable
*/
while (data.event == -1) {
main_loop_wait(false);
}
}
g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
g_assert(data.event == CHR_EVENT_OPENED);
data.event = -1;
/* Send a greeting to the client */
ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING,
sizeof(SOCKET_PING));
g_assert_cmpint(ret, ==, sizeof(SOCKET_PING));
g_assert(data.event == -1);
/* Setup a callback to receive the reply to our greeting */
qemu_chr_fe_set_handlers(&be, char_socket_can_read,
char_socket_read,
char_socket_event, NULL,
&data, NULL, true);
g_assert(data.event == CHR_EVENT_OPENED);
data.event = -1;
/* Wait for the client to go away */
while (data.event == -1) {
main_loop_wait(false);
}
g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
g_assert(data.event == CHR_EVENT_CLOSED);
g_assert(data.got_pong);
qemu_thread_join(&thread);
if (!reconnected) {
reconnected = true;
goto reconnect;
}
qapi_free_SocketAddress(addr);
object_unparent(OBJECT(chr));
g_free(optstr);
g_unsetenv("QTEST_SILENT_ERRORS");
}
static gpointer
char_socket_client_server_thread(gpointer data)
{
QIOChannelSocket *ioc = data;
QIOChannelSocket *cioc;
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
retry:
cioc = qio_channel_socket_accept(ioc, &error_abort);
g_assert_nonnull(cioc);
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
if (char_socket_ping_pong(QIO_CHANNEL(cioc), NULL) != 0) {
goto retry;
}
return NULL;
}
typedef struct {
SocketAddress *addr;
const char *reconnect;
bool wait_connected;
bool fd_pass;
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
char_socket_cb event_cb;
} CharSocketClientTestConfig;
static void char_socket_client_dupid_test(gconstpointer opaque)
{
const CharSocketClientTestConfig *config = opaque;
QIOChannelSocket *ioc;
char *optstr;
Chardev *chr1, *chr2;
SocketAddress *addr;
QemuOpts *opts;
Error *local_err = NULL;
/*
* Setup a listener socket and determine get its address
* so we know the TCP port for the client later
*/
ioc = qio_channel_socket_new();
g_assert_nonnull(ioc);
qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort);
addr = qio_channel_socket_get_local_address(ioc, &error_abort);
g_assert_nonnull(addr);
/*
* Populate the chardev address based on what the server
* is actually listening on
*/
optstr = char_socket_addr_to_opt_str(addr,
config->fd_pass,
config->reconnect,
false);
opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
optstr, true);
g_assert_nonnull(opts);
chr1 = qemu_chr_new_from_opts(opts, NULL, &error_abort);
g_assert_nonnull(chr1);
qemu_chr_wait_connected(chr1, &error_abort);
chr2 = qemu_chr_new_from_opts(opts, NULL, &local_err);
g_assert_null(chr2);
error_free_or_abort(&local_err);
object_unref(OBJECT(ioc));
qemu_opts_del(opts);
object_unparent(OBJECT(chr1));
qapi_free_SocketAddress(addr);
g_free(optstr);
}
static void char_socket_client_test(gconstpointer opaque)
{
const CharSocketClientTestConfig *config = opaque;
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
const char_socket_cb event_cb = config->event_cb;
QIOChannelSocket *ioc;
char *optstr;
Chardev *chr;
CharBackend be = {0};
CharSocketTestData data = {0};
SocketAddress *addr;
QemuThread thread;
int ret;
bool reconnected = false;
QemuOpts *opts;
/*
* Setup a listener socket and determine get its address
* so we know the TCP port for the client later
*/
ioc = qio_channel_socket_new();
g_assert_nonnull(ioc);
qio_channel_socket_listen_sync(ioc, config->addr, 1, &error_abort);
addr = qio_channel_socket_get_local_address(ioc, &error_abort);
g_assert_nonnull(addr);
/*
* Kick off a thread to act as the "remote" client
* which just plays ping-pong with us
*/
qemu_thread_create(&thread, "client",
char_socket_client_server_thread,
ioc, QEMU_THREAD_JOINABLE);
/*
* Populate the chardev address based on what the server
* is actually listening on
*/
optstr = char_socket_addr_to_opt_str(addr,
config->fd_pass,
config->reconnect,
false);
opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
optstr, true);
g_assert_nonnull(opts);
chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
qemu_opts_del(opts);
g_assert_nonnull(chr);
if (config->reconnect) {
/*
* If reconnect is set, the connection will be
* established in a background thread and we won't
* see the "connected" status updated until we
* run the main event loop, or call qemu_chr_wait_connected
*/
g_assert(!object_property_get_bool(OBJECT(chr), "connected",
&error_abort));
} else {
g_assert(object_property_get_bool(OBJECT(chr), "connected",
&error_abort));
}
qemu_chr_fe_init(&be, chr, &error_abort);
reconnect:
data.event = -1;
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
data.be = &be;
qemu_chr_fe_set_handlers(&be, NULL, NULL,
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
event_cb, NULL,
&data, NULL, true);
if (config->reconnect) {
g_assert(data.event == -1);
} else {
g_assert(data.event == CHR_EVENT_OPENED);
}
if (config->wait_connected) {
/*
* Synchronously wait for the connection to complete
* This should be a no-op if reconnect is not set.
*/
qemu_chr_wait_connected(chr, &error_abort);
} else {
/*
* Asynchronously wait for the connection to be reported
* as complete when the background thread reports its
* status.
* The loop will short-circuit if reconnect was set
*/
while (data.event == -1) {
main_loop_wait(false);
}
}
g_assert(data.event == CHR_EVENT_OPENED);
data.event = -1;
g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
/* Send a greeting to the server */
ret = qemu_chr_fe_write_all(&be, (const uint8_t *)SOCKET_PING,
sizeof(SOCKET_PING));
g_assert_cmpint(ret, ==, sizeof(SOCKET_PING));
g_assert(data.event == -1);
/* Setup a callback to receive the reply to our greeting */
qemu_chr_fe_set_handlers(&be, char_socket_can_read,
char_socket_read,
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
event_cb, NULL,
&data, NULL, true);
g_assert(data.event == CHR_EVENT_OPENED);
data.event = -1;
/* Wait for the server to go away */
while (data.event == -1) {
main_loop_wait(false);
}
g_assert(data.event == CHR_EVENT_CLOSED);
g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
g_assert(data.got_pong);
qemu_thread_join(&thread);
if (config->reconnect && !reconnected) {
reconnected = true;
qemu_thread_create(&thread, "client",
char_socket_client_server_thread,
ioc, QEMU_THREAD_JOINABLE);
goto reconnect;
}
object_unref(OBJECT(ioc));
object_unparent(OBJECT(chr));
qapi_free_SocketAddress(addr);
g_free(optstr);
}
static void
count_closed_event(void *opaque, QEMUChrEvent event)
{
int *count = opaque;
if (event == CHR_EVENT_CLOSED) {
(*count)++;
}
}
static void
char_socket_discard_read(void *opaque, const uint8_t *buf, int size)
{
}
static void char_socket_server_two_clients_test(gconstpointer opaque)
{
SocketAddress *incoming_addr = (gpointer) opaque;
Chardev *chr;
CharBackend be = {0};
QObject *qaddr;
SocketAddress *addr;
Visitor *v;
char *optstr;
QemuOpts *opts;
QIOChannelSocket *ioc1, *ioc2;
int closed = 0;
g_setenv("QTEST_SILENT_ERRORS", "1", 1);
/*
* We rely on addr containing "wait=off", otherwise
* qemu_chr_new() will block until a client connects. We
* can't spawn our client thread though, because until
* qemu_chr_new() returns we don't know what TCP port was
* allocated by the OS
*/
optstr = char_socket_addr_to_opt_str(incoming_addr,
false,
NULL,
true);
opts = qemu_opts_parse_noisily(qemu_find_opts("chardev"),
optstr, true);
g_assert_nonnull(opts);
chr = qemu_chr_new_from_opts(opts, NULL, &error_abort);
qemu_opts_del(opts);
g_assert_nonnull(chr);
g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
qaddr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
g_assert_nonnull(qaddr);
v = qobject_input_visitor_new(qaddr);
visit_type_SocketAddress(v, "addr", &addr, &error_abort);
visit_free(v);
qobject_unref(qaddr);
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read,
count_closed_event, NULL,
&closed, NULL, true);
ioc1 = qio_channel_socket_new();
qio_channel_socket_connect_sync(ioc1, addr, &error_abort);
qemu_chr_wait_connected(chr, &error_abort);
/* switch the chardev to another context */
GMainContext *ctx = g_main_context_new();
qemu_chr_fe_set_handlers(&be, char_socket_can_read, char_socket_discard_read,
count_closed_event, NULL,
&closed, ctx, true);
/* Start a second connection while the first is still connected.
* It will be placed in the listen() backlog, and connect() will
* succeed immediately.
*/
ioc2 = qio_channel_socket_new();
qio_channel_socket_connect_sync(ioc2, addr, &error_abort);
object_unref(OBJECT(ioc1));
/* The two connections should now be processed serially. */
while (g_main_context_iteration(ctx, TRUE)) {
if (closed == 1 && ioc2) {
object_unref(OBJECT(ioc2));
ioc2 = NULL;
}
if (closed == 2) {
break;
}
}
qapi_free_SocketAddress(addr);
object_unparent(OBJECT(chr));
g_main_context_unref(ctx);
g_free(optstr);
g_unsetenv("QTEST_SILENT_ERRORS");
}
#if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32)
static void char_serial_test(void)
{
QemuOpts *opts;
Chardev *chr;
opts = qemu_opts_create(qemu_find_opts("chardev"), "serial-id",
1, &error_abort);
qemu_opt_set(opts, "backend", "serial", &error_abort);
qemu_opt_set(opts, "path", "/dev/null", &error_abort);
chr = qemu_chr_new_from_opts(opts, NULL, NULL);
g_assert_nonnull(chr);
/* TODO: add more tests with a pty */
object_unparent(OBJECT(chr));
qemu_opts_del(opts);
}
#endif
#ifndef _WIN32
static void char_file_fifo_test(void)
{
Chardev *chr;
CharBackend be;
char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
char *fifo = g_build_filename(tmp_path, "fifo", NULL);
char *out = g_build_filename(tmp_path, "out", NULL);
ChardevFile file = { .in = fifo,
.has_in = true,
.out = out };
ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
.u.file.data = &file };
FeHandler fe = { 0, };
int fd, ret;
if (mkfifo(fifo, 0600) < 0) {
abort();
}
fd = open(fifo, O_RDWR);
ret = write(fd, "fifo-in", 8);
g_assert_cmpint(ret, ==, 8);
chr = qemu_chardev_new("label-file", TYPE_CHARDEV_FILE, &backend,
NULL, &error_abort);
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_handlers(&be,
fe_can_read,
fe_read,
fe_event,
NULL,
&fe, NULL, true);
g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
qmp_chardev_send_break("label-foo", NULL);
g_assert_cmpint(fe.last_event, !=, CHR_EVENT_BREAK);
qmp_chardev_send_break("label-file", NULL);
g_assert_cmpint(fe.last_event, ==, CHR_EVENT_BREAK);
main_loop();
close(fd);
g_assert_cmpint(fe.read_count, ==, 8);
g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
qemu_chr_fe_deinit(&be, true);
g_unlink(fifo);
g_free(fifo);
g_unlink(out);
g_free(out);
g_rmdir(tmp_path);
g_free(tmp_path);
}
#endif
static void char_file_test_internal(Chardev *ext_chr, const char *filepath)
{
char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
char *out;
Chardev *chr;
char *contents = NULL;
ChardevFile file = {};
ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
.u.file.data = &file };
gsize length;
int ret;
if (ext_chr) {
chr = ext_chr;
out = g_strdup(filepath);
file.out = out;
} else {
out = g_build_filename(tmp_path, "out", NULL);
file.out = out;
chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
NULL, &error_abort);
}
ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
g_assert_cmpint(ret, ==, 6);
ret = g_file_get_contents(out, &contents, &length, NULL);
g_assert(ret == TRUE);
g_assert_cmpint(length, ==, 6);
g_assert(strncmp(contents, "hello!", 6) == 0);
if (!ext_chr) {
object_unparent(OBJECT(chr));
g_unlink(out);
}
g_free(contents);
g_rmdir(tmp_path);
g_free(tmp_path);
g_free(out);
}
static void char_file_test(void)
{
char_file_test_internal(NULL, NULL);
}
static void char_null_test(void)
{
Error *err = NULL;
Chardev *chr;
CharBackend be;
int ret;
chr = qemu_chr_find("label-null");
g_assert_null(chr);
chr = qemu_chr_new("label-null", "null", NULL);
chr = qemu_chr_find("label-null");
g_assert_nonnull(chr);
g_assert(qemu_chr_has_feature(chr,
QEMU_CHAR_FEATURE_FD_PASS) == false);
g_assert(qemu_chr_has_feature(chr,
QEMU_CHAR_FEATURE_RECONNECTABLE) == false);
/* check max avail */
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_init(&be, chr, &err);
error_free_or_abort(&err);
/* deinit & reinit */
qemu_chr_fe_deinit(&be, false);
qemu_chr_fe_init(&be, chr, &error_abort);
qemu_chr_fe_set_open(&be, true);
qemu_chr_fe_set_handlers(&be,
fe_can_read,
fe_read,
fe_event,
NULL,
NULL, NULL, true);
ret = qemu_chr_fe_write(&be, (void *)"buf", 4);
g_assert_cmpint(ret, ==, 4);
qemu_chr_fe_deinit(&be, true);
}
static void char_invalid_test(void)
{
Chardev *chr;
g_setenv("QTEST_SILENT_ERRORS", "1", 1);
chr = qemu_chr_new("label-invalid", "invalid", NULL);
g_assert_null(chr);
g_unsetenv("QTEST_SILENT_ERRORS");
}
static int chardev_change(void *opaque)
{
return 0;
}
static int chardev_change_denied(void *opaque)
{
return -1;
}
static void char_hotswap_test(void)
{
char *chr_args;
Chardev *chr;
CharBackend be;
gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
char *filename = g_build_filename(tmp_path, "file", NULL);
ChardevFile file = { .out = filename };
ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
.u.file.data = &file };
ChardevReturn *ret;
int port;
int sock = make_udp_socket(&port);
g_assert_cmpint(sock, >, 0);
chr_args = g_strdup_printf("udp:127.0.0.1:%d", port);
chr = qemu_chr_new("chardev", chr_args, NULL);
qemu_chr_fe_init(&be, chr, &error_abort);
/* check that chardev operates correctly */
char_udp_test_internal(chr, sock);
/* set the handler that denies the hotswap */
qemu_chr_fe_set_handlers(&be, NULL, NULL,
NULL, chardev_change_denied, NULL, NULL, true);
/* now, change is denied and has to keep the old backend operating */
ret = qmp_chardev_change("chardev", &backend, NULL);
g_assert(!ret);
g_assert(be.chr == chr);
char_udp_test_internal(chr, sock);
/* now allow the change */
qemu_chr_fe_set_handlers(&be, NULL, NULL,
NULL, chardev_change, NULL, NULL, true);
/* has to succeed now */
ret = qmp_chardev_change("chardev", &backend, &error_abort);
g_assert(be.chr != chr);
close(sock);
chr = be.chr;
/* run the file chardev test */
char_file_test_internal(chr, filename);
object_unparent(OBJECT(chr));
qapi_free_ChardevReturn(ret);
g_unlink(filename);
g_free(filename);
g_rmdir(tmp_path);
g_free(tmp_path);
g_free(chr_args);
}
static SocketAddress tcpaddr = {
.type = SOCKET_ADDRESS_TYPE_INET,
.u.inet.host = (char *)"127.0.0.1",
.u.inet.port = (char *)"0",
};
#ifndef WIN32
static SocketAddress unixaddr = {
.type = SOCKET_ADDRESS_TYPE_UNIX,
.u.q_unix.path = (char *)"test-char.sock",
};
#endif
int main(int argc, char **argv)
{
bool has_ipv4, has_ipv6;
qemu_init_main_loop(&error_abort);
socket_init();
g_test_init(&argc, &argv, NULL);
if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
g_printerr("socket_check_protocol_support() failed\n");
goto end;
}
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_chardev_opts);
g_test_add_func("/char/null", char_null_test);
g_test_add_func("/char/invalid", char_invalid_test);
g_test_add_func("/char/ringbuf", char_ringbuf_test);
g_test_add_func("/char/mux", char_mux_test);
#ifdef _WIN32
g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
g_test_add_func("/char/console", char_console_test);
#endif
g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
g_test_add_func("/char/stdio", char_stdio_test);
#ifndef _WIN32
g_test_add_func("/char/pipe", char_pipe_test);
#endif
g_test_add_func("/char/file", char_file_test);
#ifndef _WIN32
g_test_add_func("/char/file-fifo", char_file_fifo_test);
#endif
#define SOCKET_SERVER_TEST(name, addr) \
static CharSocketServerTestConfig server1 ## name = \
{ addr, false, false }; \
static CharSocketServerTestConfig server2 ## name = \
{ addr, true, false }; \
static CharSocketServerTestConfig server3 ## name = \
{ addr, false, true }; \
static CharSocketServerTestConfig server4 ## name = \
{ addr, true, true }; \
g_test_add_data_func("/char/socket/server/mainloop/" # name, \
&server1 ##name, char_socket_server_test); \
g_test_add_data_func("/char/socket/server/wait-conn/" # name, \
&server2 ##name, char_socket_server_test); \
g_test_add_data_func("/char/socket/server/mainloop-fdpass/" # name, \
&server3 ##name, char_socket_server_test); \
g_test_add_data_func("/char/socket/server/wait-conn-fdpass/" # name, \
&server4 ##name, char_socket_server_test)
#define SOCKET_CLIENT_TEST(name, addr) \
static CharSocketClientTestConfig client1 ## name = \
{ addr, NULL, false, false, char_socket_event }; \
static CharSocketClientTestConfig client2 ## name = \
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
{ addr, NULL, true, false, char_socket_event }; \
static CharSocketClientTestConfig client3 ## name = \
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
{ addr, ",reconnect=1", false, false, char_socket_event }; \
static CharSocketClientTestConfig client4 ## name = \
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
{ addr, ",reconnect=1", true, false, char_socket_event }; \
static CharSocketClientTestConfig client5 ## name = \
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
{ addr, NULL, false, true, char_socket_event }; \
static CharSocketClientTestConfig client6 ## name = \
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
{ addr, NULL, true, true, char_socket_event }; \
static CharSocketClientTestConfig client7 ## name = \
{ addr, ",reconnect=1", true, false, \
char_socket_event_with_error }; \
static CharSocketClientTestConfig client8 ## name = \
{ addr, ",reconnect=1", false, false, char_socket_event }; \
g_test_add_data_func("/char/socket/client/mainloop/" # name, \
&client1 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
&client2 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/mainloop-reconnect/" # name, \
&client3 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn-reconnect/" # name, \
&client4 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/mainloop-fdpass/" # name, \
&client5 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
char-socket: initialize reconnect timer only when the timer doesn't start When the disconnect event is triggered in the connecting stage, the tcp_chr_disconnect_locked may be called twice. The first call: #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120 #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090 #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196 #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111 #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190 #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013 #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152 The second call: #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6 #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6 #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6 #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6 #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125 #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490 #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497 #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892 #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944 #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035 #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023 Run test/test-char to reproduce this issue. test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed. Signed-off-by: Li Feng <fengli@smartx.com> Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20200522025554.41063-1-fengli@smartx.com>
2020-05-22 04:55:54 +02:00
&client6 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \
&client7 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
&client8 ##name, char_socket_client_dupid_test)
if (has_ipv4) {
SOCKET_SERVER_TEST(tcp, &tcpaddr);
SOCKET_CLIENT_TEST(tcp, &tcpaddr);
g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr,
char_socket_server_two_clients_test);
}
#ifndef WIN32
SOCKET_SERVER_TEST(unix, &unixaddr);
SOCKET_CLIENT_TEST(unix, &unixaddr);
g_test_add_data_func("/char/socket/server/two-clients/unix", &unixaddr,
char_socket_server_two_clients_test);
#endif
g_test_add_func("/char/udp", char_udp_test);
#if defined(HAVE_CHARDEV_SERIAL) && !defined(WIN32)
g_test_add_func("/char/serial", char_serial_test);
#endif
g_test_add_func("/char/hotswap", char_hotswap_test);
g_test_add_func("/char/websocket", char_websock_test);
end:
return g_test_run();
}