[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 04/10] vnc: switch to QemuOpts, allow multipl
From: |
Gonglei |
Subject: |
Re: [Qemu-devel] [PATCH v2 04/10] vnc: switch to QemuOpts, allow multiple servers |
Date: |
Thu, 11 Dec 2014 10:59:15 +0800 |
User-agent: |
Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20120327 Thunderbird/11.0.1 |
On 2014/12/10 17:37, Gerd Hoffmann wrote:
> 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);
A debug message, isn't it?
> +
> + 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);
Now, this function is called by main() and qmp_change_vnc_listen() ,
That's ok for main() exit if encounter any errors, but don't adapt to qmp
command IMHO.
Regards,
-Gonglei
> + }
> + 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
- [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, 2014/12/10
- Re: [Qemu-devel] [PATCH v2 04/10] vnc: switch to QemuOpts, allow multiple servers,
Gonglei <=
- [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