[Spice-devel] [PATCH 4/6] spice-qemu-char: add spiceport chardev
Marc-André Lureau
marcandre.lureau at gmail.com
Fri Nov 30 05:25:45 PST 2012
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 at redhat.com>
---
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}.
+ at 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.
+ at item -chardev spiceport ,id=@var{id} ,debug=@var{debug}, name=@var{name}, chardev=@var{chardev}
+
+ at option{spiceport} is only available when spice support is built in.
+
+ at option{debug} debug level for spicevmc
+
+ at option{name} name of spice port to connect to
+
+ at 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
More information about the Spice-devel
mailing list