From nobody Thu May 2 19:51:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 153990233555375.83868444925429; Thu, 18 Oct 2018 15:38:55 -0700 (PDT) Received: from localhost ([::1]:45066 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gDGwP-0001M5-UB for importer@patchew.org; Thu, 18 Oct 2018 18:38:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38411) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gDGtG-0007Y2-Ip for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gDGtC-0003BH-Qk for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:38 -0400 Received: from smtp50.i.mail.ru ([94.100.177.110]:33096) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gDGtA-0002uQ-JQ for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:34 -0400 Received: by smtp50.i.mail.ru with esmtpa (envelope-from ) id 1gDGt1-0000Im-6P; Fri, 19 Oct 2018 01:35:23 +0300 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=yLsGjw1Q4BrOVqzY7BTYaoguuWFskmZr0rwZ+pu1b+M=; b=UHBvifmu8tR55J+EWTLripT3uf03x6jsEbgDFt6bKI3k0uQN2T+L1zR6Xymd9SiJfI+G4y/ODXqbllWt953C6leSKnnNfy1gatHQjGX3TlqYDfrLzuOcayjfW3dzGa+guwDK5ssHvU9luqNxaSA5W+S53r7EvHlmIg5g4uBRTkw=; To: qemu-devel@nongnu.org Date: Fri, 19 Oct 2018 01:34:59 +0300 Message-Id: <20181018223501.21683-2-jusual@mail.ru> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181018223501.21683-1-jusual@mail.ru> References: <20181018223501.21683-1-jusual@mail.ru> Authentication-Results: smtp50.i.mail.ru; auth=pass smtp.auth=jusual@mail.ru smtp.mailfrom=jusual@mail.ru X-7FA49CB5: 0D63561A33F958A5AE15D3ACAFC8F4858D3DD5DEE0CB5ADD7E1454E73CCEAA6E8941B15DA834481FA18204E546F3947C17119E5299B287EEF6B57BC7E64490618DEB871D839B7333395957E7521B51C2545D4CF71C94A83E9FA2833FD35BB23D27C277FBC8AE2E8B47272755C61AA17BA471835C12D1D977C4224003CC8364767815B9869FA544D8090A508E0FED629923F8577A6DFFEA7C6136E347CC761E07C4224003CC836476C0CAF46E325F83A522CA9DD8327EE4930A3850AC1BE2E7358495D5CD460A62ED294373821F5A35C643847C11F186F3C5E7DDDDC251EA7DABCC89B49CDF41148F458B267F216095A92623479134186CDE6BA297DBC24807EABDAD6C7F3747799A X-Mailru-Sender: 42ECD68FB001EF9589BB0A53C8470BCA2A965CAE45DB7B510B32D730D3FD174DD0C26A2DF909F257BCD5BA2C93075E1EC77752E0C033A69E882C431543FD75E20226C39053983FF03453F38A29522196 X-Mras: OK X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 94.100.177.110 Subject: [Qemu-devel] [PATCH v3 1/3] chardev/char-socket: Function headers refactoring X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Julia Suvorova via Qemu-devel Reply-To: Julia Suvorova Cc: Jim Mussared , =?UTF-8?q?Steffen=20G=C3=B6rtz?= , Julia Suvorova , Joel Stanley , Stefan Hajnoczi , marcandre.lureau@redhat.com, Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Upcoming websocket support requires additional parameters in function headers that are already overloaded. This patch replaces the bunch of parameters with a single structure pointer. Signed-off-by: Julia Suvorova Reviewed-by: Daniel P. Berrang=C3=A9 Reviewed-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Stefan Hajnoczi --- chardev/char-socket.c | 55 +++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index a75b46d9fe..effde65a89 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -389,30 +389,37 @@ static void tcp_chr_free_connection(Chardev *chr) s->connected =3D 0; } =20 -static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr, - bool is_listen, bool is_telnet) +static const char *qemu_chr_socket_protocol(SocketChardev *s) { - switch (addr->type) { + if (s->is_telnet) { + return "telnet"; + } + return "tcp"; +} + +static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix) +{ + switch (s->addr->type) { case SOCKET_ADDRESS_TYPE_INET: return g_strdup_printf("%s%s:%s:%s%s", prefix, - is_telnet ? "telnet" : "tcp", - addr->u.inet.host, - addr->u.inet.port, - is_listen ? ",server" : ""); + qemu_chr_socket_protocol(s), + s->addr->u.inet.host, + s->addr->u.inet.port, + s->is_listen ? ",server" : ""); break; case SOCKET_ADDRESS_TYPE_UNIX: return g_strdup_printf("%sunix:%s%s", prefix, - addr->u.q_unix.path, - is_listen ? ",server" : ""); + s->addr->u.q_unix.path, + s->is_listen ? ",server" : ""); break; case SOCKET_ADDRESS_TYPE_FD: - return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.str, - is_listen ? ",server" : ""); + return g_strdup_printf("%sfd:%s%s", prefix, s->addr->u.fd.str, + s->is_listen ? ",server" : ""); break; case SOCKET_ADDRESS_TYPE_VSOCK: return g_strdup_printf("%svsock:%s:%s", prefix, - addr->u.vsock.cid, - addr->u.vsock.port); + s->addr->u.vsock.cid, + s->addr->u.vsock.port); default: abort(); } @@ -424,8 +431,7 @@ static void update_disconnected_filename(SocketChardev = *s) =20 g_free(chr->filename); if (s->addr) { - chr->filename =3D SocketAddress_to_str("disconnected:", s->addr, - s->is_listen, s->is_telnet); + chr->filename =3D qemu_chr_socket_address(s, "disconnected:"); } else { chr->filename =3D g_strdup("disconnected:socket"); } @@ -514,10 +520,12 @@ static int tcp_chr_sync_read(Chardev *chr, const uint= 8_t *buf, int len) return size; } =20 -static char *sockaddr_to_str(struct sockaddr_storage *ss, socklen_t ss_len, - struct sockaddr_storage *ps, socklen_t ps_len, - bool is_listen, bool is_telnet) +static char *qemu_chr_compute_filename(SocketChardev *s) { + struct sockaddr_storage *ss =3D &s->sioc->localAddr; + struct sockaddr_storage *ps =3D &s->sioc->remoteAddr; + socklen_t ss_len =3D s->sioc->localAddrLen; + socklen_t ps_len =3D s->sioc->remoteAddrLen; char shost[NI_MAXHOST], sserv[NI_MAXSERV]; char phost[NI_MAXHOST], pserv[NI_MAXSERV]; const char *left =3D "", *right =3D ""; @@ -527,7 +535,7 @@ static char *sockaddr_to_str(struct sockaddr_storage *s= s, socklen_t ss_len, case AF_UNIX: return g_strdup_printf("unix:%s%s", ((struct sockaddr_un *)(ss))->sun_path, - is_listen ? ",server" : ""); + s->is_listen ? ",server" : ""); #endif case AF_INET6: left =3D "["; @@ -539,9 +547,9 @@ static char *sockaddr_to_str(struct sockaddr_storage *s= s, socklen_t ss_len, getnameinfo((struct sockaddr *) ps, ps_len, phost, sizeof(phost), pserv, sizeof(pserv), NI_NUMERICHOST | NI_NUMERICSERV); return g_strdup_printf("%s:%s%s%s:%s%s <-> %s%s%s:%s", - is_telnet ? "telnet" : "tcp", + qemu_chr_socket_protocol(s), left, shost, right, sserv, - is_listen ? ",server" : "", + s->is_listen ? ",server" : "", left, phost, right, pserv); =20 default: @@ -576,10 +584,7 @@ static void tcp_chr_connect(void *opaque) SocketChardev *s =3D SOCKET_CHARDEV(opaque); =20 g_free(chr->filename); - chr->filename =3D sockaddr_to_str( - &s->sioc->localAddr, s->sioc->localAddrLen, - &s->sioc->remoteAddr, s->sioc->remoteAddrLen, - s->is_listen, s->is_telnet); + chr->filename =3D qemu_chr_compute_filename(s); =20 s->connected =3D 1; update_ioc_handlers(s); --=20 2.17.1 From nobody Thu May 2 19:51:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 153990224442634.125314704516086; Thu, 18 Oct 2018 15:37:24 -0700 (PDT) Received: from localhost ([::1]:45061 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gDGue-00088o-6u for importer@patchew.org; Thu, 18 Oct 2018 18:37:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38407) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gDGtG-0007Y1-HK for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gDGtD-0003CP-D9 for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:38 -0400 Received: from smtp50.i.mail.ru ([94.100.177.110]:35804) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gDGtC-000304-Nz for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:35 -0400 Received: by smtp50.i.mail.ru with esmtpa (envelope-from ) id 1gDGt6-0000Im-48; Fri, 19 Oct 2018 01:35:28 +0300 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=V3mAqIKJrXSc6Qm7iF8fkyYSTujCttUHerM8O/lvPr4=; b=L64hofzcholn9e8x1mxIXQhRs1i5J1fjwcGnKVHpsz1FkifZdS68tMkmpbseaVw7aHLfCYZWWQg0nlm3srnxVxqKO4lktuQ/ErkgqljfaBvc4e6SULTgSC4jZ1o03OuiHzHmLyKwv/QltB0f2JGGzT443BqocTa2VhtSUPLZdCo=; To: qemu-devel@nongnu.org Date: Fri, 19 Oct 2018 01:35:00 +0300 Message-Id: <20181018223501.21683-3-jusual@mail.ru> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181018223501.21683-1-jusual@mail.ru> References: <20181018223501.21683-1-jusual@mail.ru> Authentication-Results: smtp50.i.mail.ru; auth=pass smtp.auth=jusual@mail.ru smtp.mailfrom=jusual@mail.ru X-7FA49CB5: 0D63561A33F958A5B01F79FC880152898D3DD5DEE0CB5ADD36A2807E4187C3608941B15DA834481FA18204E546F3947CEDCF5861DED71B2F389733CBF5DBD5E9C8A9BA7A39EFB7666BA297DBC24807EA117882F44604297287769387670735209ECD01F8117BC8BEA471835C12D1D977C4224003CC8364767815B9869FA544D8090A508E0FED629923F8577A6DFFEA7C2AE38A8E97BAFFB1B3661434B16C20ACE7DDDDC251EA7DABAAAE862A0553A39223F8577A6DFFEA7C4BB58A5F94B308007130902DED7CAE83731C566533BA786A40A5AABA2AD371193C9F3DD0FB1AF5EB1248E41960EB3BA62623479134186CDE6BA297DBC24807EABDAD6C7F3747799A X-Mailru-Sender: 42ECD68FB001EF9589BB0A53C8470BCA98CA4E558F01F8C10B32D730D3FD174D9EF95AA7B19AEE03BCD5BA2C93075E1EC77752E0C033A69E882C431543FD75E20226C39053983FF03453F38A29522196 X-Mras: OK X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 94.100.177.110 Subject: [Qemu-devel] [PATCH v3 2/3] chardev: Add websocket support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Julia Suvorova via Qemu-devel Reply-To: Julia Suvorova Cc: Jim Mussared , =?UTF-8?q?Steffen=20G=C3=B6rtz?= , Julia Suvorova , Joel Stanley , Stefan Hajnoczi , marcandre.lureau@redhat.com, Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" New option "websocket" added to allow using WebSocket protocol for chardev socket backend. Example: -chardev socket,websocket,server,id=3D... Signed-off-by: Julia Suvorova Reviewed-by: Daniel P. Berrang=C3=A9 Reviewed-by: Stefan Hajnoczi --- chardev/char-socket.c | 64 ++++++++++++++++++++++++++++++++++++++----- chardev/char.c | 8 +++++- qapi/char.json | 3 ++ qemu-options.hx | 13 +++++++-- 4 files changed, 77 insertions(+), 11 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index effde65a89..ba4ae9dfb0 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; =20 + 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(SocketChard= ev *s) if (s->is_telnet) { return "telnet"; } - return "tcp"; + return s->is_websock ? "websocket" : "tcp"; } =20 static char *qemu_chr_socket_address(SocketChardev *s, const char *prefix) @@ -714,6 +717,41 @@ cont: } =20 =20 +static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data) +{ + Chardev *chr =3D user_data; + SocketChardev *s =3D 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 =3D SOCKET_CHARDEV(chr); + QIOChannelWebsock *wioc =3D NULL; + gchar *name; + + wioc =3D qio_channel_websock_new_server(s->ioc); + + name =3D 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 =3D QIO_CHANNEL(wioc); + + qio_channel_websock_handshake(wioc, tcp_chr_websock_handshake, chr, NU= LL); +} + + 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, QIOChanne= lSocket *sioc) =20 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); } =20 return 0; @@ -959,13 +999,20 @@ static void qmp_chardev_open_socket(Chardev *chr, bool is_telnet =3D sock->has_telnet ? sock->telnet : false; bool is_tn3270 =3D sock->has_tn3270 ? sock->tn3270 : false; bool is_waitconnect =3D sock->has_wait ? sock->wait : false; + bool is_websock =3D sock->has_websocket ? sock->websocket : false; int64_t reconnect =3D sock->has_reconnect ? sock->reconnect : 0; QIOChannelSocket *sioc =3D NULL; SocketAddress *addr; =20 + if (!is_listen && is_websock) { + error_setg(errp, "%s", "Websocket client is not implemented"); + goto error; + } + s->is_listen =3D is_listen; s->is_telnet =3D is_telnet; s->is_tn3270 =3D is_tn3270; + s->is_websock =3D is_websock; s->do_nodelay =3D do_nodelay; if (sock->tls_creds) { Object *creds; @@ -1072,6 +1119,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Cha= rdevBackend *backend, bool is_waitconnect =3D is_listen && qemu_opt_get_bool(opts, "wait", t= rue); bool is_telnet =3D qemu_opt_get_bool(opts, "telnet", false); bool is_tn3270 =3D qemu_opt_get_bool(opts, "tn3270", false); + bool is_websock =3D qemu_opt_get_bool(opts, "websocket", false); bool do_nodelay =3D !qemu_opt_get_bool(opts, "delay", true); int64_t reconnect =3D qemu_opt_get_number(opts, "reconnect", 0); const char *path =3D qemu_opt_get(opts, "path"); @@ -1120,6 +1168,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Cha= rdevBackend *backend, sock->telnet =3D is_telnet; sock->has_tn3270 =3D true; sock->tn3270 =3D is_tn3270; + sock->has_websocket =3D true; + sock->websocket =3D is_websock; sock->has_wait =3D true; sock->wait =3D is_waitconnect; sock->has_reconnect =3D true; diff --git a/chardev/char.c b/chardev/char.c index e115166995..a8790017e6 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -409,7 +409,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, cons= t 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] =3D 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) @@ -429,6 +430,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, cons= t 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; } @@ -860,6 +863,9 @@ QemuOptsList qemu_chardev_opts =3D { },{ .name =3D "tls-creds", .type =3D QEMU_OPT_STRING, + },{ + .name =3D "websocket", + .type =3D QEMU_OPT_BOOL, },{ .name =3D "width", .type =3D QEMU_OPT_NUMBER, diff --git a/qapi/char.json b/qapi/char.json index b7b2a05766..79bac598a0 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -251,6 +251,8 @@ # sockets (default: false) # @tn3270: enable tn3270 protocol on server # sockets (default: false) (Since: 2.10) +# @websocket: enable websocket protocol on server +# sockets (default: false) (Since: 3.1) # @reconnect: For a client socket, if a socket is disconnected, # then attempt a reconnect after the given number of seconds. # Setting this to zero disables this function. (default: 0) @@ -265,6 +267,7 @@ '*nodelay' : 'bool', '*telnet' : 'bool', '*tn3270' : 'bool', + '*websocket' : 'bool', '*reconnect' : 'int' }, 'base': 'ChardevCommon' } =20 diff --git a/qemu-options.hx b/qemu-options.hx index f139459e80..022c793162 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2409,9 +2409,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev help\n" "-chardev null,id=3Did[,mux=3Don|off][,logfile=3DPATH][,logappend=3Don= |off]\n" "-chardev socket,id=3Did[,host=3Dhost],port=3Dport[,to=3Dto][,ipv4][,i= pv6][,nodelay][,reconnect=3Dseconds]\n" - " [,server][,nowait][,telnet][,reconnect=3Dseconds][,mux=3Don|= off]\n" + " [,server][,nowait][,telnet][,websocket][,reconnect=3Dseconds= ][,mux=3Don|off]\n" " [,logfile=3DPATH][,logappend=3Don|off][,tls-creds=3DID] (tcp= )\n" - "-chardev socket,id=3Did,path=3Dpath[,server][,nowait][,telnet][,recon= nect=3Dseconds]\n" + "-chardev socket,id=3Did,path=3Dpath[,server][,nowait][,telnet][,webso= cket][,reconnect=3Dseconds]\n" " [,mux=3Don|off][,logfile=3DPATH][,logappend=3Don|off] (unix)= \n" "-chardev udp,id=3Did[,host=3Dhost],port=3Dport[,localaddr=3Dlocaladdr= ]\n" " [,localport=3Dlocalport][,ipv4][,ipv6][,mux=3Don|off]\n" @@ -2539,7 +2539,7 @@ The available backends are: A void device. This device will not emit any data, and will drop any data = it receives. The null backend does not take any options. =20 -@item -chardev socket,id=3D@var{id}[,@var{TCP options} or @var{unix option= s}][,server][,nowait][,telnet][,reconnect=3D@var{seconds}][,tls-creds=3D@va= r{id}] +@item -chardev socket,id=3D@var{id}[,@var{TCP options} or @var{unix option= s}][,server][,nowait][,telnet][,websocket][,reconnect=3D@var{seconds}][,tls= -creds=3D@var{id}] =20 Create a two-way stream socket, which can be either a TCP or a unix socket= . A unix socket will be created if @option{path} is specified. Behaviour is @@ -2553,6 +2553,9 @@ connect to a listening socket. @option{telnet} specifies that traffic on the socket should interpret teln= et escape sequences. =20 +@option{websocket} specifies that the socket uses WebSocket protocol for +communication. + @option{reconnect} sets the timeout for reconnecting on non-server sockets= when the remote end goes away. qemu will delay this many seconds and then atte= mpt to reconnect. Zero disables reconnecting, and is the default. @@ -3101,6 +3104,10 @@ MAGIC_SYSRQ sequence if you use a telnet that suppor= ts sending the break sequence. Typically in unix telnet you do it with Control-] and then type "send break" followed by pressing the enter key. =20 +@item websocket:@var{host}:@var{port},server[,nowait][,nodelay] +The WebSocket protocol is used instead of raw tcp socket. The port acts as +a WebSocket server. Client mode is not supported. + @item unix:@var{path}[,server][,nowait][,reconnect=3D@var{seconds}] A unix domain socket is used instead of a tcp socket. The option works the same as if you had specified @code{-serial tcp} except the unix domain soc= ket --=20 2.17.1 From nobody Thu May 2 19:51:47 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1539902338746985.579666498118; Thu, 18 Oct 2018 15:38:58 -0700 (PDT) Received: from localhost ([::1]:45067 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gDGwS-0001OU-Sc for importer@patchew.org; Thu, 18 Oct 2018 18:38:56 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38375) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gDGtE-0007Xw-RH for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gDGtD-0003CA-8M for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:36 -0400 Received: from smtp50.i.mail.ru ([94.100.177.110]:43776) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1gDGtC-00038M-Mn for qemu-devel@nongnu.org; Thu, 18 Oct 2018 18:35:35 -0400 Received: by smtp50.i.mail.ru with esmtpa (envelope-from ) id 1gDGtA-0000Im-Lz; Fri, 19 Oct 2018 01:35:33 +0300 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=6UWXUv/LXqMOr3fUEwg9exKAZ+ByAm5RJK3l9gWkkao=; b=SSjg943nypClyTR2BFLuAYI7KeMx/Ix44D5fUCdMKdLWBzQNZOnvFBy8B6ygmAE/W/XDUpJvVacWV5DDmpkwCp//H3E118Xku/nXZXPh5NmvloDHDla2A4S+6gvvteKiLLI306zGRJQTbiTnTtHyoVNGs1tWmAS8MgGuh0iuEI4=; To: qemu-devel@nongnu.org Date: Fri, 19 Oct 2018 01:35:01 +0300 Message-Id: <20181018223501.21683-4-jusual@mail.ru> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181018223501.21683-1-jusual@mail.ru> References: <20181018223501.21683-1-jusual@mail.ru> Authentication-Results: smtp50.i.mail.ru; auth=pass smtp.auth=jusual@mail.ru smtp.mailfrom=jusual@mail.ru X-7FA49CB5: 0D63561A33F958A58EC20458778EC15C8D3DD5DEE0CB5ADD420F7130F2ECF6B38941B15DA834481FA18204E546F3947C17119E5299B287EEF6B57BC7E64490618DEB871D839B7333395957E7521B51C2545D4CF71C94A83E9FA2833FD35BB23D27C277FBC8AE2E8B47272755C61AA17BA471835C12D1D977C4224003CC8364767815B9869FA544D8090A508E0FED629923F8577A6DFFEA7C2AE38A8E97BAFFB1B3661434B16C20ACE7DDDDC251EA7DABAAAE862A0553A39223F8577A6DFFEA7CC078FC364215E4C835AC72D4465AF915EFF80C71ABB335746BA297DBC24807EA27F269C8F02392CDBB05166615B404773C9F3DD0FB1AF5EB4E70A05D1297E1BBCB5012B2E24CD356 X-Mailru-Sender: 42ECD68FB001EF9589BB0A53C8470BCA23AD7C25608359F10B32D730D3FD174D743D6B75E1F9502ABCD5BA2C93075E1EC77752E0C033A69E882C431543FD75E20226C39053983FF03453F38A29522196 X-Mras: OK X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 94.100.177.110 Subject: [Qemu-devel] [PATCH v3 3/3] tests/test-char: Check websocket chardev functionality X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Julia Suvorova via Qemu-devel Reply-To: Julia Suvorova Cc: Jim Mussared , =?UTF-8?q?Steffen=20G=C3=B6rtz?= , Julia Suvorova , Joel Stanley , Stefan Hajnoczi , marcandre.lureau@redhat.com, Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Test order: Creating server websocket chardev Creating usual tcp chardev client Sending handshake message from client Receiving handshake reply Sending ping frame with "hello" payload Receiving pong reply Sending binary data "world" Checking the received data on server side Checking of closing handshake Signed-off-by: Julia Suvorova Reviewed-by: Daniel P. Berrang=C3=A9 Reviewed-by: Marc-Andr=C3=A9 Lureau Reviewed-by: Stefan Hajnoczi --- tests/test-char.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/tests/test-char.c b/tests/test-char.c index 831e37fbf4..19c3efad72 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -420,6 +420,130 @@ static void char_socket_fdpass_test(void) } =20 =20 +static void websock_server_read(void *opaque, const uint8_t *buf, int size) +{ + g_assert_cmpint(size, =3D=3D, 5); + g_assert(memcmp(buf, "world", size) =3D=3D 0); + quit =3D 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[] =3D { "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 =3D 0; i < 6; i++) { + if (g_strstr_len(buf, size, ans[i]) =3D=3D NULL) { + return false; + } + } + + return true; +} + + +static void websock_client_read(void *opaque, const uint8_t *buf, int size) +{ + const uint8_t ping[] =3D { 0x89, 0x85, /* Ping header= */ + 0x07, 0x77, 0x9e, 0xf9, /* Masking key */ + 0x6f, 0x12, 0xf2, 0x95, 0x68 /* "hello" */ }; + + const uint8_t binary[] =3D { 0x82, 0x85, /* Binary he= ader */ + 0x74, 0x90, 0xb9, 0xdf, /* Masking key= */ + 0x03, 0xff, 0xcb, 0xb3, 0x10 /* "world" */ = }; + Chardev *chr_client =3D opaque; + + if (websock_check_http_headers((char *) buf, size)) { + qemu_chr_fe_write(chr_client->be, ping, sizeof(ping)); + } else if (buf[0] =3D=3D 0x8a && buf[1] =3D=3D 0x05) { + g_assert(strncmp((char *) buf + 2, "hello", 5) =3D=3D 0); + qemu_chr_fe_write(chr_client->be, binary, sizeof(binary)); + } else { + g_assert(buf[0] =3D=3D 0x88 && buf[1] =3D=3D 0x16); + g_assert(strncmp((char *) buf + 4, "peer requested close", 10) =3D= =3D 0); + quit =3D 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 =3D qemu_chr_new("server", + "websocket:127.0.0.1:0,server,nowait"); + const char handshake[] =3D "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=3D= =3D\r\n" + "Sec-WebSocket-Version: 13\r\n" + "Sec-WebSocket-Protocol: binary\r\n\r\n"; + const uint8_t close[] =3D { 0x88, 0x82, /* Close header */ + 0xef, 0xaa, 0xc5, 0x97, /* Masking key */ + 0xec, 0x42 /* Status code */ }; + + addr =3D object_property_get_qobject(OBJECT(chr), "addr", &error_abort= ); + qdict =3D qobject_to(QDict, addr); + port =3D qdict_get_str(qdict, "port"); + tmp =3D g_strdup_printf("tcp:127.0.0.1:%s", port); + handshake_port =3D 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 =3D qemu_chr_new("client", tmp); + 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_abo= rt)); + 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) { @@ -842,6 +966,7 @@ int main(int argc, char **argv) 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); =20 return g_test_run(); } --=20 2.17.1