Add a new spice chardev to allow arbitrary communication between the host and the Spice client (via the spice server). Examples: This allows the Spice client to have a special port for the qemu monitor: ... -chardev spiceport,name=org.qemu.monitor,id=monitorport -mon chardev=monitorport Or to allow arbitrary communication outside of qemu: ... -chardev spiceport,name=org.ovirt.controller,id=...,chardev=ovcsocket -chardev socket,server,host=0.0.0.0,port=4242,id=ovcsocket,nowait The spice client is notified when the qemu socket server has gain or lost a client. The qemu socket client is disconnected when the spice client is disconnected. Signed-off-by: Marc-André Lureau <marcandre.lureau@xxxxxxxxxx> --- qemu-char.c | 1 + qemu-config.c | 3 ++ qemu-options.hx | 14 ++++++ spice-qemu-char.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ trace-events | 3 ++ ui/qemu-spice.h | 1 + 6 files changed, 161 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 1414ca1..bc1c74b 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2782,6 +2782,7 @@ static const struct { #endif #ifdef CONFIG_SPICE { .name = "spicevmc", .open = qemu_chr_open_spice }, + { .name = "spiceport", .open = qemu_chr_open_spice_port }, #endif }; diff --git a/qemu-config.c b/qemu-config.c index 10d1ba4..b4e7af3 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -217,6 +217,9 @@ static QemuOptsList qemu_chardev_opts = { },{ .name = "debug", .type = QEMU_OPT_NUMBER, + },{ + .name = "chardev", + .type = QEMU_OPT_STRING, }, { /* end of list */ } }, diff --git a/qemu-options.hx b/qemu-options.hx index fbcf079..d2f09f6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1749,6 +1749,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #endif #if defined(CONFIG_SPICE) "-chardev spicevmc,id=id,name=name[,debug=debug]\n" + "-chardev spiceport,id=id,name=name[,chardev=name,debug=debug]\n" #endif , QEMU_ARCH_ALL ) @@ -1776,6 +1777,7 @@ Backend is one of: @option{tty}, @option{parport}, @option{spicevmc}. +@option{spiceport}. The specific backend will determine the applicable options. All devices must have an id, which can be any string up to 127 characters long. @@ -1961,6 +1963,18 @@ required. Connect to a spice virtual machine channel, such as vdiport. +@item -chardev spiceport ,id=@var{id} ,debug=@var{debug}, name=@var{name}, chardev=@var{chardev} + +@option{spiceport} is only available when spice support is built in. + +@option{debug} debug level for spicevmc + +@option{name} name of spice port to connect to + +@option{chardev} name of chardev to connect to + +Connect to a spice port, fixme. + @end table ETEXI diff --git a/spice-qemu-char.c b/spice-qemu-char.c index b86e83a..629b500 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -3,6 +3,7 @@ #include "ui/qemu-spice.h" #include <spice.h> #include <spice-experimental.h> +#include <spice/protocol.h> #include "osdep.h" @@ -23,6 +24,7 @@ typedef struct SpiceCharDriver { uint8_t *datapos; ssize_t bufsize, datalen; uint32_t debug; + CharDriverState *chardev; } SpiceCharDriver; static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) @@ -67,6 +69,25 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) return bytes; } +static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event) +{ + SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); + int chr_event; + + switch (event) { + case SPICE_PORT_EVENT_BREAK: + chr_event = CHR_EVENT_BREAK; + break; + default: + dprintf(scd, 2, "%s: unknown %d\n", __func__, event); + return; + } + + dprintf(scd, 2, "%s: %d\n", __func__, event); + trace_spice_vmc_event(chr_event); + qemu_chr_be_event(scd->chr, chr_event); +} + static void vmc_state(SpiceCharDeviceInstance *sin, int connected) { SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); @@ -103,6 +124,7 @@ static SpiceCharDeviceInterface vmc_interface = { .state = vmc_state, .write = vmc_write, .read = vmc_read, + .event = vmc_event, }; @@ -116,6 +138,10 @@ static void vmc_register_interface(SpiceCharDriver *scd) qemu_spice_add_interface(&scd->sin.base); scd->active = true; trace_spice_vmc_register_interface(scd); + + if (scd->chardev != NULL && scd->chardev->opened) { + spice_server_port_event(&scd->sin, SPICE_PORT_EVENT_OPENED); + } } static void vmc_unregister_interface(SpiceCharDriver *scd) @@ -242,3 +268,116 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) return chr; } +static int port_can_read(void *opaque) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + return qemu_chr_be_can_write(scd->chardev); +} + +static void port_read(void *opaque, const uint8_t *buf, int size) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + dprintf(scd, 2, "%s: %d\n", __func__, size); + trace_spice_port_chardev_write(size); + qemu_chr_fe_write(scd->chardev, buf, size); +} + +static void port_event(void *opaque, int event) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + dprintf(scd, 2, "%s: %d\n", __func__, event); + + switch (event) { + case CHR_EVENT_CLOSED: + if (scd->chardev != NULL) { + qemu_chr_remove_clients(scd->chardev); + } + break; + } +} + +static int chardev_can_read(void *opaque) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *s = chr->opaque; + + if (!chr->opened) { + return 0; + } + + if (s->datalen != 0) { + return 0; + } + + /* FIXME: assume spice can take chunks of 4096 */ + return 4096; +} + +/* Send data from a char device over to the spice port */ +static void chardev_read(void *opaque, const uint8_t *buf, int size) +{ + CharDriverState *chr = opaque; + + trace_spice_port_chardev_read(size); + /* spicevmc port always send/queue all data */ + qemu_chr_fe_write(chr, buf, size); +} + +static void chardev_event(void *opaque, int event) +{ + CharDriverState *chr = opaque; + SpiceCharDriver *scd = chr->opaque; + + dprintf(scd, 2, "%s: %d\n", __func__, event); + + switch (event) { + case CHR_EVENT_OPENED: + spice_server_port_event(&scd->sin, SPICE_PORT_EVENT_OPENED); + break; + case CHR_EVENT_CLOSED: + spice_server_port_event(&scd->sin, SPICE_PORT_EVENT_CLOSED); + break; + } +} + +CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts) +{ + CharDriverState *chr, *chardev = NULL; + SpiceCharDriver *s; + const char *name = qemu_opt_get(opts, "name"); + const char *chrdev = qemu_opt_get(opts, "chardev"); + + if (name == NULL) { + fprintf(stderr, "spice-qemu-char: missing name parameter\n"); + return NULL; + } + + if (chrdev != NULL) { + chardev = qemu_chr_find(chrdev); + if (chardev == NULL) { + fprintf(stderr, "spice-qemu-char: chardev \"%s\" not found\n", + chrdev); + return NULL; + } + } + + chr = chr_open(opts, "port"); + s = chr->opaque; + s->sin.portname = name; + + if (chardev != NULL) { + s->chardev = chardev; + qemu_chr_add_handlers(chardev, chardev_can_read, + chardev_read, chardev_event, chr); + } + + qemu_chr_add_handlers(chr, port_can_read, port_read, port_event, chr); + + return chr; +} diff --git a/trace-events b/trace-events index 6c6cbf1..26ca363 100644 --- a/trace-events +++ b/trace-events @@ -535,6 +535,9 @@ spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d" spice_vmc_read(int bytes, int len) "spice read %d of requested %d" spice_vmc_register_interface(void *scd) "spice vmc registered interface %p" spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p" +spice_vmc_event(int event) "spice vmc event %d" +spice_port_chardev_read(int bytes) "spice port read %d from chardev" +spice_port_chardev_write(int bytes) "spice port wrote %d to chardev" # hw/lm32_pic.c lm32_pic_raise_irq(void) "Raise CPU interrupt" diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 3299da8..ab1943a 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -46,6 +46,7 @@ void do_info_spice_print(Monitor *mon, const QObject *data); void do_info_spice(Monitor *mon, QObject **ret_data); CharDriverState *qemu_chr_open_spice(QemuOpts *opts); +CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts); #else /* CONFIG_SPICE */ #include "monitor.h" -- 1.7.11.7 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel