summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/qxl.h21
-rw-r--r--src/qxl_driver.c63
-rw-r--r--src/spiceqxl_spice_server.c327
-rw-r--r--src/spiceqxl_spice_server.h35
5 files changed, 433 insertions, 15 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e99e081..1777d56 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -61,6 +61,8 @@ spiceqxl_drv_la_LIBADD = uxa/libuxa.la
spiceqxl_drv_la_SOURCES = \
qxl.h \
+ spiceqxl_spice_server.c \
+ spiceqxl_spice_server.h \
spiceqxl_io_port.c \
spiceqxl_driver.c \
spiceqxl_main_loop.c \
diff --git a/src/qxl.h b/src/qxl.h
index 86927df..23ed2dc 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -101,6 +101,27 @@ typedef struct qxl_surface_t qxl_surface_t;
enum {
#ifdef XSPICE
OPTION_SPICE_PORT = 0,
+ OPTION_SPICE_TLS_PORT,
+ OPTION_SPICE_ADDR,
+ OPTION_SPICE_X509_DIR,
+ OPTION_SPICE_SASL,
+ OPTION_SPICE_AGENT_MOUSE,
+ OPTION_SPICE_DISABLE_TICKETING,
+ OPTION_SPICE_PASSWORD,
+ OPTION_SPICE_X509_KEY_FILE,
+ OPTION_SPICE_STREAMING_VIDEO,
+ OPTION_SPICE_PLAYBACK_COMPRESSION,
+ OPTION_SPICE_ZLIB_GLZ_WAN_COMPRESSION,
+ OPTION_SPICE_JPEG_WAN_COMPRESSION,
+ OPTION_SPICE_IMAGE_COMPRESSION,
+ OPTION_SPICE_DISABLE_COPY_PASTE,
+ OPTION_SPICE_IPV4_ONLY,
+ OPTION_SPICE_IPV6_ONLY,
+ OPTION_SPICE_X509_CERT_FILE,
+ OPTION_SPICE_X509_KEY_PASSWORD,
+ OPTION_SPICE_TLS_CIPHERS,
+ OPTION_SPICE_CACERT_FILE,
+ OPTION_SPICE_DH_FILE,
#endif
OPTION_COUNT,
};
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index f0d6541..2e5a9d6 100644
--- a/src/qxl_driver.c
+++ b/src/qxl_driver.c
@@ -43,6 +43,7 @@
#include "spiceqxl_display.h"
#include "spiceqxl_inputs.h"
#include "spiceqxl_io_port.h"
+#include "spiceqxl_spice_server.h"
#endif /* XSPICE */
#if 0
@@ -52,9 +53,53 @@
const OptionInfoRec DefaultOptions[] = {
#ifdef XSPICE
- { OPTION_SPICE_PORT, "SpicePort", OPTV_INTEGER, {5912}, FALSE },
+ { OPTION_SPICE_PORT,
+ "SpicePort", OPTV_INTEGER, {5900}, FALSE },
+ { OPTION_SPICE_TLS_PORT,
+ "SpiceTlsPort", OPTV_INTEGER, {0}, FALSE},
+ { OPTION_SPICE_ADDR,
+ "SpiceAddr", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_X509_DIR,
+ "SpiceX509Dir", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_SASL,
+ "SpiceSasl", OPTV_BOOLEAN, {0}, FALSE},
+ /* VVV qemu defaults to 1 - not implemented in xspice yet */
+ { OPTION_SPICE_AGENT_MOUSE,
+ "SpiceAgentMouse", OPTV_BOOLEAN, {0}, FALSE},
+ { OPTION_SPICE_DISABLE_TICKETING,
+ "SpiceDisableTicketing", OPTV_BOOLEAN, {0}, FALSE},
+ { OPTION_SPICE_PASSWORD,
+ "SpicePassword", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_X509_KEY_FILE,
+ "SpiceX509KeyFile", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_STREAMING_VIDEO,
+ "SpiceStreamingVideo", OPTV_STRING, {.str="filter"}, FALSE},
+ { OPTION_SPICE_PLAYBACK_COMPRESSION,
+ "SpicePlaybackCompression", OPTV_BOOLEAN, {1}, FALSE},
+ { OPTION_SPICE_ZLIB_GLZ_WAN_COMPRESSION,
+ "SpiceZlibGlzWanCompression", OPTV_STRING, {.str="auto"}, FALSE},
+ { OPTION_SPICE_JPEG_WAN_COMPRESSION,
+ "SpiceJpegWanCompression", OPTV_STRING, {.str="auto"}, FALSE},
+ { OPTION_SPICE_IMAGE_COMPRESSION,
+ "SpiceImageCompression", OPTV_STRING, {.str="auto_glz"}, FALSE},
+ { OPTION_SPICE_DISABLE_COPY_PASTE,
+ "SpiceDisableCopyPaste", OPTV_BOOLEAN, {0}, FALSE},
+ { OPTION_SPICE_IPV4_ONLY,
+ "SpiceIPV4Only", OPTV_BOOLEAN, {0}, FALSE},
+ { OPTION_SPICE_IPV6_ONLY,
+ "SpiceIPV6Only", OPTV_BOOLEAN, {0}, FALSE},
+ { OPTION_SPICE_X509_CERT_FILE,
+ "SpiceX509CertFile", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_X509_KEY_PASSWORD,
+ "SpiceX509KeyPassword", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_TLS_CIPHERS,
+ "SpiceTlsCiphers", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_CACERT_FILE,
+ "SpiceCacertFile", OPTV_STRING, {0}, FALSE},
+ { OPTION_SPICE_DH_FILE,
+ "SpiceDhFile", OPTV_STRING, {0}, FALSE},
#endif
- { -1, NULL, OPTV_NONE, {0}, FALSE }
+ { -1, NULL, OPTV_NONE, {0}, FALSE }
};
int
@@ -895,15 +940,6 @@ setup_uxa (qxl_screen_t *qxl, ScreenPtr screen)
#ifdef XSPICE
-SpiceServer *xspice_get_spice_server(void)
-{
- static SpiceServer *spice_server;
- if (!spice_server) {
- spice_server = spice_server_new();
- }
- return spice_server;
-}
-
static void
spiceqxl_screen_init(int scrnIndex, ScrnInfoPtr pScrn, qxl_screen_t *qxl)
{
@@ -912,10 +948,7 @@ spiceqxl_screen_init(int scrnIndex, ScrnInfoPtr pScrn, qxl_screen_t *qxl)
// Init spice
if (!qxl->spice_server) {
qxl->spice_server = xspice_get_spice_server();
- // some common initialization for all display tests
- spice_server_set_port(qxl->spice_server, qxl->options[OPTION_SPICE_PORT].value.num);
- spice_server_set_noauth(qxl->spice_server); // TODO - take this from config
- // TODO - parse rest of parameters (streaming, compression, jpeg, etc.) from config
+ xspice_set_spice_server_options(qxl->options);
core = basic_event_loop_init();
spice_server_init(qxl->spice_server, core);
qxl_add_spice_display_interface(qxl);
diff --git a/src/spiceqxl_spice_server.c b/src/spiceqxl_spice_server.c
new file mode 100644
index 0000000..61f20d1
--- /dev/null
+++ b/src/spiceqxl_spice_server.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** \file spiceqxl_spice_server.c
+ * \author Alon Levy <alevy@redhat.com>
+ *
+ * spice server helpers for spiceqxl.
+ */
+
+#include "qxl.h"
+#include "spiceqxl_spice_server.h"
+
+/* Single instance of spice server per Xorg executable.
+ */
+SpiceServer *xspice_get_spice_server(void)
+{
+ static SpiceServer *spice_server;
+ if (!spice_server) {
+ spice_server = spice_server_new();
+ }
+ return spice_server;
+}
+
+static
+int get_int_option(OptionInfoPtr options, int option_index,
+ const char *env_name)
+{
+ if (getenv(env_name)) {
+ return atoi(getenv(env_name));
+ }
+ return options[option_index].value.num;
+}
+
+static
+const char *get_str_option(OptionInfoPtr options, int option_index,
+ const char *env_name)
+{
+ if (getenv(env_name)) {
+ return getenv(env_name);
+ }
+ return options[option_index].value.str;
+}
+
+static
+int get_bool_option(OptionInfoPtr options, int option_index,
+ const char *env_name)
+{
+ if (getenv(env_name)) {
+ /* we don't support the whole range of boolean true and
+ * false values documented in man xorg.conf, just the c
+ * convention - 0 is false, anything else is true, so
+ * just like a number. */
+ return !!atoi(getenv(env_name));
+ }
+ return options[option_index].value.bool;
+}
+
+#define X509_CA_CERT_FILE "ca-cert.pem"
+#define X509_SERVER_KEY_FILE "server-key.pem"
+#define X509_SERVER_CERT_FILE "server-cert.pem"
+
+/* config string parsing */
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static int name2enum(const char *string, const char *table[], int entries)
+{
+ int i;
+
+ if (string) {
+ for (i = 0; i < entries; i++) {
+ if (!table[i]) {
+ continue;
+ }
+ if (strcmp(string, table[i]) != 0) {
+ continue;
+ }
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int parse_name(const char *string, const char *optname,
+ const char *table[], int entries)
+{
+ int value = name2enum(string, table, entries);
+
+ if (value != -1) {
+ return value;
+ }
+ fprintf(stderr, "spice: invalid %s: %s\n", optname, string);
+ exit(1);
+}
+
+static const char *stream_video_names[] = {
+ [ SPICE_STREAM_VIDEO_OFF ] = "off",
+ [ SPICE_STREAM_VIDEO_ALL ] = "all",
+ [ SPICE_STREAM_VIDEO_FILTER ] = "filter",
+};
+#define parse_stream_video(_name) \
+ name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
+
+static const char *compression_names[] = {
+ [ SPICE_IMAGE_COMPRESS_OFF ] = "off",
+ [ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz",
+ [ SPICE_IMAGE_COMPRESS_AUTO_LZ ] = "auto_lz",
+ [ SPICE_IMAGE_COMPRESS_QUIC ] = "quic",
+ [ SPICE_IMAGE_COMPRESS_GLZ ] = "glz",
+ [ SPICE_IMAGE_COMPRESS_LZ ] = "lz",
+};
+#define parse_compression(_name) \
+ parse_name(_name, "image compression", \
+ compression_names, ARRAY_SIZE(compression_names))
+
+static const char *wan_compression_names[] = {
+ [ SPICE_WAN_COMPRESSION_AUTO ] = "auto",
+ [ SPICE_WAN_COMPRESSION_NEVER ] = "never",
+ [ SPICE_WAN_COMPRESSION_ALWAYS ] = "always",
+};
+#define parse_wan_compression(_name) \
+ parse_name(_name, "wan compression", \
+ wan_compression_names, ARRAY_SIZE(wan_compression_names))
+
+void xspice_set_spice_server_options(OptionInfoPtr options)
+{
+ /* environment variables take precedense. If not then take
+ * parameters from the config file. */
+ int addr_flags;
+ int len;
+ spice_image_compression_t compression;
+ spice_wan_compression_t wan_compr;
+ int port = get_int_option(options, OPTION_SPICE_PORT, "XSPICE_PORT");
+ int tls_port =
+ get_int_option(options, OPTION_SPICE_TLS_PORT, "XSPICE_TLS_PORT");
+ const char *password =
+ get_str_option(options, OPTION_SPICE_PASSWORD, "XSPICE_PASSWORD");
+ int disable_ticketing =
+ get_bool_option(options, OPTION_SPICE_DISABLE_TICKETING, "XSPICE_DISABLE_TICKETING");
+ const char *x509_dir =
+ get_str_option(options, OPTION_SPICE_X509_DIR, "XSPICE_X509_DIR");
+ int sasl = get_bool_option(options, OPTION_SPICE_SASL, "XSPICE_SASL");
+ const char *x509_key_file_base =
+ get_str_option(options, OPTION_SPICE_X509_KEY_FILE,
+ "XSPICE_X509_KEY_FILE");
+ char *x509_key_file = NULL;
+ const char *x509_cert_file_base =
+ get_str_option(options, OPTION_SPICE_X509_CERT_FILE,
+ "XSPICE_X509_CERT_FILE");
+ char *x509_cert_file = NULL;
+ const char *x509_key_password =
+ get_str_option(options, OPTION_SPICE_X509_KEY_PASSWORD,
+ "XSPICE_X509_KEY_PASSWORD");
+ const char *tls_ciphers =
+ get_str_option(options, OPTION_SPICE_TLS_CIPHERS,
+ "XSPICE_TLS_CIPHERS");
+ const char *x509_cacert_file_base =
+ get_str_option(options, OPTION_SPICE_CACERT_FILE,
+ "XSPICE_CACERT_FILE");
+ char *x509_cacert_file = NULL;
+ const char * addr =
+ get_str_option(options, OPTION_SPICE_ADDR, "XSPICE_ADDR");
+ int ipv4 =
+ get_bool_option(options, OPTION_SPICE_IPV4_ONLY, "XSPICE_IPV4_ONLY");
+ int ipv6 =
+ get_bool_option(options, OPTION_SPICE_IPV6_ONLY, "XSPICE_IPV6_ONLY");
+ const char *x509_dh_file =
+ get_str_option(options, OPTION_SPICE_DH_FILE, "XSPICE_DH_FILE");
+ int disable_copy_paste =
+ get_bool_option(options, OPTION_SPICE_DISABLE_COPY_PASTE,
+ "XSPICE_DISABLE_COPY_PASTE");
+ const char *image_compression =
+ get_str_option(options, OPTION_SPICE_IMAGE_COMPRESSION,
+ "XSPICE_IMAGE_COMPRESSION");
+ const char *jpeg_wan_compression =
+ get_str_option(options, OPTION_SPICE_JPEG_WAN_COMPRESSION,
+ "XSPICE_JPEG_WAN_COMPRESSION");
+ const char *zlib_glz_wan_compression =
+ get_str_option(options, OPTION_SPICE_ZLIB_GLZ_WAN_COMPRESSION,
+ "XSPICE_ZLIB_GLZ_WAN_COMPRESSION");
+ const char *streaming_video =
+ get_str_option(options, OPTION_SPICE_STREAMING_VIDEO,
+ "XSPICE_STREAMING_VIDEO");
+ int agent_mouse =
+ get_bool_option(options, OPTION_SPICE_AGENT_MOUSE,
+ "XSPICE_AGENT_MOUSE");
+ int playback_compression =
+ get_bool_option(options, OPTION_SPICE_PLAYBACK_COMPRESSION,
+ "XSPICE_PLAYBACK_COMPRESSION");
+
+ SpiceServer *spice_server = xspice_get_spice_server();
+
+ if (!port && !tls_port) {
+ printf("one of tls-port or port must be set\n");
+ exit(1);
+ }
+ printf("xspice: port = %d, tls_port = %d\n", port, tls_port);
+ spice_server_set_port(spice_server, port);
+ if (disable_ticketing) {
+ spice_server_set_noauth(spice_server);
+ }
+ if (tls_port) {
+ if (NULL == x509_dir) {
+ x509_dir = ".";
+ }
+ len = strlen(x509_dir) + 32;
+
+ if (x509_key_file_base) {
+ x509_key_file = strdup(x509_key_file_base);
+ } else {
+ x509_key_file = malloc(len);
+ snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE);
+ }
+
+ if (x509_cert_file_base) {
+ x509_cert_file = strdup(x509_cert_file_base);
+ } else {
+ x509_cert_file = malloc(len);
+ snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE);
+ }
+
+ if (x509_cacert_file_base) {
+ x509_cacert_file = strdup(x509_cert_file_base);
+ } else {
+ x509_cacert_file = malloc(len);
+ snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE);
+ }
+ }
+
+ addr_flags = 0;
+ if (ipv4) {
+ addr_flags |= SPICE_ADDR_FLAG_IPV4_ONLY;
+ } else if (ipv6) {
+ addr_flags |= SPICE_ADDR_FLAG_IPV6_ONLY;
+ }
+
+ spice_server_set_addr(spice_server, addr ? addr : "", addr_flags);
+ if (port) {
+ spice_server_set_port(spice_server, port);
+ }
+ if (tls_port) {
+ spice_server_set_tls(spice_server, tls_port,
+ x509_cacert_file,
+ x509_cert_file,
+ x509_key_file,
+ x509_key_password,
+ x509_dh_file,
+ tls_ciphers);
+ }
+ if (password) {
+ spice_server_set_ticket(spice_server, password, 0, 0, 0);
+ }
+ if (sasl) {
+#if SPICE_SERVER_VERSION >= 0x000802 /* 0.8.2 */
+ if (spice_server_set_sasl_appname(spice_server, "xspice") == -1 ||
+ spice_server_set_sasl(spice_server, 1) == -1) {
+ fprintf(stderr, "spice: failed to enable sasl\n");
+ exit(1);
+ }
+#else
+ fprintf(stderr, "spice: sasl is not available (spice >= 0.8.2 required)\n");
+ exit(1);
+#endif
+ }
+ if (disable_ticketing) {
+ spice_server_set_noauth(spice_server);
+ }
+
+#if SPICE_SERVER_VERSION >= 0x000801
+ /* we still don't actually support agent in xspice, but this
+ * can't hurt for later, just copied from qemn/ui/spice-core.c */
+ if (disable_copy_paste) {
+ spice_server_set_agent_copypaste(spice_server, 0);
+ }
+#endif
+
+ compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
+ if (image_compression) {
+ compression = parse_compression(image_compression);
+ }
+ spice_server_set_image_compression(spice_server, compression);
+
+ wan_compr = SPICE_WAN_COMPRESSION_AUTO;
+ if (jpeg_wan_compression) {
+ wan_compr = parse_wan_compression(jpeg_wan_compression);
+ }
+ spice_server_set_jpeg_compression(spice_server, wan_compr);
+
+ wan_compr = SPICE_WAN_COMPRESSION_AUTO;
+ if (zlib_glz_wan_compression) {
+ wan_compr = parse_wan_compression(zlib_glz_wan_compression);
+ }
+ spice_server_set_zlib_glz_compression(spice_server, wan_compr);
+
+ if (streaming_video) {
+ int streaming_video_opt = parse_stream_video(streaming_video);
+ spice_server_set_streaming_video(spice_server, streaming_video_opt);
+ }
+
+ spice_server_set_agent_mouse
+ (spice_server, agent_mouse);
+ spice_server_set_playback_compression
+ (spice_server, playback_compression);
+
+ free(x509_key_file);
+ free(x509_cert_file);
+ free(x509_cacert_file);
+}
diff --git a/src/spiceqxl_spice_server.h b/src/spiceqxl_spice_server.h
new file mode 100644
index 0000000..da83ea3
--- /dev/null
+++ b/src/spiceqxl_spice_server.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** \file spiceqxl_spice_server.h
+ * \author Alon Levy <alevy@redhat.com>
+ *
+ * spice server helpers for spiceqxl.
+ */
+
+#ifndef SPICEQXL_SPICE_SERVER_H
+#define SPICEQXL_SPICE_SERVER_H
+
+SpiceServer *xspice_get_spice_server(void);
+void xspice_set_spice_server_options(OptionInfoPtr options);
+
+#endif // SPICEQXL_SPICE_SERVER_H