Commit 294daff7 authored by Alon Levy's avatar Alon Levy

xspice: add vdagent support

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's avatarAlon Levy <alevy@redhat.com>
parent 9d8a953c
......@@ -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 \
......
......@@ -144,6 +144,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,
};
......
......@@ -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
{
......
#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);
}
#ifndef SPICEQXL_VDAGENT_H
#define SPICEQXL_VDAGENT_H
#include "qxl.h"
void spiceqxl_vdagent_init(qxl_screen_t *qxl);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment