All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 0/7] Chardev patches
@ 2018-10-30 17:36 Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 1/7] websock: fix handshake leak Marc-André Lureau
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Marc-André Lureau

The following changes since commit 3f3285491dd52014852a56135c90e428c8b507ea:

  Merge remote-tracking branch 'remotes/jnsnow/tags/bitmaps-pull-request' into staging (2018-10-30 14:09:25 +0000)

are available in the Git repository at:

  https://github.com/elmarco/qemu.git tags/chrdev-pull-request

for you to fetch changes up to 22333dd533e2a93d9da18479aee5fb49302c7933:

  editorconfig: set emacs mode (2018-10-30 21:30:22 +0400)

----------------------------------------------------------------
- add websocket support
- socket: make 'fd' incompatible with 'reconnect'
- fix a websocket leak
- unrelated editorconfig patch that missed -trivial (included for
  convenience)

----------------------------------------------------------------

Julia Suvorova (3):
  chardev/char-socket: Function headers refactoring
  chardev: Add websocket support
  tests/test-char: Check websocket chardev functionality

Marc-André Lureau (4):
  websock: fix handshake leak
  char-socket: correctly set has_reconnect when parsing QemuOpts
  char-socket: make 'fd' incompatible with 'reconnect'
  editorconfig: set emacs mode

 qapi/char.json        |   3 +
 chardev/char-socket.c | 123 ++++++++++++++++++++++++++++++-----------
 chardev/char.c        |   8 ++-
 io/channel-websock.c  |   1 +
 tests/test-char.c     | 125 ++++++++++++++++++++++++++++++++++++++++++
 .editorconfig         |  21 ++++++-
 qemu-options.hx       |  13 ++++-
 7 files changed, 257 insertions(+), 37 deletions(-)

-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PULL 1/7] websock: fix handshake leak
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
@ 2018-10-30 17:36 ` Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 2/7] char-socket: correctly set has_reconnect when parsing QemuOpts Marc-André Lureau
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, Marc-André Lureau, Daniel P . Berrangé,
	Philippe Mathieu-Daudé

Missed in f69a8bde293.
Thanks Valgrind:

==955== 217 bytes in 1 blocks are definitely lost in loss record 275 of 321
==955==    at 0x483A965: realloc (vg_replace_malloc.c:785)
==955==    by 0x50B6839: __vasprintf_chk (in /usr/lib64/libc-2.28.so)
==955==    by 0x49AA05C: g_vasprintf (in /usr/lib64/libglib-2.0.so.0.5800.1)
==955==    by 0x4983440: g_strdup_vprintf (in /usr/lib64/libglib-2.0.so.0.5800.1)
==955==    by 0x126048: qio_channel_websock_handshake_send_res (channel-websock.c:162)
==955==    by 0x1266E6: qio_channel_websock_handshake_send_res_ok (channel-websock.c:362)
==955==    by 0x126D3E: qio_channel_websock_handshake_process (channel-websock.c:468)
==955==    by 0x126EF2: qio_channel_websock_handshake_read (channel-websock.c:511)
==955==    by 0x12715B: qio_channel_websock_handshake_io (channel-websock.c:571)
==955==    by 0x125027: qio_channel_fd_source_dispatch (channel-watch.c:84)
==955==    by 0x496326C: g_main_context_dispatch (in /usr/lib64/libglib-2.0.so.0.5800.1)
==955==    by 0x169EC3: glib_pollfds_poll (main-loop.c:215)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 io/channel-websock.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/io/channel-websock.c b/io/channel-websock.c
index e6608b969d..dc43dc6bb9 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -163,6 +163,7 @@ qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc,
     responselen = strlen(response);
     buffer_reserve(&ioc->encoutput, responselen);
     buffer_append(&ioc->encoutput, response, responselen);
+    g_free(response);
     va_end(vargs);
 }
 
-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PULL 2/7] char-socket: correctly set has_reconnect when parsing QemuOpts
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 1/7] websock: fix handshake leak Marc-André Lureau
@ 2018-10-30 17:36 ` Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 3/7] char-socket: make 'fd' incompatible with 'reconnect' Marc-André Lureau
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, Marc-André Lureau, Daniel P . Berrangé

qemu_chr_parse_socket() fills all ChardevSocket fields, but that
doesn't reflect correctly the arguments given with the options / on
the command line. "reconnect" takes a number as argument, and the
default value is 0, which doesn't help to identify the missing
option. The other arguments have default values that are less
problematic, leave them set by default for now.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 chardev/char-socket.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index a75b46d9fe..64e24cb2ab 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -1117,7 +1117,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
     sock->tn3270 = is_tn3270;
     sock->has_wait = true;
     sock->wait = is_waitconnect;
-    sock->has_reconnect = true;
+    sock->has_reconnect = qemu_opt_find(opts, "reconnect");
     sock->reconnect = reconnect;
     sock->tls_creds = g_strdup(tls_creds);
 
-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PULL 3/7] char-socket: make 'fd' incompatible with 'reconnect'
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 1/7] websock: fix handshake leak Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 2/7] char-socket: correctly set has_reconnect when parsing QemuOpts Marc-André Lureau
@ 2018-10-30 17:36 ` Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 4/7] chardev/char-socket: Function headers refactoring Marc-André Lureau
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, Marc-André Lureau, Daniel P . Berrangé

A chardev socket created with the 'fd=' argument is not going to
handle reconnection properly by recycling the same fd (or not in a
supported way). Let's forbid this case.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
---
 chardev/char-socket.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 64e24cb2ab..e4137ccd3c 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -997,6 +997,10 @@ static void qmp_chardev_open_socket(Chardev *chr,
 
     s->addr = addr = socket_address_flatten(sock->addr);
 
+    if (sock->has_reconnect && addr->type == SOCKET_ADDRESS_TYPE_FD) {
+        error_setg(errp, "'reconnect' option is incompatible with 'fd'");
+        goto error;
+    }
     qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
     /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
     if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) {
-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PULL 4/7] chardev/char-socket: Function headers refactoring
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
                   ` (2 preceding siblings ...)
  2018-10-30 17:36 ` [Qemu-devel] [PULL 3/7] char-socket: make 'fd' incompatible with 'reconnect' Marc-André Lureau
@ 2018-10-30 17:36 ` Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 5/7] chardev: Add websocket support Marc-André Lureau
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, Julia Suvorova, Daniel P . Berrangé,
	Marc-André Lureau, Stefan Hajnoczi

From: Julia Suvorova via Qemu-devel <qemu-devel@nongnu.org>

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 <jusual@mail.ru>
Message-Id: <20181018223501.21683-2-jusual@mail.ru>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 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 e4137ccd3c..0bbeb83ceb 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 = 0;
 }
 
-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)
 
     g_free(chr->filename);
     if (s->addr) {
-        chr->filename = SocketAddress_to_str("disconnected:", s->addr,
-                                             s->is_listen, s->is_telnet);
+        chr->filename = qemu_chr_socket_address(s, "disconnected:");
     } else {
         chr->filename = g_strdup("disconnected:socket");
     }
@@ -514,10 +520,12 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8_t *buf, int len)
     return size;
 }
 
-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 = &s->sioc->localAddr;
+    struct sockaddr_storage *ps = &s->sioc->remoteAddr;
+    socklen_t ss_len = s->sioc->localAddrLen;
+    socklen_t ps_len = s->sioc->remoteAddrLen;
     char shost[NI_MAXHOST], sserv[NI_MAXSERV];
     char phost[NI_MAXHOST], pserv[NI_MAXSERV];
     const char *left = "", *right = "";
@@ -527,7 +535,7 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, 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  = "[";
@@ -539,9 +547,9 @@ static char *sockaddr_to_str(struct sockaddr_storage *ss, 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);
 
     default:
@@ -576,10 +584,7 @@ static void tcp_chr_connect(void *opaque)
     SocketChardev *s = SOCKET_CHARDEV(opaque);
 
     g_free(chr->filename);
-    chr->filename = sockaddr_to_str(
-        &s->sioc->localAddr, s->sioc->localAddrLen,
-        &s->sioc->remoteAddr, s->sioc->remoteAddrLen,
-        s->is_listen, s->is_telnet);
+    chr->filename = qemu_chr_compute_filename(s);
 
     s->connected = 1;
     update_ioc_handlers(s);
-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PULL 5/7] chardev: Add websocket support
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
                   ` (3 preceding siblings ...)
  2018-10-30 17:36 ` [Qemu-devel] [PULL 4/7] chardev/char-socket: Function headers refactoring Marc-André Lureau
@ 2018-10-30 17:36 ` Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 6/7] tests/test-char: Check websocket chardev functionality Marc-André Lureau
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, Julia Suvorova, Daniel P . Berrangé,
	Stefan Hajnoczi, Marc-André Lureau

From: Julia Suvorova via Qemu-devel <qemu-devel@nongnu.org>

New option "websocket" added to allow using WebSocket protocol for
chardev socket backend.
Example:
    -chardev socket,websocket,server,id=...

Signed-off-by: Julia Suvorova <jusual@mail.ru>
Message-Id: <20181018223501.21683-3-jusual@mail.ru>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/char.json        |  3 ++
 chardev/char-socket.c | 64 ++++++++++++++++++++++++++++++++++++++-----
 chardev/char.c        |  8 +++++-
 qemu-options.hx       | 13 +++++++--
 4 files changed, 77 insertions(+), 11 deletions(-)

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' }
 
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;
     }
@@ -860,6 +863,9 @@ QemuOptsList qemu_chardev_opts = {
         },{
             .name = "tls-creds",
             .type = QEMU_OPT_STRING,
+        },{
+            .name = "websocket",
+            .type = QEMU_OPT_BOOL,
         },{
             .name = "width",
             .type = QEMU_OPT_NUMBER,
diff --git a/qemu-options.hx b/qemu-options.hx
index 08f8516a9a..38c7a978c1 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2414,9 +2414,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
     "-chardev help\n"
     "-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
     "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4][,ipv6][,nodelay][,reconnect=seconds]\n"
-    "         [,server][,nowait][,telnet][,reconnect=seconds][,mux=on|off]\n"
+    "         [,server][,nowait][,telnet][,websocket][,reconnect=seconds][,mux=on|off]\n"
     "         [,logfile=PATH][,logappend=on|off][,tls-creds=ID] (tcp)\n"
-    "-chardev socket,id=id,path=path[,server][,nowait][,telnet][,reconnect=seconds]\n"
+    "-chardev socket,id=id,path=path[,server][,nowait][,telnet][,websocket][,reconnect=seconds]\n"
     "         [,mux=on|off][,logfile=PATH][,logappend=on|off] (unix)\n"
     "-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n"
     "         [,localport=localport][,ipv4][,ipv6][,mux=on|off]\n"
@@ -2544,7 +2544,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.
 
-@item -chardev socket,id=@var{id}[,@var{TCP options} or @var{unix options}][,server][,nowait][,telnet][,reconnect=@var{seconds}][,tls-creds=@var{id}]
+@item -chardev socket,id=@var{id}[,@var{TCP options} or @var{unix options}][,server][,nowait][,telnet][,websocket][,reconnect=@var{seconds}][,tls-creds=@var{id}]
 
 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
@@ -2558,6 +2558,9 @@ connect to a listening socket.
 @option{telnet} specifies that traffic on the socket should interpret telnet
 escape sequences.
 
+@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 attempt
 to reconnect.  Zero disables reconnecting, and is the default.
@@ -3106,6 +3109,10 @@ MAGIC_SYSRQ sequence if you use a telnet that supports sending the break
 sequence.  Typically in unix telnet you do it with Control-] and then
 type "send break" followed by pressing the enter key.
 
+@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=@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 socket
-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PULL 6/7] tests/test-char: Check websocket chardev functionality
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
                   ` (4 preceding siblings ...)
  2018-10-30 17:36 ` [Qemu-devel] [PULL 5/7] chardev: Add websocket support Marc-André Lureau
@ 2018-10-30 17:36 ` Marc-André Lureau
  2018-10-30 17:36 ` [Qemu-devel] [PULL 7/7] editorconfig: set emacs mode Marc-André Lureau
  2018-10-31 16:11 ` [Qemu-devel] [PULL 0/7] Chardev patches Peter Maydell
  7 siblings, 0 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: peter.maydell, Julia Suvorova, Daniel P . Berrangé,
	Marc-André Lureau, Stefan Hajnoczi

From: Julia Suvorova via Qemu-devel <qemu-devel@nongnu.org>

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 <jusual@mail.ru>
Message-Id: <20181018223501.21683-4-jusual@mail.ru>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 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)
 }
 
 
+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,nowait");
+    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);
+    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)
 {
@@ -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);
 
     return g_test_run();
 }
-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [Qemu-devel] [PULL 7/7] editorconfig: set emacs mode
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
                   ` (5 preceding siblings ...)
  2018-10-30 17:36 ` [Qemu-devel] [PULL 6/7] tests/test-char: Check websocket chardev functionality Marc-André Lureau
@ 2018-10-30 17:36 ` Marc-André Lureau
  2018-10-31 16:11 ` [Qemu-devel] [PULL 0/7] Chardev patches Peter Maydell
  7 siblings, 0 replies; 9+ messages in thread
From: Marc-André Lureau @ 2018-10-30 17:36 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Marc-André Lureau, Markus Armbruster

Some time ago, I proposed to use an (eval) in .dir-locals.el to set
the mode for all json files and Makefile. Unfortunately, this isn't
safe, and emacs will prompt the user, which isn't very friendly.

Fortunately, editorconfig provides a special config key which does
allow to set the emacs mode. Add a few missing entries and set the
emacs mode.

Update top comment to provide a short summary about the file and the
IDE plugins while at it.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
---
 .editorconfig | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/.editorconfig b/.editorconfig
index b2022e391a..1582883393 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,4 +1,10 @@
-# http://editorconfig.org
+# EditorConfig is a file format and collection of text editor plugins
+# for maintaining consistent coding styles between different editors
+# and IDEs. Most popular editors support this either natively or via
+# plugin.
+#
+# Check https://editorconfig.org for details.
+
 root = true
 
 [*]
@@ -6,10 +12,23 @@ end_of_line = lf
 insert_final_newline = true
 charset = utf-8
 
+[*.mak]
+indent_style = tab
+indent_size = 8
+file_type_emacs = makefile
+
 [Makefile*]
 indent_style = tab
 indent_size = 8
+file_type_emacs = makefile
 
 [*.{c,h}]
 indent_style = space
 indent_size = 4
+
+[*.{vert,frag}]
+file_type_emacs = glsl
+
+[*.json]
+indent_style = space
+file_type_emacs = python
-- 
2.19.1.708.g4ede3d42df

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [Qemu-devel] [PULL 0/7] Chardev patches
  2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
                   ` (6 preceding siblings ...)
  2018-10-30 17:36 ` [Qemu-devel] [PULL 7/7] editorconfig: set emacs mode Marc-André Lureau
@ 2018-10-31 16:11 ` Peter Maydell
  7 siblings, 0 replies; 9+ messages in thread
From: Peter Maydell @ 2018-10-31 16:11 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: QEMU Developers

On 30 October 2018 at 17:36, Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
> The following changes since commit 3f3285491dd52014852a56135c90e428c8b507ea:
>
>   Merge remote-tracking branch 'remotes/jnsnow/tags/bitmaps-pull-request' into staging (2018-10-30 14:09:25 +0000)
>
> are available in the Git repository at:
>
>   https://github.com/elmarco/qemu.git tags/chrdev-pull-request
>
> for you to fetch changes up to 22333dd533e2a93d9da18479aee5fb49302c7933:
>
>   editorconfig: set emacs mode (2018-10-30 21:30:22 +0400)
>
> ----------------------------------------------------------------
> - add websocket support
> - socket: make 'fd' incompatible with 'reconnect'
> - fix a websocket leak
> - unrelated editorconfig patch that missed -trivial (included for
>   convenience)
>
> ----------------------------------------------------------------
>
> Julia Suvorova (3):
>   chardev/char-socket: Function headers refactoring
>   chardev: Add websocket support
>   tests/test-char: Check websocket chardev functionality

Hi -- it looks like this pull request includes some
commits where the author field is "somebody  via
Qemu-devel <qemu-devel@nongnu.org>" (this is an artefact
of the mailing list's handling of senders with SPF setups).
Could you fix up those commits to have the right email
address for their authors, please?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-10-31 16:11 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-30 17:36 [Qemu-devel] [PULL 0/7] Chardev patches Marc-André Lureau
2018-10-30 17:36 ` [Qemu-devel] [PULL 1/7] websock: fix handshake leak Marc-André Lureau
2018-10-30 17:36 ` [Qemu-devel] [PULL 2/7] char-socket: correctly set has_reconnect when parsing QemuOpts Marc-André Lureau
2018-10-30 17:36 ` [Qemu-devel] [PULL 3/7] char-socket: make 'fd' incompatible with 'reconnect' Marc-André Lureau
2018-10-30 17:36 ` [Qemu-devel] [PULL 4/7] chardev/char-socket: Function headers refactoring Marc-André Lureau
2018-10-30 17:36 ` [Qemu-devel] [PULL 5/7] chardev: Add websocket support Marc-André Lureau
2018-10-30 17:36 ` [Qemu-devel] [PULL 6/7] tests/test-char: Check websocket chardev functionality Marc-André Lureau
2018-10-30 17:36 ` [Qemu-devel] [PULL 7/7] editorconfig: set emacs mode Marc-André Lureau
2018-10-31 16:11 ` [Qemu-devel] [PULL 0/7] Chardev patches Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.