diff options
Diffstat (limited to 'chardev')
-rw-r--r-- | chardev/char-socket.c | 64 | ||||
-rw-r--r-- | chardev/char.c | 8 |
2 files changed, 64 insertions, 8 deletions
diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 0bbeb83ceb..eaa8e8b68f 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -26,6 +26,7 @@ #include "chardev/char.h" #include "io/channel-socket.h" #include "io/channel-tls.h" +#include "io/channel-websock.h" #include "io/net-listener.h" #include "qemu/error-report.h" #include "qemu/option.h" @@ -68,6 +69,8 @@ typedef struct { GSource *telnet_source; TCPChardevTelnetInit *telnet_init; + bool is_websock; + GSource *reconnect_timer; int64_t reconnect_time; bool connect_err_reported; @@ -394,7 +397,7 @@ static const char *qemu_chr_socket_protocol(SocketChardev *s) if (s->is_telnet) { return "telnet"; } - return "tcp"; + return s->is_websock ? "websocket" : "tcp"; } static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix) @@ -714,6 +717,41 @@ cont: } +static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data) +{ + Chardev *chr = user_data; + SocketChardev *s = user_data; + + if (qio_task_propagate_error(task, NULL)) { + tcp_chr_disconnect(chr); + } else { + if (s->do_telnetopt) { + tcp_chr_telnet_init(chr); + } else { + tcp_chr_connect(chr); + } + } +} + + +static void tcp_chr_websock_init(Chardev *chr) +{ + SocketChardev *s = SOCKET_CHARDEV(chr); + QIOChannelWebsock *wioc = NULL; + gchar *name; + + wioc = qio_channel_websock_new_server(s->ioc); + + name = g_strdup_printf("chardev-websocket-server-%s", chr->label); + qio_channel_set_name(QIO_CHANNEL(wioc), name); + g_free(name); + object_unref(OBJECT(s->ioc)); + s->ioc = QIO_CHANNEL(wioc); + + qio_channel_websock_handshake(wioc, tcp_chr_websock_handshake, chr, NULL); +} + + static void tcp_chr_tls_handshake(QIOTask *task, gpointer user_data) { @@ -723,7 +761,9 @@ static void tcp_chr_tls_handshake(QIOTask *task, if (qio_task_propagate_error(task, NULL)) { tcp_chr_disconnect(chr); } else { - if (s->do_telnetopt) { + if (s->is_websock) { + tcp_chr_websock_init(chr); + } else if (s->do_telnetopt) { tcp_chr_telnet_init(chr); } else { tcp_chr_connect(chr); @@ -809,12 +849,12 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc) if (s->tls_creds) { tcp_chr_tls_init(chr); + } else if (s->is_websock) { + tcp_chr_websock_init(chr); + } else if (s->do_telnetopt) { + tcp_chr_telnet_init(chr); } else { - if (s->do_telnetopt) { - tcp_chr_telnet_init(chr); - } else { - tcp_chr_connect(chr); - } + tcp_chr_connect(chr); } return 0; @@ -959,13 +999,20 @@ static void qmp_chardev_open_socket(Chardev *chr, bool is_telnet = sock->has_telnet ? sock->telnet : false; bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false; bool is_waitconnect = sock->has_wait ? sock->wait : false; + bool is_websock = sock->has_websocket ? sock->websocket : false; int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0; QIOChannelSocket *sioc = NULL; SocketAddress *addr; + if (!is_listen && is_websock) { + error_setg(errp, "%s", "Websocket client is not implemented"); + goto error; + } + s->is_listen = is_listen; s->is_telnet = is_telnet; s->is_tn3270 = is_tn3270; + s->is_websock = is_websock; s->do_nodelay = do_nodelay; if (sock->tls_creds) { Object *creds; @@ -1076,6 +1123,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true); bool is_telnet = qemu_opt_get_bool(opts, "telnet", false); bool is_tn3270 = qemu_opt_get_bool(opts, "tn3270", false); + bool is_websock = qemu_opt_get_bool(opts, "websocket", false); bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true); int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0); const char *path = qemu_opt_get(opts, "path"); @@ -1124,6 +1172,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend, sock->telnet = is_telnet; sock->has_tn3270 = true; sock->tn3270 = is_tn3270; + sock->has_websocket = true; + sock->websocket = is_websock; sock->has_wait = true; sock->wait = is_waitconnect; sock->has_reconnect = qemu_opt_find(opts, "reconnect"); diff --git a/chardev/char.c b/chardev/char.c index 7f07a1bfbd..79b05fb7b7 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -409,7 +409,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename, } if (strstart(filename, "tcp:", &p) || strstart(filename, "telnet:", &p) || - strstart(filename, "tn3270:", &p)) { + strstart(filename, "tn3270:", &p) || + strstart(filename, "websocket:", &p)) { if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) @@ -429,6 +430,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename, qemu_opt_set(opts, "telnet", "on", &error_abort); } else if (strstart(filename, "tn3270:", &p)) { qemu_opt_set(opts, "tn3270", "on", &error_abort); + } else if (strstart(filename, "websocket:", &p)) { + qemu_opt_set(opts, "websocket", "on", &error_abort); } return opts; } @@ -861,6 +864,9 @@ QemuOptsList qemu_chardev_opts = { .name = "tls-creds", .type = QEMU_OPT_STRING, },{ + .name = "websocket", + .type = QEMU_OPT_BOOL, + },{ .name = "width", .type = QEMU_OPT_NUMBER, },{ |