[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 04/10] vnc: switch to QemuOpts, allow multiple se
From: |
Gerd Hoffmann |
Subject: |
[Qemu-devel] [PATCH v2 04/10] vnc: switch to QemuOpts, allow multiple servers |
Date: |
Wed, 10 Dec 2014 10:37:27 +0100 |
This patch switches vnc over to QemuOpts, and it (more or less
as side effect) allows multiple vnc server instances.
Signed-off-by: Gerd Hoffmann <address@hidden>
---
include/ui/console.h | 4 +-
qmp.c | 15 ++-
ui/vnc.c | 271 ++++++++++++++++++++++++++++++++-------------------
vl.c | 42 +++-----
4 files changed, 200 insertions(+), 132 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index 5ff2e27..887ed91 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -328,12 +328,14 @@ void cocoa_display_init(DisplayState *ds, int
full_screen);
/* vnc.c */
void vnc_display_init(const char *id);
-void vnc_display_open(const char *id, const char *display, Error **errp);
+void vnc_display_open(const char *id, Error **errp);
void vnc_display_add_client(const char *id, int csock, bool skipauth);
char *vnc_display_local_addr(const char *id);
#ifdef CONFIG_VNC
int vnc_display_password(const char *id, const char *password);
int vnc_display_pw_expire(const char *id, time_t expires);
+QemuOpts *vnc_parse_func(const char *str);
+int vnc_init_func(QemuOpts *opts, void *opaque);
#else
static inline int vnc_display_password(const char *id, const char *password)
{
diff --git a/qmp.c b/qmp.c
index 0b4f131..3fda973 100644
--- a/qmp.c
+++ b/qmp.c
@@ -368,7 +368,20 @@ void qmp_change_vnc_password(const char *password, Error
**errp)
static void qmp_change_vnc_listen(const char *target, Error **errp)
{
- vnc_display_open(NULL, target, errp);
+ QemuOptsList *olist = qemu_find_opts("vnc");
+ QemuOpts *opts;
+
+ if (strstr(target, "id=")) {
+ error_setg(errp, "id not supported");
+ return;
+ }
+
+ opts = qemu_opts_find(olist, "default");
+ if (opts) {
+ qemu_opts_del(opts);
+ }
+ opts = vnc_parse_func(target);
+ vnc_init_func(opts, NULL);
}
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
diff --git a/ui/vnc.c b/ui/vnc.c
index 1b86365..cf8bed8 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -31,6 +31,7 @@
#include "qemu/sockets.h"
#include "qemu/timer.h"
#include "qemu/acl.h"
+#include "qemu/config-file.h"
#include "qapi/qmp/types.h"
#include "qmp-commands.h"
#include "qemu/osdep.h"
@@ -2969,7 +2970,12 @@ static const DisplayChangeListenerOps dcl_ops = {
void vnc_display_init(const char *id)
{
- VncDisplay *vs = g_malloc0(sizeof(*vs));
+ VncDisplay *vs;
+
+ if (vnc_display_find(id) != NULL) {
+ return;
+ }
+ vs = g_malloc0(sizeof(*vs));
vs->id = strdup(id);
QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
@@ -3065,14 +3071,65 @@ char *vnc_display_local_addr(const char *id)
return vnc_socket_local_addr("%s:%s", vs->lsock);
}
-void vnc_display_open(const char *id, const char *display, Error **errp)
+static QemuOptsList qemu_vnc_opts = {
+ .name = "vnc",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_vnc_opts.head),
+ .implied_opt_name = "vnc",
+ .desc = {
+ {
+ .name = "vnc",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "websocket",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "x509",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "share",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "password",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "reverse",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "lock-key-sync",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "sasl",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "tls",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "x509verify",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "acl",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "lossy",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "non-adaptive",
+ .type = QEMU_OPT_BOOL,
+ },
+ { /* end of list */ }
+ },
+};
+
+void vnc_display_open(const char *id, Error **errp)
{
VncDisplay *vs = vnc_display_find(id);
- const char *options;
+ QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
+ const char *display, *websocket, *share;
int password = 0;
int reverse = 0;
#ifdef CONFIG_VNC_TLS
int tls = 0, x509 = 0;
+ const char *path;
#endif
#ifdef CONFIG_VNC_SASL
int sasl = 0;
@@ -3088,115 +3145,86 @@ void vnc_display_open(const char *id, const char
*display, Error **errp)
return;
}
vnc_display_close(vs);
- if (strcmp(display, "none") == 0)
- return;
+ if (!opts) {
+ return;
+ }
+ display = qemu_opt_get(opts, "vnc");
+ if (!display || strcmp(display, "none") == 0) {
+ return;
+ }
vs->display = g_strdup(display);
- vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
-
- options = display;
- while ((options = strchr(options, ','))) {
- options++;
- if (strncmp(options, "password", 8) == 0) {
- if (fips_get_state()) {
- error_setg(errp,
- "VNC password auth disabled due to FIPS mode, "
- "consider using the VeNCrypt or SASL authentication
"
- "methods as an alternative");
- goto fail;
- }
- password = 1; /* Require password auth */
- } else if (strncmp(options, "reverse", 7) == 0) {
- reverse = 1;
- } else if (strncmp(options, "no-lock-key-sync", 16) == 0) {
- lock_key_sync = 0;
+
+ password = qemu_opt_get_bool(opts, "password", false);
+ if (password && fips_get_state()) {
+ error_setg(errp,
+ "VNC password auth disabled due to FIPS mode, "
+ "consider using the VeNCrypt or SASL authentication "
+ "methods as an alternative");
+ goto fail;
+ }
+
+ reverse = qemu_opt_get_bool(opts, "reverse", false);
+ lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true);
#ifdef CONFIG_VNC_SASL
- } else if (strncmp(options, "sasl", 4) == 0) {
- sasl = 1; /* Require SASL auth */
+ sasl = qemu_opt_get_bool(opts, "sasl", false);
#endif
-#ifdef CONFIG_VNC_WS
- } else if (strncmp(options, "websocket", 9) == 0) {
- char *start, *end;
- vs->websocket = 1;
-
- /* Check for 'websocket=<port>' */
- start = strchr(options, '=');
- end = strchr(options, ',');
- if (start && (!end || (start < end))) {
- int len = end ? end-(start+1) : strlen(start+1);
- if (len < 6) {
- /* extract the host specification from display */
- char *host = NULL, *port = NULL, *host_end = NULL;
- port = g_strndup(start + 1, len);
-
- /* ipv6 hosts have colons */
- end = strchr(display, ',');
- host_end = g_strrstr_len(display, end - display, ":");
-
- if (host_end) {
- host = g_strndup(display, host_end - display + 1);
- } else {
- host = g_strndup(":", 1);
- }
- vs->ws_display = g_strconcat(host, port, NULL);
- g_free(host);
- g_free(port);
- }
- }
-#endif /* CONFIG_VNC_WS */
#ifdef CONFIG_VNC_TLS
- } else if (strncmp(options, "tls", 3) == 0) {
- tls = 1; /* Require TLS */
- } else if (strncmp(options, "x509", 4) == 0) {
- char *start, *end;
- x509 = 1; /* Require x509 certificates */
- if (strncmp(options, "x509verify", 10) == 0)
- vs->tls.x509verify = 1; /* ...and verify client certs */
-
- /* Now check for 'x509=/some/path' postfix
- * and use that to setup x509 certificate/key paths */
- start = strchr(options, '=');
- end = strchr(options, ',');
- if (start && (!end || (start < end))) {
- int len = end ? end-(start+1) : strlen(start+1);
- char *path = g_strndup(start + 1, len);
-
- VNC_DEBUG("Trying certificate path '%s'\n", path);
- if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
- error_setg(errp, "Failed to find x509 certificates/keys in
%s", path);
- g_free(path);
- goto fail;
- }
- g_free(path);
- } else {
- error_setg(errp, "No certificate path provided");
- goto fail;
- }
+ tls = qemu_opt_get_bool(opts, "tls", false);
+ path = qemu_opt_get(opts, "x509");
+ if (path) {
+ x509 = 1;
+ vs->tls.x509verify = qemu_opt_get_bool(opts, "x509verify", false);
+ if (vnc_tls_set_x509_creds_dir(vs, path) < 0) {
+ error_setg(errp, "Failed to find x509 certificates/keys in %s",
+ path);
+ goto fail;
+ }
+ }
#endif
#if defined(CONFIG_VNC_TLS) || defined(CONFIG_VNC_SASL)
- } else if (strncmp(options, "acl", 3) == 0) {
- acl = 1;
-#endif
- } else if (strncmp(options, "lossy", 5) == 0) {
-#ifdef CONFIG_VNC_JPEG
- vs->lossy = true;
+ acl = qemu_opt_get_bool(opts, "acl", false);
#endif
- } else if (strncmp(options, "non-adaptive", 12) == 0) {
- vs->non_adaptive = true;
- } else if (strncmp(options, "share=", 6) == 0) {
- if (strncmp(options+6, "ignore", 6) == 0) {
- vs->share_policy = VNC_SHARE_POLICY_IGNORE;
- } else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
- vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
- } else if (strncmp(options+6, "force-shared", 12) == 0) {
- vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
- } else {
- error_setg(errp, "unknown vnc share= option");
- goto fail;
- }
+
+ share = qemu_opt_get(opts, "share");
+ if (share) {
+ if (strcmp(share, "ignore") == 0) {
+ vs->share_policy = VNC_SHARE_POLICY_IGNORE;
+ } else if (strcmp(share, "allow-exclusive") == 0) {
+ vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+ } else if (strcmp(share, "force-shared") == 0) {
+ vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
+ } else {
+ error_setg(errp, "unknown vnc share= option");
+ goto fail;
+ }
+ } else {
+ vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+ }
+
+ #ifdef CONFIG_VNC_WS
+ websocket = qemu_opt_get(opts, "websocket");
+ if (websocket) {
+ /* extract the host specification from display */
+ char *host = NULL, *host_end = NULL;
+ vs->websocket = 1;
+
+ /* ipv6 hosts have colons */
+ host_end = strrchr(display, ':');
+ if (host_end) {
+ host = g_strndup(display, host_end - display + 1);
+ } else {
+ host = g_strdup(":");
}
+ vs->ws_display = g_strconcat(host, websocket, NULL);
+ g_free(host);
}
+#endif /* CONFIG_VNC_WS */
+#ifdef CONFIG_VNC_JPEG
+ vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
+#endif
+ vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
/* adaptive updates are only used with tight encoding and
* if lossy updates are enabled so we can disable all the
* calculations otherwise */
@@ -3407,3 +3435,44 @@ void vnc_display_add_client(const char *id, int csock,
bool skipauth)
}
vnc_connect(vs, csock, skipauth, false);
}
+
+QemuOpts *vnc_parse_func(const char *str)
+{
+ return qemu_opts_parse(qemu_find_opts("vnc"), str, 1);
+}
+
+int vnc_init_func(QemuOpts *opts, void *opaque)
+{
+ Error *local_err = NULL;
+ QemuOptsList *olist = qemu_find_opts("vnc");
+ char *id = (char *)qemu_opts_id(opts);
+
+ if (!id) {
+ /* auto-assign id if not present */
+ int i = 2;
+ id = g_strdup("default");
+ while (qemu_opts_find(olist, id)) {
+ g_free(id);
+ id = g_strdup_printf("vnc%d", i++);
+ }
+ qemu_opts_set_id(opts, id);
+ }
+ fprintf(stderr, "%s: id \"%s\"\n", __func__, id);
+
+ vnc_display_init(id);
+ vnc_display_open(id, &local_err);
+ if (local_err != NULL) {
+ error_report("Failed to start VNC server on `%s': %s",
+ qemu_opt_get(opts, "display"),
+ error_get_pretty(local_err));
+ error_free(local_err);
+ exit(1);
+ }
+ return 0;
+}
+
+static void vnc_register_config(void)
+{
+ qemu_add_opts(&qemu_vnc_opts);
+}
+machine_init(vnc_register_config);
diff --git a/vl.c b/vl.c
index 08b73ee..0bf00cf 100644
--- a/vl.c
+++ b/vl.c
@@ -158,9 +158,6 @@ int smp_cpus = 1;
int max_cpus = 0;
int smp_cores = 1;
int smp_threads = 1;
-#ifdef CONFIG_VNC
-const char *vnc_display;
-#endif
int acpi_enabled = 1;
int no_hpet = 0;
int fd_bootchk = 1;
@@ -2087,16 +2084,12 @@ static DisplayType select_display(const char *p)
#endif
} else if (strstart(p, "vnc", &opts)) {
#ifdef CONFIG_VNC
- display_remote++;
-
- if (*opts) {
- const char *nextopt;
-
- if (strstart(opts, "=", &nextopt)) {
- vnc_display = nextopt;
+ if (*opts == '=') {
+ display_remote++;
+ if (vnc_parse_func(opts+1) == NULL) {
+ exit(1);
}
- }
- if (!vnc_display) {
+ } else {
fprintf(stderr, "VNC requires a display argument vnc=<display>\n");
exit(1);
}
@@ -3563,7 +3556,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_vnc:
#ifdef CONFIG_VNC
display_remote++;
- vnc_display = optarg;
+ if (vnc_parse_func(optarg) == NULL) {
+ exit(1);
+ }
#else
fprintf(stderr, "VNC support is disabled\n");
exit(1);
@@ -4016,7 +4011,7 @@ int main(int argc, char **argv, char **envp)
#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
display_type = DT_SDL;
#elif defined(CONFIG_VNC)
- vnc_display = "localhost:0,to=99";
+ vnc_parse_func("localhost:0,to=99,id=default");
show_vnc_port = 1;
#else
display_type = DT_NONE;
@@ -4321,21 +4316,10 @@ int main(int argc, char **argv, char **envp)
#ifdef CONFIG_VNC
/* init remote displays */
- if (vnc_display) {
- Error *local_err = NULL;
- const char *id = "default";
- vnc_display_init(id);
- vnc_display_open(id, vnc_display, &local_err);
- if (local_err != NULL) {
- error_report("Failed to start VNC server on `%s': %s",
- vnc_display, error_get_pretty(local_err));
- error_free(local_err);
- exit(1);
- }
-
- if (show_vnc_port) {
- printf("VNC server running on `%s'\n", vnc_display_local_addr(id));
- }
+ qemu_opts_foreach(qemu_find_opts("vnc"), vnc_init_func, NULL, 0);
+ if (show_vnc_port) {
+ printf("VNC server running on `%s'\n",
+ vnc_display_local_addr("default"));
}
#endif
#ifdef CONFIG_SPICE
--
1.8.3.1
- [Qemu-devel] [PATCH v2 00/10] vnc: add support for multiple vnc displays, Gerd Hoffmann, 2014/12/10
- [Qemu-devel] [PATCH v2 06/10] vnc: update docs/multiseat.txt, Gerd Hoffmann, 2014/12/10
- [Qemu-devel] [PATCH v2 03/10] vnc: add display id to acl names, Gerd Hoffmann, 2014/12/10
- [Qemu-devel] [PATCH v2 01/10] vnc: remove vnc_display global, Gerd Hoffmann, 2014/12/10
- [Qemu-devel] [PATCH v2 04/10] vnc: switch to QemuOpts, allow multiple servers,
Gerd Hoffmann <=
- [Qemu-devel] [PATCH v2 10/10] monitor: add vnc websockets, Gerd Hoffmann, 2014/12/10
- [Qemu-devel] [PATCH v2 07/10] vnc: track & limit connections, Gerd Hoffmann, 2014/12/10
- [Qemu-devel] [PATCH v2 09/10] monitor: add query-vnc2 command, Gerd Hoffmann, 2014/12/10