Revision d1f29646
b/hmp.c | ||
---|---|---|
306 | 306 |
qapi_free_VncInfo(info); |
307 | 307 |
} |
308 | 308 |
|
309 |
void hmp_info_spice(Monitor *mon) |
|
310 |
{ |
|
311 |
SpiceChannelList *chan; |
|
312 |
SpiceInfo *info; |
|
313 |
|
|
314 |
info = qmp_query_spice(NULL); |
|
315 |
|
|
316 |
if (!info->enabled) { |
|
317 |
monitor_printf(mon, "Server: disabled\n"); |
|
318 |
goto out; |
|
319 |
} |
|
320 |
|
|
321 |
monitor_printf(mon, "Server:\n"); |
|
322 |
if (info->has_port) { |
|
323 |
monitor_printf(mon, " address: %s:%" PRId64 "\n", |
|
324 |
info->host, info->port); |
|
325 |
} |
|
326 |
if (info->has_tls_port) { |
|
327 |
monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n", |
|
328 |
info->host, info->tls_port); |
|
329 |
} |
|
330 |
monitor_printf(mon, " auth: %s\n", info->auth); |
|
331 |
monitor_printf(mon, " compiled: %s\n", info->compiled_version); |
|
332 |
|
|
333 |
if (!info->has_channels || info->channels == NULL) { |
|
334 |
monitor_printf(mon, "Channels: none\n"); |
|
335 |
} else { |
|
336 |
for (chan = info->channels; chan; chan = chan->next) { |
|
337 |
monitor_printf(mon, "Channel:\n"); |
|
338 |
monitor_printf(mon, " address: %s:%s%s\n", |
|
339 |
chan->value->host, chan->value->port, |
|
340 |
chan->value->tls ? " [tls]" : ""); |
|
341 |
monitor_printf(mon, " session: %" PRId64 "\n", |
|
342 |
chan->value->connection_id); |
|
343 |
monitor_printf(mon, " channel: %" PRId64 ":%" PRId64 "\n", |
|
344 |
chan->value->channel_type, chan->value->channel_id); |
|
345 |
} |
|
346 |
} |
|
347 |
|
|
348 |
out: |
|
349 |
qapi_free_SpiceInfo(info); |
|
350 |
} |
|
351 |
|
|
309 | 352 |
void hmp_quit(Monitor *mon, const QDict *qdict) |
310 | 353 |
{ |
311 | 354 |
monitor_suspend(mon); |
b/hmp.h | ||
---|---|---|
29 | 29 |
void hmp_info_block(Monitor *mon); |
30 | 30 |
void hmp_info_blockstats(Monitor *mon); |
31 | 31 |
void hmp_info_vnc(Monitor *mon); |
32 |
void hmp_info_spice(Monitor *mon); |
|
32 | 33 |
void hmp_quit(Monitor *mon, const QDict *qdict); |
33 | 34 |
void hmp_stop(Monitor *mon, const QDict *qdict); |
34 | 35 |
void hmp_system_reset(Monitor *mon, const QDict *qdict); |
b/monitor.c | ||
---|---|---|
2857 | 2857 |
.args_type = "", |
2858 | 2858 |
.params = "", |
2859 | 2859 |
.help = "show the spice server status", |
2860 |
.user_print = do_info_spice_print, |
|
2861 |
.mhandler.info_new = do_info_spice, |
|
2860 |
.mhandler.info = hmp_info_spice, |
|
2862 | 2861 |
}, |
2863 | 2862 |
#endif |
2864 | 2863 |
{ |
... | ... | |
2965 | 2964 |
.user_print = do_pci_info_print, |
2966 | 2965 |
.mhandler.info_new = do_pci_info, |
2967 | 2966 |
}, |
2968 |
#if defined(CONFIG_SPICE) |
|
2969 |
{ |
|
2970 |
.name = "spice", |
|
2971 |
.args_type = "", |
|
2972 |
.params = "", |
|
2973 |
.help = "show the spice server status", |
|
2974 |
.user_print = do_info_spice_print, |
|
2975 |
.mhandler.info_new = do_info_spice, |
|
2976 |
}, |
|
2977 |
#endif |
|
2978 | 2967 |
{ |
2979 | 2968 |
.name = "balloon", |
2980 | 2969 |
.args_type = "", |
b/qapi-schema.json | ||
---|---|---|
585 | 585 |
{ 'command': 'query-vnc', 'returns': 'VncInfo' } |
586 | 586 |
|
587 | 587 |
## |
588 |
# @SpiceChannel |
|
589 |
# |
|
590 |
# Information about a SPICE client channel. |
|
591 |
# |
|
592 |
# @host: The host name of the client. QEMU tries to resolve this to a DNS name |
|
593 |
# when possible. |
|
594 |
# |
|
595 |
# @family: 'ipv6' if the client is connected via IPv6 and TCP |
|
596 |
# 'ipv4' if the client is connected via IPv4 and TCP |
|
597 |
# 'unix' if the client is connected via a unix domain socket |
|
598 |
# 'unknown' otherwise |
|
599 |
# |
|
600 |
# @port: The client's port number. |
|
601 |
# |
|
602 |
# @connection-id: SPICE connection id number. All channels with the same id |
|
603 |
# belong to the same SPICE session. |
|
604 |
# |
|
605 |
# @connection-type: SPICE channel type number. "1" is the main control channel, |
|
606 |
# filter for this one if you want track spice sessions only |
|
607 |
# |
|
608 |
# @channel-id: SPICE channel ID number. Usually "0", might be different needed |
|
609 |
# when multiple channels of the same type exist, such as multiple |
|
610 |
# display channels in a multihead setup |
|
611 |
# |
|
612 |
# @tls: true if the channel is encrypted, false otherwise. |
|
613 |
# |
|
614 |
# Since: 0.14.0 |
|
615 |
## |
|
616 |
{ 'type': 'SpiceChannel', |
|
617 |
'data': {'host': 'str', 'family': 'str', 'port': 'str', |
|
618 |
'connection-id': 'int', 'channel-type': 'int', 'channel-id': 'int', |
|
619 |
'tls': 'bool'} } |
|
620 |
|
|
621 |
## |
|
622 |
# @SpiceInfo |
|
623 |
# |
|
624 |
# Information about the SPICE session. |
|
625 |
# |
|
626 |
# @enabled: true if the SPICE server is enabled, false otherwise |
|
627 |
# |
|
628 |
# @host: #optional The hostname the SPICE server is bound to. This depends on |
|
629 |
# the name resolution on the host and may be an IP address. |
|
630 |
# |
|
631 |
# @port: #optional The SPICE server's port number. |
|
632 |
# |
|
633 |
# @compiled-version: #optional SPICE server version. |
|
634 |
# |
|
635 |
# @tls-port: #optional The SPICE server's TLS port number. |
|
636 |
# |
|
637 |
# @auth: #optional the current authentication type used by the server |
|
638 |
# 'none' if no authentication is being used |
|
639 |
# 'spice' (TODO: describe) |
|
640 |
# |
|
641 |
# @channels: a list of @SpiceChannel for each active spice channel |
|
642 |
# |
|
643 |
# Since: 0.14.0 |
|
644 |
## |
|
645 |
{ 'type': 'SpiceInfo', |
|
646 |
'data': {'enabled': 'bool', '*host': 'str', '*port': 'int', |
|
647 |
'*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', |
|
648 |
'*channels': ['SpiceChannel']} } |
|
649 |
|
|
650 |
## |
|
651 |
# @query-spice |
|
652 |
# |
|
653 |
# Returns information about the current SPICE server |
|
654 |
# |
|
655 |
# Returns: @SpiceInfo |
|
656 |
# |
|
657 |
# Since: 0.14.0 |
|
658 |
## |
|
659 |
{ 'command': 'query-spice', 'returns': 'SpiceInfo' } |
|
660 |
|
|
661 |
## |
|
588 | 662 |
# @quit: |
589 | 663 |
# |
590 | 664 |
# This command will cause the QEMU process to exit gracefully. While every |
b/qmp-commands.hx | ||
---|---|---|
1817 | 1817 |
|
1818 | 1818 |
EQMP |
1819 | 1819 |
|
1820 |
#if defined(CONFIG_SPICE) |
|
1821 |
{ |
|
1822 |
.name = "query-spice", |
|
1823 |
.args_type = "", |
|
1824 |
.mhandler.cmd_new = qmp_marshal_input_query_spice, |
|
1825 |
}, |
|
1826 |
#endif |
|
1827 |
|
|
1820 | 1828 |
SQMP |
1821 | 1829 |
query-name |
1822 | 1830 |
---------- |
b/qmp.c | ||
---|---|---|
105 | 105 |
return NULL; |
106 | 106 |
}; |
107 | 107 |
#endif |
108 |
|
|
109 |
#ifndef CONFIG_SPICE |
|
110 |
/* If SPICE support is enabled, the "true" query-spice command is |
|
111 |
defined in the SPICE subsystem. Also note that we use a small |
|
112 |
trick to maintain query-spice's original behavior, which is not |
|
113 |
to be available in the namespace if SPICE is not compiled in */ |
|
114 |
SpiceInfo *qmp_query_spice(Error **errp) |
|
115 |
{ |
|
116 |
error_set(errp, QERR_COMMAND_NOT_FOUND, "query-spice"); |
|
117 |
return NULL; |
|
118 |
}; |
|
119 |
#endif |
b/ui/spice-core.c | ||
---|---|---|
27 | 27 |
#include "qemu-queue.h" |
28 | 28 |
#include "qemu-x509.h" |
29 | 29 |
#include "qemu_socket.h" |
30 |
#include "qmp-commands.h" |
|
30 | 31 |
#include "qint.h" |
31 | 32 |
#include "qbool.h" |
32 | 33 |
#include "qstring.h" |
... | ... | |
194 | 195 |
qdict_put(dict, "tls", qbool_from_int(tls)); |
195 | 196 |
} |
196 | 197 |
|
197 |
static QList *channel_list_get(void) |
|
198 |
{ |
|
199 |
ChannelList *item; |
|
200 |
QList *list; |
|
201 |
QDict *dict; |
|
202 |
|
|
203 |
list = qlist_new(); |
|
204 |
QTAILQ_FOREACH(item, &channel_list, link) { |
|
205 |
dict = qdict_new(); |
|
206 |
add_addr_info(dict, &item->info->paddr, item->info->plen); |
|
207 |
add_channel_info(dict, item->info); |
|
208 |
qlist_append(list, dict); |
|
209 |
} |
|
210 |
return list; |
|
211 |
} |
|
212 |
|
|
213 | 198 |
static void channel_event(int event, SpiceChannelEventInfo *info) |
214 | 199 |
{ |
215 | 200 |
static const int qevent[] = { |
... | ... | |
351 | 336 |
|
352 | 337 |
/* functions for the rest of qemu */ |
353 | 338 |
|
354 |
static void info_spice_iter(QObject *obj, void *opaque)
|
|
339 |
static SpiceChannelList *qmp_query_spice_channels(void)
|
|
355 | 340 |
{ |
356 |
QDict *client; |
|
357 |
Monitor *mon = opaque; |
|
358 |
|
|
359 |
client = qobject_to_qdict(obj); |
|
360 |
monitor_printf(mon, "Channel:\n"); |
|
361 |
monitor_printf(mon, " address: %s:%s%s\n", |
|
362 |
qdict_get_str(client, "host"), |
|
363 |
qdict_get_str(client, "port"), |
|
364 |
qdict_get_bool(client, "tls") ? " [tls]" : ""); |
|
365 |
monitor_printf(mon, " session: %" PRId64 "\n", |
|
366 |
qdict_get_int(client, "connection-id")); |
|
367 |
monitor_printf(mon, " channel: %d:%d\n", |
|
368 |
(int)qdict_get_int(client, "channel-type"), |
|
369 |
(int)qdict_get_int(client, "channel-id")); |
|
370 |
} |
|
371 |
|
|
372 |
void do_info_spice_print(Monitor *mon, const QObject *data) |
|
373 |
{ |
|
374 |
QDict *server; |
|
375 |
QList *channels; |
|
376 |
const char *host; |
|
377 |
int port; |
|
378 |
|
|
379 |
server = qobject_to_qdict(data); |
|
380 |
if (qdict_get_bool(server, "enabled") == 0) { |
|
381 |
monitor_printf(mon, "Server: disabled\n"); |
|
382 |
return; |
|
383 |
} |
|
341 |
SpiceChannelList *cur_item = NULL, *head = NULL; |
|
342 |
ChannelList *item; |
|
384 | 343 |
|
385 |
monitor_printf(mon, "Server:\n"); |
|
386 |
host = qdict_get_str(server, "host"); |
|
387 |
port = qdict_get_try_int(server, "port", -1); |
|
388 |
if (port != -1) { |
|
389 |
monitor_printf(mon, " address: %s:%d\n", host, port); |
|
390 |
} |
|
391 |
port = qdict_get_try_int(server, "tls-port", -1); |
|
392 |
if (port != -1) { |
|
393 |
monitor_printf(mon, " address: %s:%d [tls]\n", host, port); |
|
344 |
QTAILQ_FOREACH(item, &channel_list, link) { |
|
345 |
SpiceChannelList *chan; |
|
346 |
char host[NI_MAXHOST], port[NI_MAXSERV]; |
|
347 |
|
|
348 |
chan = g_malloc0(sizeof(*chan)); |
|
349 |
chan->value = g_malloc0(sizeof(*chan->value)); |
|
350 |
|
|
351 |
getnameinfo(&item->info->paddr, item->info->plen, |
|
352 |
host, sizeof(host), port, sizeof(port), |
|
353 |
NI_NUMERICHOST | NI_NUMERICSERV); |
|
354 |
chan->value->host = g_strdup(host); |
|
355 |
chan->value->port = g_strdup(port); |
|
356 |
chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family)); |
|
357 |
|
|
358 |
chan->value->connection_id = item->info->connection_id; |
|
359 |
chan->value->channel_type = item->info->type; |
|
360 |
chan->value->channel_id = item->info->id; |
|
361 |
chan->value->tls = item->info->flags & SPICE_CHANNEL_EVENT_FLAG_TLS; |
|
362 |
|
|
363 |
/* XXX: waiting for the qapi to support GSList */ |
|
364 |
if (!cur_item) { |
|
365 |
head = cur_item = chan; |
|
366 |
} else { |
|
367 |
cur_item->next = chan; |
|
368 |
cur_item = chan; |
|
369 |
} |
|
394 | 370 |
} |
395 |
monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth")); |
|
396 |
monitor_printf(mon, " compiled: %s\n", |
|
397 |
qdict_get_str(server, "compiled-version")); |
|
398 | 371 |
|
399 |
channels = qdict_get_qlist(server, "channels"); |
|
400 |
if (qlist_empty(channels)) { |
|
401 |
monitor_printf(mon, "Channels: none\n"); |
|
402 |
} else { |
|
403 |
qlist_iter(channels, info_spice_iter, mon); |
|
404 |
} |
|
372 |
return head; |
|
405 | 373 |
} |
406 | 374 |
|
407 |
void do_info_spice(Monitor *mon, QObject **ret_data)
|
|
375 |
SpiceInfo *qmp_query_spice(Error **errp)
|
|
408 | 376 |
{ |
409 | 377 |
QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); |
410 |
QDict *server; |
|
411 |
QList *clist; |
|
412 |
const char *addr; |
|
413 | 378 |
int port, tls_port; |
379 |
const char *addr; |
|
380 |
SpiceInfo *info; |
|
414 | 381 |
char version_string[20]; /* 12 = |255.255.255\0| is the max */ |
415 | 382 |
|
383 |
info = g_malloc0(sizeof(*info)); |
|
384 |
|
|
416 | 385 |
if (!spice_server) { |
417 |
*ret_data = qobject_from_jsonf("{ 'enabled': false }");
|
|
418 |
return; |
|
386 |
info->enabled = false;
|
|
387 |
return info;
|
|
419 | 388 |
} |
420 | 389 |
|
390 |
info->enabled = true; |
|
391 |
|
|
421 | 392 |
addr = qemu_opt_get(opts, "addr"); |
422 | 393 |
port = qemu_opt_get_number(opts, "port", 0); |
423 | 394 |
tls_port = qemu_opt_get_number(opts, "tls-port", 0); |
424 |
clist = channel_list_get(); |
|
425 | 395 |
|
426 |
server = qdict_new(); |
|
427 |
qdict_put(server, "enabled", qbool_from_int(true)); |
|
428 |
qdict_put(server, "auth", qstring_from_str(auth)); |
|
429 |
qdict_put(server, "host", qstring_from_str(addr ? addr : "0.0.0.0")); |
|
396 |
info->has_auth = true; |
|
397 |
info->auth = g_strdup(auth); |
|
398 |
|
|
399 |
info->has_host = true; |
|
400 |
info->host = g_strdup(addr ? addr : "0.0.0.0"); |
|
401 |
|
|
402 |
info->has_compiled_version = true; |
|
430 | 403 |
snprintf(version_string, sizeof(version_string), "%d.%d.%d", |
431 | 404 |
(SPICE_SERVER_VERSION & 0xff0000) >> 16, |
432 | 405 |
(SPICE_SERVER_VERSION & 0xff00) >> 8, |
433 | 406 |
SPICE_SERVER_VERSION & 0xff); |
434 |
qdict_put(server, "compiled-version", qstring_from_str(version_string)); |
|
407 |
info->compiled_version = g_strdup(version_string); |
|
408 |
|
|
435 | 409 |
if (port) { |
436 |
qdict_put(server, "port", qint_from_int(port)); |
|
410 |
info->has_port = true; |
|
411 |
info->port = port; |
|
437 | 412 |
} |
438 | 413 |
if (tls_port) { |
439 |
qdict_put(server, "tls-port", qint_from_int(tls_port)); |
|
440 |
} |
|
441 |
if (clist) { |
|
442 |
qdict_put(server, "channels", clist); |
|
414 |
info->has_tls_port = true; |
|
415 |
info->tls_port = tls_port; |
|
443 | 416 |
} |
444 | 417 |
|
445 |
*ret_data = QOBJECT(server); |
|
418 |
/* for compatibility with the original command */ |
|
419 |
info->has_channels = true; |
|
420 |
info->channels = qmp_query_spice_channels(); |
|
421 |
|
|
422 |
return info; |
|
446 | 423 |
} |
447 | 424 |
|
448 | 425 |
static void migration_state_notifier(Notifier *notifier, void *data) |
Also available in: Unified diff