From 45220a9e3e4d8f7ba5e71e51f240a13f5fff70d7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 5 Jan 2011 15:29:38 -0200 Subject: [PATCH 33/48] spice: add qmp 'query-spice' and hmp 'info spice' commands. RH-Author: Gerd Hoffmann Message-id: <1294241382-17988-35-git-send-email-kraxel@redhat.com> Patchwork-id: 15769 O-Subject: [RHEL-6 kvm PATCH 34/38] spice: add qmp 'query-spice' and hmp 'info spice' commands. Bugzilla: 642131 634153 615947 632458 631832 647865 RH-Acked-by: Uri Lublin RH-Acked-by: Alon Levy RH-Acked-by: Hans de Goede The patch adds a 'query-spice' monitor command which returns informations about the spice server configuration and also a list of channel connections. upstream: cb42a870c3f5b38911b1428cb785dd702bc47d0f Signed-off-by: Gerd Hoffmann --- monitor.c | 10 ++++ qemu-monitor.hx | 70 ++++++++++++++++++++++++++++ ui/qemu-spice.h | 3 + ui/spice-core.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+), 0 deletions(-) Signed-off-by: Luiz Capitulino --- monitor.c | 10 ++++ qemu-monitor.hx | 70 ++++++++++++++++++++++++++++ ui/qemu-spice.h | 3 + ui/spice-core.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+), 0 deletions(-) diff --git a/monitor.c b/monitor.c index 2733007..4af4fdc 100644 --- a/monitor.c +++ b/monitor.c @@ -2772,6 +2772,16 @@ static const mon_cmd_t info_cmds[] = { .user_print = do_info_vnc_print, .mhandler.info_new = do_info_vnc, }, +#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 = "name", .args_type = "", diff --git a/qemu-monitor.hx b/qemu-monitor.hx index dc82b0c..af00d74 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -2222,6 +2222,76 @@ STEXI show the current VM name ETEXI SQMP +query-spice +----------- + +Show SPICE server information. + +Return a json-object with server information. Connected clients are returned +as a json-array of json-objects. + +The main json-object contains the following: + +- "enabled": true or false (json-bool) +- "host": server's IP address (json-string) +- "port": server's port number (json-int, optional) +- "tls-port": server's port number (json-int, optional) +- "auth": authentication method (json-string) + - Possible values: "none", "spice" +- "channels": a json-array of all active channels clients + +Channels are described by a json-object, each one contain the following: + +- "host": client's IP address (json-string) +- "family": address family (json-string) + - Possible values: "ipv4", "ipv6", "unix", "unknown" +- "port": client's port number (json-string) +- "connection-id": spice connection id. All channels with the same id + belong to the same spice session (json-int) +- "channel-type": channel type. "1" is the main control channel, filter for + this one if you want track spice sessions only (json-int) +- "channel-id": channel id. Usually "0", might be different needed when + multiple channels of the same type exist, such as multiple + display channels in a multihead setup (json-int) +- "tls": whevener the channel is encrypted (json-bool) + +Example: + +-> { "execute": "query-spice" } +<- { + "return": { + "enabled": true, + "auth": "spice", + "port": 5920, + "tls-port": 5921, + "host": "0.0.0.0", + "channels": [ + { + "port": "54924", + "family": "ipv4", + "channel-type": 1, + "connection-id": 1804289383, + "host": "127.0.0.1", + "channel-id": 0, + "tls": true + }, + { + "port": "36710", + "family": "ipv4", + "channel-type": 4, + "connection-id": 1804289383, + "host": "127.0.0.1", + "channel-id": 0, + "tls": false + }, + [ ... more channels follow ... ] + ] + } + } + +EQMP + +SQMP query-name ---------- diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 0e3ad9b..8b23ac9 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -33,6 +33,9 @@ void qemu_spice_audio_init(void); void qemu_spice_display_init(DisplayState *ds); int qemu_spice_add_interface(SpiceBaseInstance *sin); +void do_info_spice_print(Monitor *mon, const QObject *data); +void do_info_spice(Monitor *mon, QObject **ret_data); + #else /* CONFIG_SPICE */ #define using_spice 0 diff --git a/ui/spice-core.c b/ui/spice-core.c index 871398e..833be32 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -131,6 +131,36 @@ static void watch_remove(SpiceWatch *watch) #if SPICE_INTERFACE_CORE_MINOR >= 3 +typedef struct ChannelList ChannelList; +struct ChannelList { + SpiceChannelEventInfo *info; + QTAILQ_ENTRY(ChannelList) link; +}; +static QTAILQ_HEAD(, ChannelList) channel_list = QTAILQ_HEAD_INITIALIZER(channel_list); + +static void channel_list_add(SpiceChannelEventInfo *info) +{ + ChannelList *item; + + item = qemu_mallocz(sizeof(*item)); + item->info = info; + QTAILQ_INSERT_TAIL(&channel_list, item, link); +} + +static void channel_list_del(SpiceChannelEventInfo *info) +{ + ChannelList *item; + + QTAILQ_FOREACH(item, &channel_list, link) { + if (item->info != info) { + continue; + } + QTAILQ_REMOVE(&channel_list, item, link); + qemu_free(item); + return; + } +} + static void add_addr_info(QDict *dict, struct sockaddr *addr, int len) { char host[NI_MAXHOST], port[NI_MAXSERV]; @@ -155,6 +185,22 @@ 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[] = { @@ -174,6 +220,10 @@ static void channel_event(int event, SpiceChannelEventInfo *info) if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { qdict_put(server, "auth", qstring_from_str(auth)); add_channel_info(client, info); + channel_list_add(info); + } + if (event == SPICE_CHANNEL_EVENT_DISCONNECTED) { + channel_list_del(info); } data = qobject_from_jsonf("{ 'client': %p, 'server': %p }", @@ -278,6 +328,92 @@ static const char *wan_compression_names[] = { /* functions for the rest of qemu */ +static void info_spice_iter(QObject *obj, void *opaque) +{ + 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; + } + + 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); + } + monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth")); + + channels = qdict_get_qlist(server, "channels"); + if (qlist_empty(channels)) { + monitor_printf(mon, "Channels: none\n"); + } else { + qlist_iter(channels, info_spice_iter, mon); + } +} + +void do_info_spice(Monitor *mon, QObject **ret_data) +{ + QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); + QDict *server; + QList *clist; + const char *addr; + int port, tls_port; + + if (!spice_server) { + *ret_data = qobject_from_jsonf("{ 'enabled': false }"); + return; + } + + 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")); + if (port) { + qdict_put(server, "port", qint_from_int(port)); + } + if (tls_port) { + qdict_put(server, "tls-port", qint_from_int(tls_port)); + } + if (clist) { + qdict_put(server, "channels", clist); + } + + *ret_data = QOBJECT(server); +} + static int add_channel(const char *name, const char *value, void *opaque) { int security = 0; -- 1.7.4.rc1.16.gd2f15e