[Spice-devel] [PATCH xf86-video-qxl v2 06/11] xspice: add vdagent support

Alon Levy alevy at redhat.com
Sun Sep 8 05:11:48 PDT 2013


Adds a configurable virtio path used to communicate with the vdagentd,
and a configuration variable for enabling the thing.

With this you can have multiple monitors, but due to usage of a tablet
you cannot generate pointer events on and monitors besides the first.

clipboard already works.

The next patch adds uinput emulation to let vdagentd generate uinput
events and fix this glitch.

Signed-off-by: Alon Levy <alevy at redhat.com>
---
 src/Makefile.am        |   2 +
 src/qxl.h              |   2 +
 src/qxl_driver.c       |   7 +++
 src/spiceqxl_vdagent.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/spiceqxl_vdagent.h |   8 +++
 5 files changed, 187 insertions(+)
 create mode 100644 src/spiceqxl_vdagent.c
 create mode 100644 src/spiceqxl_vdagent.h

diff --git a/src/Makefile.am b/src/Makefile.am
index c237618..c6e6dcd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -89,6 +89,8 @@ spiceqxl_drv_la_SOURCES =				\
 	spiceqxl_main_loop.h		\
 	spiceqxl_display.c			\
 	spiceqxl_display.h			\
+	spiceqxl_vdagent.c			\
+	spiceqxl_vdagent.h			\
 	spiceqxl_audio.c			\
 	spiceqxl_audio.h			\
 	spiceqxl_inputs.c			\
diff --git a/src/qxl.h b/src/qxl.h
index c026b63..b1ba2e9 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -134,6 +134,8 @@ enum {
     OPTION_SPICE_DH_FILE,
     OPTION_SPICE_EXIT_ON_DISCONNECT,
     OPTION_SPICE_PLAYBACK_FIFO_DIR,
+    OPTION_SPICE_VDAGENT_ENABLED,
+    OPTION_SPICE_VDAGENT_VIRTIO_PATH,
 #endif
     OPTION_COUNT,
 };
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index d5ad45f..00736a2 100644
--- a/src/qxl_driver.c
+++ b/src/qxl_driver.c
@@ -55,6 +55,7 @@
 #include "spiceqxl_io_port.h"
 #include "spiceqxl_spice_server.h"
 #include "spiceqxl_audio.h"
+#include "spiceqxl_vdagent.h"
 #endif /* XSPICE */
 
 #include "dfps.h"
@@ -67,6 +68,7 @@ extern void compat_init_scrn (ScrnInfoPtr);
 static char filter_str[] = "filter";
 static char auto_str[]   = "auto";
 static char auto_glz_str[]   = "auto_glz";
+static char spice_vdagent_virtio_path_default[] = "/tmp/xspice-virtio";
 #endif
 static char driver_name[] = QXL_DRIVER_NAME;
 const OptionInfoRec DefaultOptions[] =
@@ -133,6 +135,10 @@ const OptionInfoRec DefaultOptions[] =
       "SpiceExitOnDisconnect",    OPTV_BOOLEAN,   {0}, FALSE},
     { OPTION_SPICE_PLAYBACK_FIFO_DIR,
       "SpicePlaybackFIFODir",     OPTV_STRING,    {0}, FALSE},
+    { OPTION_SPICE_VDAGENT_ENABLED,
+      "SpiceVdagentEnabled",      OPTV_BOOLEAN,   {0}, FALSE},
+    { OPTION_SPICE_VDAGENT_VIRTIO_PATH,
+      "SpiceVdagentVirtioPath",   OPTV_STRING,    {.str = spice_vdagent_virtio_path_default}, FALSE},
 #endif
     
     { -1, NULL, OPTV_NONE, {0}, FALSE }
@@ -639,6 +645,7 @@ spiceqxl_screen_init (ScrnInfoPtr pScrn, qxl_screen_t *qxl)
 	spice_server_init (qxl->spice_server, qxl->core);
 	qxl_add_spice_display_interface (qxl);
 	qxl_add_spice_playback_interface (qxl);
+	spiceqxl_vdagent_init (qxl);
     }
     else
     {
diff --git a/src/spiceqxl_vdagent.c b/src/spiceqxl_vdagent.c
new file mode 100644
index 0000000..4b029bd
--- /dev/null
+++ b/src/spiceqxl_vdagent.c
@@ -0,0 +1,168 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "qxl_option_helpers.h"
+
+#include "spiceqxl_vdagent.h"
+
+static const char *vdagent_virtio_filename;
+static int virtio_fd;
+static int virtio_client_fd = -1;
+static SpiceWatch *virtio_client_watch;
+
+typedef struct XSpiceVdagentCharDeviceInstance {
+    SpiceCharDeviceInstance base;
+    qxl_screen_t *qxl;
+} XSpiceVdagentCharDeviceInstance;
+
+XSpiceVdagentCharDeviceInstance vdagent_sin = {
+    .base = {
+        .subtype = "vdagent"
+    }
+};
+
+static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
+{
+    int written;
+
+    if (virtio_client_fd == -1) {
+        return 0;
+    }
+    written = send(virtio_client_fd, buf, len, 0);
+    if (written != len) {
+        fprintf(stderr, "%s: ERROR: short write to vdagentd - TODO buffering\n", __func__);
+    }
+    return written;
+}
+
+static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
+{
+    int read;
+
+    if (virtio_client_fd == -1) {
+        return 0;
+    }
+    read = recv(virtio_client_fd, buf, len, 0);
+    if (read <= 0) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            return 0;
+        }
+        fprintf(stderr, "ERROR: vdagentd died\n");
+        close(virtio_client_fd);
+        virtio_client_fd = -1;
+        vdagent_sin.qxl->core->watch_remove(virtio_client_watch);
+        virtio_client_watch = NULL;
+    }
+    return read;
+}
+
+static void on_read_available(int fd, int event, void *opaque)
+{
+    if (virtio_client_fd == -1) {
+        return;
+    }
+    spice_server_char_device_wakeup(&vdagent_sin.base);
+}
+
+#if SPICE_SERVER_VERSION >= 0x000c02
+static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event)
+{
+}
+#endif
+
+static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
+{
+}
+
+static SpiceCharDeviceInterface vmc_interface = {
+    .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
+    .base.description   = "Xspice virtual channel char device",
+    .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
+    .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
+    .state              = vmc_state,
+    .write              = vmc_write,
+    .read               = vmc_read,
+#if SPICE_SERVER_VERSION >= 0x000c02
+    .event              = vmc_event,
+#endif
+};
+
+static void on_accept(int fd, int event, void *opaque)
+{
+    qxl_screen_t *qxl = opaque;
+    struct sockaddr_un address;
+    socklen_t length = sizeof(address);
+    int flags;
+
+    virtio_client_fd = accept(virtio_fd, (struct sockaddr *)&address, &length);
+    if (virtio_client_fd == -1) {
+        fprintf(stderr, "error accepting on unix domain socket: %s\n", strerror(errno));
+        return;
+    }
+    flags = fcntl(virtio_client_fd, F_GETFL);
+    if (flags == -1) {
+        fprintf(stderr, "error getting flags from uds client fd: %s\n", strerror(errno));
+        goto error;
+    }
+    if (fcntl(virtio_client_fd, F_SETFL, flags | O_NONBLOCK | O_CLOEXEC) == -1) {
+        fprintf(stderr, "error setting CLOEXEC & NONBLOCK flags from uds client fd: %s\n",
+                strerror(errno));
+        goto error;
+    }
+    virtio_client_watch = qxl->core->watch_add(virtio_client_fd, SPICE_WATCH_EVENT_READ
+        /* TODO - SPICE_WATCH_EVENT_WRITE */, on_read_available, qxl);
+    return;
+
+error:
+    if (virtio_client_fd != -1) {
+        close(virtio_client_fd);
+        virtio_client_fd = -1;
+    }
+}
+
+void spiceqxl_vdagent_init(qxl_screen_t *qxl)
+{
+    struct sockaddr_un address;
+    int c;
+    int enabled;
+
+    vdagent_sin.qxl = qxl;
+    vdagent_virtio_filename = get_str_option(qxl->options, OPTION_SPICE_VDAGENT_VIRTIO_PATH,
+               "XSPICE_VDAGENT_VIRTIO_PATH");
+    enabled = get_bool_option(qxl->options, OPTION_SPICE_VDAGENT_ENABLED, "XSPICE_VDAGENT_ENABLED");
+
+    if (!enabled || !vdagent_virtio_filename) {
+        return;
+    }
+    
+    virtio_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (virtio_fd == -1) {
+        fprintf(stderr, "error creating unix domain socket\n");
+        return;
+    }
+    address.sun_family = AF_UNIX;
+    snprintf(address.sun_path, sizeof(address.sun_path), "%s", vdagent_virtio_filename);
+    c = bind(virtio_fd, (struct sockaddr *)&address, sizeof(address));
+    if (c != 0) {
+        fprintf(stderr, "error binding unix domain socket to %s: %s\n",
+                vdagent_virtio_filename, strerror(errno));
+        return;
+    }
+    c = listen(virtio_fd, 1);
+    if (c != 0) {
+        fprintf(stderr, "error listening to unix domain socket: %s\n", strerror(errno));
+        return;
+    }
+    qxl->core->watch_add(virtio_fd, SPICE_WATCH_EVENT_READ
+        /* TODO - SPICE_WATCH_EVENT_WRITE */, on_accept, qxl);
+
+    vdagent_sin.base.base.sif = &vmc_interface.base;
+    spice_server_add_interface(qxl->spice_server, &vdagent_sin.base.base);
+}
diff --git a/src/spiceqxl_vdagent.h b/src/spiceqxl_vdagent.h
new file mode 100644
index 0000000..d9c6337
--- /dev/null
+++ b/src/spiceqxl_vdagent.h
@@ -0,0 +1,8 @@
+#ifndef SPICEQXL_VDAGENT_H
+#define SPICEQXL_VDAGENT_H
+
+#include "qxl.h"
+
+void spiceqxl_vdagent_init(qxl_screen_t *qxl);
+
+#endif
-- 
1.8.3.1



More information about the Spice-devel mailing list