From patchwork Thu Oct 27 19:02:11 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Capitulino X-Patchwork-Id: 122233 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 4CCBE1007D3 for ; Fri, 28 Oct 2011 06:32:47 +1100 (EST) Received: from localhost ([::1]:44385 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RJVgx-00016T-Ex for incoming@patchwork.ozlabs.org; Thu, 27 Oct 2011 15:32:43 -0400 Received: from eggs.gnu.org ([140.186.70.92]:44218) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RJVES-0004L6-RP for qemu-devel@nongnu.org; Thu, 27 Oct 2011 15:03:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RJVE3-00022E-62 for qemu-devel@nongnu.org; Thu, 27 Oct 2011 15:02:56 -0400 Received: from mx1.redhat.com ([209.132.183.28]:13845) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RJVE2-00021j-Q3 for qemu-devel@nongnu.org; Thu, 27 Oct 2011 15:02:51 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p9RJ2mZj030545 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Thu, 27 Oct 2011 15:02:48 -0400 Received: from localhost (ovpn-113-103.phx2.redhat.com [10.3.113.103]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p9RJ2lCo011345; Thu, 27 Oct 2011 15:02:47 -0400 From: Luiz Capitulino To: aliguori@us.ibm.com Date: Thu, 27 Oct 2011 17:02:11 -0200 Message-Id: <1319742136-8691-15-git-send-email-lcapitulino@redhat.com> In-Reply-To: <1319742136-8691-1-git-send-email-lcapitulino@redhat.com> References: <1319742136-8691-1-git-send-email-lcapitulino@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 209.132.183.28 Cc: mdroth@linux.vnet.ibm.com, qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH 14/19] qapi: Convert query-spice X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Anthony Liguori Signed-off-by: Luiz Capitulino --- hmp.c | 43 +++++++++++++++++ hmp.h | 1 + monitor.c | 13 +----- qapi-schema.json | 74 +++++++++++++++++++++++++++++ qmp-commands.hx | 8 +++ qmp.c | 12 +++++ ui/spice-core.c | 139 ++++++++++++++++++++++------------------------------- 7 files changed, 197 insertions(+), 93 deletions(-) diff --git a/hmp.c b/hmp.c index 6d86fe3..aae13c0 100644 --- a/hmp.c +++ b/hmp.c @@ -306,6 +306,49 @@ out: qapi_free_VncInfo(info); } +void hmp_info_spice(Monitor *mon) +{ + SpiceChannelList *chan; + SpiceInfo *info; + + info = qmp_query_spice(NULL); + + if (!info->enabled) { + monitor_printf(mon, "Server: disabled\n"); + goto out; + } + + monitor_printf(mon, "Server:\n"); + if (info->has_port) { + monitor_printf(mon, " address: %s:%" PRId64 "\n", + info->host, info->port); + } + if (info->has_tls_port) { + monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n", + info->host, info->tls_port); + } + monitor_printf(mon, " auth: %s\n", info->auth); + monitor_printf(mon, " compiled: %s\n", info->compiled_version); + + if (!info->has_channels || info->channels == NULL) { + monitor_printf(mon, "Channels: none\n"); + } else { + for (chan = info->channels; chan; chan = chan->next) { + monitor_printf(mon, "Channel:\n"); + monitor_printf(mon, " address: %s:%s%s\n", + chan->value->host, chan->value->port, + chan->value->tls ? " [tls]" : ""); + monitor_printf(mon, " session: %" PRId64 "\n", + chan->value->connection_id); + monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n", + chan->value->channel_type, chan->value->channel_id); + } + } + +out: + qapi_free_SpiceInfo(info); +} + void hmp_quit(Monitor *mon, const QDict *qdict) { monitor_suspend(mon); diff --git a/hmp.h b/hmp.h index 7713348..09f3a01 100644 --- a/hmp.h +++ b/hmp.h @@ -29,6 +29,7 @@ void hmp_info_cpus(Monitor *mon); void hmp_info_block(Monitor *mon); void hmp_info_blockstats(Monitor *mon); void hmp_info_vnc(Monitor *mon); +void hmp_info_spice(Monitor *mon); void hmp_quit(Monitor *mon, const QDict *qdict); void hmp_stop(Monitor *mon, const QDict *qdict); void hmp_system_reset(Monitor *mon, const QDict *qdict); diff --git a/monitor.c b/monitor.c index d7c72bb..fc3da38 100644 --- a/monitor.c +++ b/monitor.c @@ -2857,8 +2857,7 @@ static const mon_cmd_t info_cmds[] = { .args_type = "", .params = "", .help = "show the spice server status", - .user_print = do_info_spice_print, - .mhandler.info_new = do_info_spice, + .mhandler.info = hmp_info_spice, }, #endif { @@ -2965,16 +2964,6 @@ static const mon_cmd_t qmp_query_cmds[] = { .user_print = do_pci_info_print, .mhandler.info_new = do_pci_info, }, -#if defined(CONFIG_SPICE) - { - .name = "spice", - .args_type = "", - .params = "", - .help = "show the spice server status", - .user_print = do_info_spice_print, - .mhandler.info_new = do_info_spice, - }, -#endif { .name = "balloon", .args_type = "", diff --git a/qapi-schema.json b/qapi-schema.json index 23be143..087a463 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -585,6 +585,80 @@ { 'command': 'query-vnc', 'returns': 'VncInfo' } ## +# @SpiceChannel +# +# Information about a SPICE client channel. +# +# @host: The host name of the client. QEMU tries to resolve this to a DNS name +# when possible. +# +# @family: 'ipv6' if the client is connected via IPv6 and TCP +# 'ipv4' if the client is connected via IPv4 and TCP +# 'unix' if the client is connected via a unix domain socket +# 'unknown' otherwise +# +# @port: The client's port number. +# +# @connection-id: SPICE connection id number. All channels with the same id +# belong to the same SPICE session. +# +# @connection-type: SPICE channel type number. "1" is the main control channel, +# filter for this one if you want track spice sessions only +# +# @channel-id: SPICE channel ID number. Usually "0", might be different needed +# when multiple channels of the same type exist, such as multiple +# display channels in a multihead setup +# +# @tls: true if the channel is encrypted, false otherwise. +# +# Since: 0.14.0 +## +{ 'type': 'SpiceChannel', + 'data': {'host': 'str', 'family': 'str', 'port': 'str', + 'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int', + 'tls': 'bool'} } + +## +# @SpiceInfo +# +# Information about the SPICE session. +# +# @enabled: true if the SPICE server is enabled, false otherwise +# +# @host: #optional The hostname the SPICE server is bound to. This depends on +# the name resolution on the host and may be an IP address. +# +# @port: #optional The SPICE server's port number. +# +# @compiled-version: #optional SPICE server version. +# +# @tls-port: #optional The SPICE server's TLS port number. +# +# @auth: #optional the current authentication type used by the server +# 'none' if no authentication is being used +# 'spice' (TODO: describe) +# +# @channels: a list of @SpiceChannel for each active spice channel +# +# Since: 0.14.0 +## +{ 'type': 'SpiceInfo', + 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int', + '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', + '*channels': ['SpiceChannel']} } + +## +# @query-spice +# +# Returns information about the current SPICE server +# +# Returns: @SpiceInfo +# +# Since: 0.14.0 +## +{ 'command': 'query-spice', 'returns': 'SpiceInfo' } + +## # @quit: # # This command will cause the QEMU process to exit gracefully. While every diff --git a/qmp-commands.hx b/qmp-commands.hx index 0953d3f..e99c240 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1817,6 +1817,14 @@ Example: EQMP +#if defined(CONFIG_SPICE) + { + .name = "query-spice", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_spice, + }, +#endif + SQMP query-name ---------- diff --git a/qmp.c b/qmp.c index 3a58cfe..511dd62 100644 --- a/qmp.c +++ b/qmp.c @@ -105,3 +105,15 @@ VncInfo *qmp_query_vnc(Error **errp) return NULL; }; #endif + +#ifndef CONFIG_SPICE +/* If SPICE support is enabled, the "true" query-spice command is + defined in the SPICE subsystem. Also note that we use a small + trick to maintain query-spice's original behavior, which is not + to be available in the namespace if SPICE is not compiled in */ +SpiceInfo *qmp_query_spice(Error **errp) +{ + error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice"); + return NULL; +}; +#endif diff --git a/ui/spice-core.c b/ui/spice-core.c index b33366e..f556849 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -27,6 +27,7 @@ #include "qemu-queue.h" #include "qemu-x509.h" #include "qemu_socket.h" +#include "qmp-commands.h" #include "qint.h" #include "qbool.h" #include "qstring.h" @@ -194,22 +195,6 @@ static void add_channel_info(QDict *dict, SpiceChannelEventInfo *info) qdict_put(dict, "tls", qbool_from_int(tls)); } -static QList *channel_list_get(void) -{ - ChannelList *item; - QList *list; - QDict *dict; - - list = qlist_new(); - QTAILQ_FOREACH(item, &channel_list, link) { - dict = qdict_new(); - add_addr_info(dict, &item->info->paddr, item->info->plen); - add_channel_info(dict, item->info); - qlist_append(list, dict); - } - return list; -} - static void channel_event(int event, SpiceChannelEventInfo *info) { static const int qevent[] = { @@ -351,98 +336,90 @@ static const char *wan_compression_names[] = { /* functions for the rest of qemu */ -static void info_spice_iter(QObject *obj, void *opaque) +static SpiceChannelList *qmp_query_spice_channels(void) { - QDict *client; - Monitor *mon = opaque; - - client = qobject_to_qdict(obj); - monitor_printf(mon, "Channel:\n"); - monitor_printf(mon, " address: %s:%s%s\n", - qdict_get_str(client, "host"), - qdict_get_str(client, "port"), - qdict_get_bool(client, "tls") ? " [tls]" : ""); - monitor_printf(mon, " session: %" PRId64 "\n", - qdict_get_int(client, "connection-id")); - monitor_printf(mon, " channel: %d:%d\n", - (int)qdict_get_int(client, "channel-type"), - (int)qdict_get_int(client, "channel-id")); -} - -void do_info_spice_print(Monitor *mon, const QObject *data) -{ - QDict *server; - QList *channels; - const char *host; - int port; - - server = qobject_to_qdict(data); - if (qdict_get_bool(server, "enabled") == 0) { - monitor_printf(mon, "Server: disabled\n"); - return; - } + SpiceChannelList *cur_item = NULL, *head = NULL; + ChannelList *item; - monitor_printf(mon, "Server:\n"); - host = qdict_get_str(server, "host"); - port = qdict_get_try_int(server, "port", -1); - if (port != -1) { - monitor_printf(mon, " address: %s:%d\n", host, port); - } - port = qdict_get_try_int(server, "tls-port", -1); - if (port != -1) { - monitor_printf(mon, " address: %s:%d [tls]\n", host, port); + QTAILQ_FOREACH(item, &channel_list, link) { + SpiceChannelList *chan; + char host[NI_MAXHOST], port[NI_MAXSERV]; + + chan = g_malloc0(sizeof(*chan)); + chan->value = g_malloc0(sizeof(*chan->value)); + + getnameinfo(&item->info->paddr, item->info->plen, + host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV); + chan->value->host = g_strdup(host); + chan->value->port = g_strdup(port); + chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family)); + + chan->value->connection_id = item->info->connection_id; + chan->value->channel_type = item->info->type; + chan->value->channel_id = item->info->id; + chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS; + + /* XXX: waiting for the qapi to support GSList */ + if (!cur_item) { + head = cur_item = chan; + } else { + cur_item->next = chan; + cur_item = chan; + } } - monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth")); - monitor_printf(mon, " compiled: %s\n", - qdict_get_str(server, "compiled-version")); - channels = qdict_get_qlist(server, "channels"); - if (qlist_empty(channels)) { - monitor_printf(mon, "Channels: none\n"); - } else { - qlist_iter(channels, info_spice_iter, mon); - } + return head; } -void do_info_spice(Monitor *mon, QObject **ret_data) +SpiceInfo *qmp_query_spice(Error **errp) { QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); - QDict *server; - QList *clist; - const char *addr; int port, tls_port; + const char *addr; + SpiceInfo *info; char version_string[20]; /* 12 = |255.255.255\0| is the max */ + info = g_malloc0(sizeof(*info)); + if (!spice_server) { - *ret_data = qobject_from_jsonf("{ 'enabled': false }"); - return; + info->enabled = false; + return info; } + info->enabled = true; + addr = qemu_opt_get(opts, "addr"); port = qemu_opt_get_number(opts, "port", 0); tls_port = qemu_opt_get_number(opts, "tls-port", 0); - clist = channel_list_get(); - server = qdict_new(); - qdict_put(server, "enabled", qbool_from_int(true)); - qdict_put(server, "auth", qstring_from_str(auth)); - qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0")); + info->has_auth = true; + info->auth = g_strdup(auth); + + info->has_host = true; + info->host = g_strdup(addr ? addr : "0.0.0.0"); + + info->has_compiled_version = true; snprintf(version_string, sizeof(version_string), "%d.%d.%d", (SPICE_SERVER_VERSION & 0xff0000) >> 16, (SPICE_SERVER_VERSION & 0xff00) >> 8, SPICE_SERVER_VERSION & 0xff); - qdict_put(server, "compiled-version", qstring_from_str(version_string)); + info->compiled_version = g_strdup(version_string); + if (port) { - qdict_put(server, "port", qint_from_int(port)); + info->has_port = true; + info->port = port; } if (tls_port) { - qdict_put(server, "tls-port", qint_from_int(tls_port)); - } - if (clist) { - qdict_put(server, "channels", clist); + info->has_tls_port = true; + info->tls_port = tls_port; } - *ret_data = QOBJECT(server); + /* for compatibility with the original command */ + info->has_channels = true; + info->channels = qmp_query_spice_channels(); + + return info; } static void migration_state_notifier(Notifier *notifier, void *data)