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