Adding lz4 compression same as in spicevmc channel. Compression will be enabled only if LZ4 is in use && socket is not AF_LOCAL type (local) && data size is under threshold && host has lz4 compression capability. -handling compressed msgs is implemented in src/channel-webdav.c -compression of msgs is implemented in src/vmcstream.c --- src/channel-webdav.c | 57 ++++++++++++++++++++++++++++++++++++++++++ src/vmcstream.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/src/channel-webdav.c b/src/channel-webdav.c index 4ecc769..39598a5 100644 --- a/src/channel-webdav.c +++ b/src/channel-webdav.c @@ -25,6 +25,10 @@ #include "vmcstream.h" #include "giopipe.h" +#ifdef USE_LZ4 +#include <lz4.h> +#endif + /** * SECTION:channel-webdav * @short_description: exports a directory @@ -531,6 +535,9 @@ static void spice_webdav_channel_init(SpiceWebdavChannel *channel) GOutputStream *ostream = g_io_stream_get_output_stream(G_IO_STREAM(c->stream)); c->queue = output_queue_new(ostream); +#ifdef USE_LZ4 + spice_channel_set_capability(channel, SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4); +#endif } static void spice_webdav_channel_finalize(GObject *object) @@ -593,6 +600,50 @@ static void webdav_handle_msg(SpiceChannel *channel, SpiceMsgIn *in) buf, size); } +/* coroutine context */ +static int webdav_try_handle_compressed_msg(SpiceChannel *channel, SpiceMsgIn *in) +{ + SpiceWebdavChannel *self = SPICE_WEBDAV_CHANNEL(channel); + SpiceWebdavChannelPrivate *c = self->priv; + int size; + int decompressed_size = 0; + char *decompressed = NULL; + + SpiceMsgCompressedData *compressed_data_msg = spice_msg_in_parsed(in); + + if (compressed_data_msg->uncompressed_size == 0) { + spice_warning("Invalid uncompressed_size"); + return FALSE; + } + + switch (compressed_data_msg->type) { +#ifdef USE_LZ4 + case SPICE_DATA_COMPRESSION_TYPE_LZ4: + decompressed = g_malloc(compressed_data_msg->uncompressed_size); + decompressed_size = LZ4_decompress_safe ((char*)compressed_data_msg->compressed_data, + decompressed, + compressed_data_msg->compressed_size, + compressed_data_msg->uncompressed_size); + break; +#endif + default: + spice_warning("Unknown Compression Type"); + return FALSE; + } + if (decompressed_size != compressed_data_msg->uncompressed_size) { + spice_warning("Decompress Error decompressed_size=%d expected=%u", + decompressed_size, compressed_data_msg->uncompressed_size); + g_free(decompressed); + return FALSE; + } + + size = decompressed_size; + spice_vmc_input_stream_co_data( + SPICE_VMC_INPUT_STREAM(g_io_stream_get_input_stream(G_IO_STREAM(c->stream))), + (uint8_t*)decompressed, size); + g_free(decompressed); + return TRUE; +} /* coroutine context */ static void spice_webdav_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg) @@ -604,6 +655,12 @@ static void spice_webdav_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg) if (type == SPICE_MSG_SPICEVMC_DATA) webdav_handle_msg(channel, msg); + else if (type == SPICE_MSG_SPICEVMC_COMPRESSED_DATA) { + if(!webdav_try_handle_compressed_msg(channel, msg)) { + spice_warning("handling compressed message failed"); + g_return_if_reached(); + } + } else if (parent_class->handle_msg) parent_class->handle_msg(channel, msg); else diff --git a/src/vmcstream.c b/src/vmcstream.c index 0634bce..57f3758 100644 --- a/src/vmcstream.c +++ b/src/vmcstream.c @@ -23,6 +23,11 @@ #include "spice-channel-priv.h" #include "gio-coroutine.h" +#ifdef USE_LZ4 +#include <lz4.h> +#define COMPRESS_THRESHOLD 1000 +#endif + struct _SpiceVmcInputStream { GInputStream parent_instance; @@ -43,6 +48,9 @@ struct _SpiceVmcInputStreamClass GInputStreamClass parent_class; }; +#ifdef USE_LZ4 +static int try_write_compress_LZ4(SpiceChannel *channel, const uint8_t *data, int count); +#endif static gssize spice_vmc_input_stream_read (GInputStream *stream, void *buffer, gsize count, @@ -373,6 +381,63 @@ spice_vmc_output_stream_new(SpiceChannel *channel) return self; } +#ifdef USE_LZ4 +static int try_write_compress_LZ4(SpiceChannel *channel, const uint8_t *data, int count) +{ + SpiceChannelPrivate *c; + SpiceMsgOut *msg_out_compressed; + int bound, compressed_data_count; + uint8_t *compressed_buf; + SpiceMsgCompressedData compressed_data_msg = { + .type = SPICE_DATA_COMPRESSION_TYPE_LZ4, + .uncompressed_size = count + }; + + c = SPICE_CHANNEL(channel)->priv; + if (g_socket_get_family(c->sock) == G_SOCKET_FAMILY_UNIX) { + /* AF_LOCAL socket - data will not be compressed */ + return FALSE; + } + if (count <= COMPRESS_THRESHOLD) { + /* Not enough data to compress */ + return FALSE; + } + if (!spice_channel_test_capability(SPICE_CHANNEL(channel), + SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4)) { + /* No server compression capability - data will not be compressed */ + return FALSE; + } + bound = LZ4_compressBound(count); + if (bound == 0) { + /* Invalid bound - data will not be compressed */ + return FALSE; + } + + compressed_buf = g_malloc(bound); + compressed_data_count = LZ4_compress_default((char*)data, + (char*)compressed_buf, + count, + bound); + if (compressed_data_count > 0 && compressed_data_count < count) { + compressed_data_msg.compressed_data = compressed_buf; + msg_out_compressed = spice_msg_out_new(SPICE_CHANNEL(channel), + SPICE_MSGC_SPICEVMC_COMPRESSED_DATA); + msg_out_compressed->marshallers->msg_SpiceMsgCompressedData(msg_out_compressed->marshaller, + &compressed_data_msg); + spice_marshaller_add_ref_full(msg_out_compressed->marshaller, + compressed_data_msg.compressed_data, + compressed_data_count, + (spice_marshaller_item_free_func)g_free, + channel); + spice_msg_out_send(msg_out_compressed); + return TRUE; + } + /* if not - free & fallback to sending the message uncompressed */ + g_free(compressed_buf); + return FALSE; +} +#endif + static gssize spice_vmc_output_stream_write_fn(GOutputStream *stream, const void *buffer, @@ -383,6 +448,11 @@ spice_vmc_output_stream_write_fn(GOutputStream *stream, SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream); SpiceMsgOut *msg_out; +#ifdef USE_LZ4 + if (try_write_compress_LZ4(SPICE_CHANNEL(self->channel), buffer, count)) { + return count; + } +#endif msg_out = spice_msg_out_new(SPICE_CHANNEL(self->channel), SPICE_MSGC_SPICEVMC_DATA); spice_marshaller_add(msg_out->marshaller, buffer, count); -- 2.5.5 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel