diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/qxl.h | 21 | ||||
-rw-r--r-- | src/qxl_driver.c | 63 | ||||
-rw-r--r-- | src/spiceqxl_spice_server.c | 327 | ||||
-rw-r--r-- | src/spiceqxl_spice_server.h | 35 |
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 \ @@ -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 |