Browse Source

spice package update

Signed-off-by: virtbuilder_pel7x64builder0 <virtbuilder@powerel.org>
master
virtbuilder_pel7x64builder0 6 years ago
parent
commit
2fa0175e33
  1. 32
      SOURCES/0001-inputs-channel-Check-message-size-handling-migration.patch
  2. 66
      SOURCES/0002-red-channel-Remove-red_channel_init_outgoing_message.patch
  3. 40
      SOURCES/0003-reds-Remove-leak-allocating-migration-state.patch
  4. 64
      SOURCES/0004-tests-Check-leaks-registering-migration-interface.patch
  5. 179
      SOURCES/0005-Notify-client-of-the-creation-of-new-channels-dynami.patch
  6. 194
      SOURCES/0006-stream-device-Add-device-to-handle-streaming.patch
  7. 178
      SOURCES/0007-stream-device-Start-parsing-new-protocol-from-guest.patch
  8. 271
      SOURCES/0008-stream-channel-Write-a-base-channel-to-implement-the.patch
  9. 88
      SOURCES/0009-stream-channel-Start-implementing-DisplayChannel-pro.patch
  10. 151
      SOURCES/0010-stream-device-Create-channel-for-stream-device.patch
  11. 231
      SOURCES/0011-stream-device-Handle-streaming-data-from-device-to-c.patch
  12. 115
      SOURCES/0012-stream-channel-Allows-not-fixed-size.patch
  13. 67
      SOURCES/0013-stream-channel-Allows-to-register-callback-to-get-ne.patch
  14. 131
      SOURCES/0014-stream-channel-Support-client-connection-disconnecti.patch
  15. 64
      SOURCES/0015-stream-channel-Do-not-show-an-empty-blank-screen-on-.patch
  16. 67
      SOURCES/0016-char-device-Do-not-stop-and-clear-interface-on-reset.patch
  17. 166
      SOURCES/0017-stream-device-Start-supporting-resetting-device-when.patch
  18. 89
      SOURCES/0018-stream-device-Create-channel-when-needed.patch
  19. 206
      SOURCES/0019-stream-device-Limit-sending-queue-from-guest-to-serv.patch
  20. 65
      SOURCES/0020-stream-channel-Activate-streaming-report-from-client.patch
  21. 271
      SPECS/spice.spec

32
SOURCES/0001-inputs-channel-Check-message-size-handling-migration.patch

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Fri, 6 Oct 2017 09:38:31 +0100
Subject: [spice-server] inputs-channel: Check message size handling migration
data

Prevent possible buffer reading overflow.
Note that message pointer must be valid and data are checked
value by value so even on overflow you just get an error.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
---
server/inputs-channel.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/server/inputs-channel.c b/server/inputs-channel.c
index 8e17cc724..11a338a26 100644
--- a/server/inputs-channel.c
+++ b/server/inputs-channel.c
@@ -505,6 +505,11 @@ static bool inputs_channel_handle_migrate_data(RedChannelClient *rcc,
SpiceMigrateDataHeader *header;
SpiceMigrateDataInputs *mig_data;
+ if (size < sizeof(SpiceMigrateDataHeader) + sizeof(SpiceMigrateDataInputs)) {
+ spice_warning("bad message size %u", size);
+ return FALSE;
+ }
+
header = (SpiceMigrateDataHeader *)message;
mig_data = (SpiceMigrateDataInputs *)(header + 1);

66
SOURCES/0002-red-channel-Remove-red_channel_init_outgoing_message.patch

@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Fri, 6 Oct 2017 08:57:42 +0100
Subject: [spice-server] red-channel: Remove
red_channel_init_outgoing_messages_window

This function does not make much sense anymore.
Is called by RedVmcChannel which doesn't use RedChannelClient ACKs
so the variable changed are not used.
Moreover, at red_vmc_channel_constructed() time, there will be no
clients yet, so red_channel_init_outgoing_messages() will be a no-op.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
---
server/red-channel.c | 8 --------
server/red-channel.h | 3 ---
server/spicevmc.c | 2 --
3 files changed, 13 deletions(-)

diff --git a/server/red-channel.c b/server/red-channel.c
index b5094829e..8c507f202 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -421,14 +421,6 @@ void red_channel_push(RedChannel *channel)
g_list_foreach(channel->priv->clients, (GFunc)red_channel_client_push, NULL);
}
-// TODO: this function doesn't make sense because the window should be client (WAN/LAN)
-// specific
-void red_channel_init_outgoing_messages_window(RedChannel *channel)
-{
- g_list_foreach(channel->priv->clients,
- (GFunc)red_channel_client_init_outgoing_messages_window, NULL);
-}
-
void red_channel_pipes_add(RedChannel *channel, RedPipeItem *item)
{
RedChannelClient *rcc;
diff --git a/server/red-channel.h b/server/red-channel.h
index e0fe94fec..281ed0c9e 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -157,9 +157,6 @@ void red_channel_destroy(RedChannel *channel);
/* return true if all the channel clients support the cap */
bool red_channel_test_remote_cap(RedChannel *channel, uint32_t cap);
-/* should be called when a new channel is ready to send messages */
-void red_channel_init_outgoing_messages_window(RedChannel *channel);
-
// helper to push a new item to all channels
typedef RedPipeItem *(*new_pipe_item_t)(RedChannelClient *rcc, void *data, int num);
int red_channel_pipes_new_add(RedChannel *channel, new_pipe_item_t creator, void *data);
diff --git a/server/spicevmc.c b/server/spicevmc.c
index 6b9b96fc8..a1685483d 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -246,8 +246,6 @@ red_vmc_channel_constructed(GObject *object)
red_channel_set_cap(RED_CHANNEL(self), SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4);
#endif
- red_channel_init_outgoing_messages_window(RED_CHANNEL(self));
-
reds_register_channel(reds, RED_CHANNEL(self));
}

40
SOURCES/0003-reds-Remove-leak-allocating-migration-state.patch

@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Tue, 19 Sep 2017 08:28:02 +0100
Subject: [spice-server] reds: Remove leak allocating migration state

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
---
server/reds.c | 2 +-
server/reds.h | 4 ----
2 files changed, 1 insertion(+), 5 deletions(-)

diff --git a/server/reds.c b/server/reds.c
index 12c33570a..1b1ab94ea 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3378,7 +3378,7 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *reds,
return -1;
}
reds->migration_interface = SPICE_CONTAINEROF(sin, SpiceMigrateInstance, base);
- reds->migration_interface->st = spice_new0(SpiceMigrateState, 1);
+ reds->migration_interface->st = (SpiceMigrateState *)(intptr_t)1; // dummy pointer
}
return 0;
diff --git a/server/reds.h b/server/reds.h
index 4f5fc28c3..cea002c51 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -35,10 +35,6 @@ static inline QXLInterface * qxl_get_interface(QXLInstance *qxl)
return SPICE_CONTAINEROF(qxl->base.sif, QXLInterface, base);
}
-struct SpiceMigrateState {
- int dummy;
-};
-
/* main thread only */
void reds_handle_channel_event(RedsState *reds, int event, SpiceChannelEventInfo *info);

64
SOURCES/0004-tests-Check-leaks-registering-migration-interface.patch

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Tue, 19 Sep 2017 08:27:38 +0100
Subject: [spice-server] tests: Check leaks registering migration interface

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
---
server/tests/test-leaks.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/server/tests/test-leaks.c b/server/tests/test-leaks.c
index 04dcac4f4..7032000aa 100644
--- a/server/tests/test-leaks.c
+++ b/server/tests/test-leaks.c
@@ -143,12 +143,48 @@ static void vmc_leaks(void)
basic_event_loop_destroy();
}
+static void migrate_cb(SpiceMigrateInstance *sin)
+{
+}
+
+static const SpiceMigrateInterface migrate_interface = {
+ .base = {
+ .type = SPICE_INTERFACE_MIGRATION,
+ .description = "migration",
+ .major_version = SPICE_INTERFACE_MIGRATION_MAJOR,
+ .minor_version = SPICE_INTERFACE_MIGRATION_MINOR,
+ },
+ .migrate_connect_complete = migrate_cb,
+ .migrate_end_complete = migrate_cb,
+};
+
+static void migration_leaks(void)
+{
+ SpiceCoreInterface *core;
+ SpiceServer *server = spice_server_new();
+ SpiceMigrateInstance migrate;
+
+ g_assert_nonnull(server);
+
+ core = basic_event_loop_init();
+ g_assert_nonnull(core);
+
+ g_assert_cmpint(spice_server_init(server, core), ==, 0);
+
+ migrate.base.sif = &migrate_interface.base;
+ spice_server_add_interface(server, &migrate.base);
+
+ spice_server_destroy(server);
+ basic_event_loop_destroy();
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/server/server leaks", server_leaks);
g_test_add_func("/server/vmc leaks", vmc_leaks);
+ g_test_add_func("/server/migration leaks", migration_leaks);
return g_test_run();
}

179
SOURCES/0005-Notify-client-of-the-creation-of-new-channels-dynami.patch

@ -0,0 +1,179 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Thu, 24 Aug 2017 23:37:25 +0100
Subject: [spice-server] Notify client of the creation of new channels
dynamically

This allows the server to add channels after the client is connected.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/main-channel-client.c | 51 ++++++++++++++++++++++++++++++++++++++++++++
server/main-channel-client.h | 3 +++
server/main-channel.c | 6 ++++++
server/main-channel.h | 3 +++
server/reds.c | 2 ++
5 files changed, 65 insertions(+)

diff --git a/server/main-channel-client.c b/server/main-channel-client.c
index b7b60eddb..61a2830fa 100644
--- a/server/main-channel-client.c
+++ b/server/main-channel-client.c
@@ -62,6 +62,7 @@ struct MainChannelClientPrivate {
int mig_wait_prev_try_seamless;
int init_sent;
int seamless_mig_dst;
+ bool initial_channels_list_sent;
uint8_t recv_buf[MAIN_CHANNEL_RECEIVE_BUF_SIZE];
};
@@ -119,6 +120,12 @@ typedef struct RedMultiMediaTimePipeItem {
uint32_t time;
} RedMultiMediaTimePipeItem;
+typedef struct RedRegisteredChannelPipeItem {
+ RedPipeItem base;
+ uint32_t channel_type;
+ uint32_t channel_id;
+} RedRegisteredChannelPipeItem;
+
#define ZERO_BUF_SIZE 4096
static const uint8_t zero_page[ZERO_BUF_SIZE] = {0};
@@ -446,6 +453,20 @@ RedPipeItem *main_multi_media_time_item_new(uint32_t mm_time)
return &item->base;
}
+RedPipeItem *registered_channel_item_new(RedChannel *channel)
+{
+ RedRegisteredChannelPipeItem *item;
+
+ item = g_new0(RedRegisteredChannelPipeItem, 1);
+ red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL);
+
+ uint32_t type, id;
+ g_object_get(channel, "channel-type", &type, "id", &id, NULL);
+ item->channel_type = type;
+ item->channel_id = id;
+ return &item->base;
+}
+
void main_channel_client_handle_migrate_connected(MainChannelClient *mcc,
int success,
int seamless)
@@ -927,6 +948,25 @@ static void main_channel_marshall_agent_connected(SpiceMarshaller *m,
spice_marshall_msg_main_agent_connected_tokens(m, &connected);
}
+static void main_channel_marshall_registered_channel(RedChannelClient *rcc,
+ SpiceMarshaller *m,
+ RedRegisteredChannelPipeItem *item)
+{
+ struct {
+ SpiceMsgChannels info;
+ SpiceChannelId ids[1];
+ } channels_info_buffer;
+ SpiceMsgChannels* channels_info = &channels_info_buffer.info;
+
+ red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST);
+
+ channels_info->channels[0].type = item->channel_type;
+ channels_info->channels[0].id = item->channel_id;
+ channels_info->num_of_channels = 1;
+
+ spice_marshall_msg_main_channels_list(m, channels_info);
+}
+
void main_channel_client_send_item(RedChannelClient *rcc, RedPipeItem *base)
{
MainChannelClient *mcc = MAIN_CHANNEL_CLIENT(rcc);
@@ -947,6 +987,7 @@ void main_channel_client_send_item(RedChannelClient *rcc, RedPipeItem *base)
switch (base->type) {
case RED_PIPE_ITEM_TYPE_MAIN_CHANNELS_LIST:
main_channel_marshall_channels(rcc, m, base);
+ mcc->priv->initial_channels_list_sent = true;
break;
case RED_PIPE_ITEM_TYPE_MAIN_PING:
main_channel_marshall_ping(rcc, m,
@@ -1003,6 +1044,16 @@ void main_channel_client_send_item(RedChannelClient *rcc, RedPipeItem *base)
case RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS:
main_channel_marshall_agent_connected(m, rcc, base);
break;
+ case RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL:
+ /* The spice protocol requires that the server receive a ATTACH_CHANNELS
+ * message from the client before sending any CHANNEL_LIST message. If
+ * we've already sent our initial CHANNELS_LIST message, then it should be
+ * safe to send new ones for newly-registered channels. */
+ if (mcc->priv->initial_channels_list_sent) {
+ main_channel_marshall_registered_channel(rcc, m,
+ SPICE_UPCAST(RedRegisteredChannelPipeItem, base));
+ }
+ break;
default:
break;
};
diff --git a/server/main-channel-client.h b/server/main-channel-client.h
index 26b7e20b8..2cf2e3424 100644
--- a/server/main-channel-client.h
+++ b/server/main-channel-client.h
@@ -122,12 +122,15 @@ enum {
RED_PIPE_ITEM_TYPE_MAIN_NAME,
RED_PIPE_ITEM_TYPE_MAIN_UUID,
RED_PIPE_ITEM_TYPE_MAIN_AGENT_CONNECTED_TOKENS,
+ RED_PIPE_ITEM_TYPE_MAIN_REGISTERED_CHANNEL,
};
RedPipeItem *main_mouse_mode_item_new(SpiceMouseMode current_mode, int is_client_mouse_allowed);
RedPipeItem *main_multi_media_time_item_new(uint32_t mm_time);
+RedPipeItem *registered_channel_item_new(RedChannel *channel);
+
G_END_DECLS
#endif /* MAIN_CHANNEL_CLIENT_H_ */
diff --git a/server/main-channel.c b/server/main-channel.c
index eca857f6b..4dc130e40 100644
--- a/server/main-channel.c
+++ b/server/main-channel.c
@@ -149,6 +149,12 @@ static void main_channel_fill_mig_target(MainChannel *main_channel, RedsMigSpice
main_channel->mig_target.sport = mig_target->sport;
}
+void
+main_channel_registered_new_channel(MainChannel *main_chan, RedChannel *channel)
+{
+ red_channel_pipes_add(RED_CHANNEL(main_chan), registered_channel_item_new(channel));
+}
+
void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice *mig_target)
{
main_channel_fill_mig_target(main_chan, mig_target);
diff --git a/server/main-channel.h b/server/main-channel.h
index eb3bcec3a..0cb5be728 100644
--- a/server/main-channel.h
+++ b/server/main-channel.h
@@ -66,6 +66,9 @@ void main_channel_push_mouse_mode(MainChannel *main_chan, SpiceMouseMode current
void main_channel_push_agent_connected(MainChannel *main_chan);
void main_channel_push_agent_disconnected(MainChannel *main_chan);
void main_channel_push_multi_media_time(MainChannel *main_chan, uint32_t time);
+/* tell MainChannel we have a new channel ready */
+void main_channel_registered_new_channel(MainChannel *main_chan,
+ RedChannel *channel);
int main_channel_is_connected(MainChannel *main_chan);
diff --git a/server/reds.c b/server/reds.c
index 1b1ab94ea..99b1fd76b 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -387,6 +387,8 @@ void reds_register_channel(RedsState *reds, RedChannel *channel)
{
spice_assert(reds);
reds->channels = g_list_prepend(reds->channels, channel);
+ // create new channel in the client if possible
+ main_channel_registered_new_channel(reds->main_channel, channel);
}
void reds_unregister_channel(RedsState *reds, RedChannel *channel)

194
SOURCES/0006-stream-device-Add-device-to-handle-streaming.patch

@ -0,0 +1,194 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 11:24:58 +0000
Subject: [spice-server] stream-device: Add device to handle streaming

Add a stub device in guest.
The aim of this device is to make it possible for the guest to send a
stream through a DisplayChannel (in the sense of protocol channel).
This stub allows the guest to send some data and you can see some debug
lines of data arrived on host logs.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/Makefile.am | 1 +
server/char-device.h | 1 +
server/reds.c | 2 +
server/stream-device.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 134 insertions(+)
create mode 100644 server/stream-device.c

diff --git a/server/Makefile.am b/server/Makefile.am
index 5d5590af9..f08ddf883 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -166,6 +166,7 @@ libserver_la_SOURCES = \
stat.h \
stream.c \
stream.h \
+ stream-device.c \
sw-canvas.c \
tree.c \
tree.h \
diff --git a/server/char-device.h b/server/char-device.h
index dccd576da..54a1ef939 100644
--- a/server/char-device.h
+++ b/server/char-device.h
@@ -236,6 +236,7 @@ RedCharDevice *spicevmc_device_connect(RedsState *reds,
uint8_t channel_type);
void spicevmc_device_disconnect(RedsState *reds,
SpiceCharDeviceInstance *char_device);
+RedCharDevice *stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin);
SpiceCharDeviceInterface *spice_char_device_get_interface(SpiceCharDeviceInstance *instance);
diff --git a/server/reds.c b/server/reds.c
index 99b1fd76b..b24f61ab2 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3223,6 +3223,8 @@ static int spice_server_char_device_add_interface(SpiceServer *reds,
else if (strcmp(char_device->subtype, SUBTYPE_PORT) == 0) {
if (strcmp(char_device->portname, "org.spice-space.webdav.0") == 0) {
dev_state = spicevmc_device_connect(reds, char_device, SPICE_CHANNEL_WEBDAV);
+ } else if (strcmp(char_device->portname, "com.redhat.stream.0") == 0) {
+ dev_state = stream_device_connect(reds, char_device);
} else {
dev_state = spicevmc_device_connect(reds, char_device, SPICE_CHANNEL_PORT);
}
diff --git a/server/stream-device.c b/server/stream-device.c
new file mode 100644
index 000000000..f3a147b80
--- /dev/null
+++ b/server/stream-device.c
@@ -0,0 +1,130 @@
+/* spice-server character device to handle a video stream
+
+ Copyright (C) 2017 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "char-device.h"
+
+#define TYPE_STREAM_DEVICE stream_device_get_type()
+
+#define STREAM_DEVICE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_STREAM_DEVICE, StreamDevice))
+#define STREAM_DEVICE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_STREAM_DEVICE, StreamDeviceClass))
+#define STREAM_DEVICE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_STREAM_DEVICE, StreamDeviceClass))
+
+typedef struct StreamDevice StreamDevice;
+typedef struct StreamDeviceClass StreamDeviceClass;
+
+struct StreamDevice {
+ RedCharDevice parent;
+};
+
+struct StreamDeviceClass {
+ RedCharDeviceClass parent_class;
+};
+
+static GType stream_device_get_type(void) G_GNUC_CONST;
+static StreamDevice *stream_device_new(SpiceCharDeviceInstance *sin, RedsState *reds);
+
+G_DEFINE_TYPE(StreamDevice, stream_device, RED_TYPE_CHAR_DEVICE)
+
+static RedPipeItem *
+stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *sin)
+{
+ SpiceCharDeviceInterface *sif;
+ int n;
+
+ sif = spice_char_device_get_interface(sin);
+
+ do {
+ uint8_t buf[256];
+ n = sif->read(sin, buf, sizeof(buf));
+ spice_debug("read %d bytes from device", n);
+ } while (n > 0);
+
+ return NULL;
+}
+
+static void
+stream_device_send_msg_to_client(RedCharDevice *self, RedPipeItem *msg, RedClient *client)
+{
+}
+
+static void
+stream_device_send_tokens_to_client(RedCharDevice *self, RedClient *client, uint32_t tokens)
+{
+ spice_printerr("Not implemented!");
+}
+
+static void
+stream_device_remove_client(RedCharDevice *self, RedClient *client)
+{
+}
+
+RedCharDevice *
+stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin)
+{
+ SpiceCharDeviceInterface *sif;
+
+ StreamDevice *dev = stream_device_new(sin, reds);
+
+ sif = spice_char_device_get_interface(sin);
+ if (sif->state) {
+ sif->state(sin, 1);
+ }
+
+ return RED_CHAR_DEVICE(dev);
+}
+
+static void
+stream_device_dispose(GObject *object)
+{
+}
+
+static void
+stream_device_class_init(StreamDeviceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedCharDeviceClass *char_dev_class = RED_CHAR_DEVICE_CLASS(klass);
+
+ object_class->dispose = stream_device_dispose;
+
+ char_dev_class->read_one_msg_from_device = stream_device_read_msg_from_dev;
+ char_dev_class->send_msg_to_client = stream_device_send_msg_to_client;
+ char_dev_class->send_tokens_to_client = stream_device_send_tokens_to_client;
+ char_dev_class->remove_client = stream_device_remove_client;
+}
+
+static void
+stream_device_init(StreamDevice *self)
+{
+}
+
+static StreamDevice *
+stream_device_new(SpiceCharDeviceInstance *sin, RedsState *reds)
+{
+ return g_object_new(TYPE_STREAM_DEVICE,
+ "sin", sin,
+ "spice-server", reds,
+ "client-tokens-interval", 0ULL,
+ "self-tokens", ~0ULL,
+ NULL);
+}

178
SOURCES/0007-stream-device-Start-parsing-new-protocol-from-guest.patch

@ -0,0 +1,178 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Fri, 13 Jan 2017 18:20:43 +0000
Subject: [spice-server] stream-device: Start parsing new protocol from guest

Parse the data sent from the guest to the streaming device.
At the moment, the data is simply discarded after it is parsed.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-device.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 124 insertions(+), 4 deletions(-)

diff --git a/server/stream-device.c b/server/stream-device.c
index f3a147b80..58edb3d11 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -19,6 +19,8 @@
#include <config.h>
#endif
+#include <spice/stream-device.h>
+
#include "char-device.h"
#define TYPE_STREAM_DEVICE stream_device_get_type()
@@ -35,6 +37,9 @@ typedef struct StreamDeviceClass StreamDeviceClass;
struct StreamDevice {
RedCharDevice parent;
+ StreamDevHeader hdr;
+ uint8_t hdr_pos;
+ bool has_error;
};
struct StreamDeviceClass {
@@ -46,21 +51,136 @@ static StreamDevice *stream_device_new(SpiceCharDeviceInstance *sin, RedsState *
G_DEFINE_TYPE(StreamDevice, stream_device, RED_TYPE_CHAR_DEVICE)
+typedef bool StreamMsgHandler(StreamDevice *dev, SpiceCharDeviceInstance *sin)
+ SPICE_GNUC_WARN_UNUSED_RESULT;
+
+static StreamMsgHandler handle_msg_format, handle_msg_data;
+
+static bool handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin,
+ const char *error_msg) SPICE_GNUC_WARN_UNUSED_RESULT;
+
static RedPipeItem *
stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *sin)
{
+ StreamDevice *dev = STREAM_DEVICE(self);
SpiceCharDeviceInterface *sif;
int n;
+ bool handled = false;
+
+ if (dev->has_error) {
+ return NULL;
+ }
sif = spice_char_device_get_interface(sin);
- do {
- uint8_t buf[256];
+ /* read header */
+ while (dev->hdr_pos < sizeof(dev->hdr)) {
+ n = sif->read(sin, (uint8_t *) &dev->hdr, sizeof(dev->hdr) - dev->hdr_pos);
+ if (n <= 0) {
+ return NULL;
+ }
+ dev->hdr_pos += n;
+ if (dev->hdr_pos >= sizeof(dev->hdr)) {
+ dev->hdr.type = GUINT16_FROM_LE(dev->hdr.type);
+ dev->hdr.size = GUINT32_FROM_LE(dev->hdr.size);
+ }
+ }
+
+ switch ((StreamMsgType) dev->hdr.type) {
+ case STREAM_TYPE_FORMAT:
+ if (dev->hdr.size != sizeof(StreamMsgFormat)) {
+ handled = handle_msg_invalid(dev, sin, "Wrong size for StreamMsgFormat");
+ } else {
+ handled = handle_msg_format(dev, sin);
+ }
+ break;
+ case STREAM_TYPE_DATA:
+ handled = handle_msg_data(dev, sin);
+ break;
+ case STREAM_TYPE_CAPABILITIES:
+ /* FIXME */
+ default:
+ handled = handle_msg_invalid(dev, sin, "Invalid message type");
+ break;
+ }
+
+ /* current message has been handled, so reset state and get ready to parse
+ * the next message */
+ if (handled) {
+ dev->hdr_pos = 0;
+ }
+
+ return NULL;
+}
+
+static bool
+handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin, const char *error_msg)
+{
+ static const char default_error_msg[] = "Protocol error";
+
+ if (!error_msg) {
+ error_msg = default_error_msg;
+ }
+
+ int msg_size = sizeof(StreamMsgNotifyError) + strlen(error_msg) + 1;
+ int total_size = sizeof(StreamDevHeader) + msg_size;
+
+ RedCharDevice *char_dev = RED_CHAR_DEVICE(dev);
+ RedCharDeviceWriteBuffer *buf =
+ red_char_device_write_buffer_get_server_no_token(char_dev, total_size);
+ buf->buf_used = total_size;
+
+ StreamDevHeader *const hdr = (StreamDevHeader *)buf->buf;
+ hdr->protocol_version = STREAM_DEVICE_PROTOCOL;
+ hdr->padding = 0;
+ hdr->type = GUINT16_TO_LE(STREAM_TYPE_NOTIFY_ERROR);
+ hdr->size = GUINT32_TO_LE(msg_size);
+
+ StreamMsgNotifyError *const error = (StreamMsgNotifyError *)(hdr+1);
+ error->error_code = GUINT32_TO_LE(0);
+ strcpy((char *) error->msg, error_msg);
+
+ red_char_device_write_buffer_add(char_dev, buf);
+
+ dev->has_error = true;
+ return false;
+}
+
+static bool
+handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin)
+{
+ StreamMsgFormat fmt;
+ SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
+ int n = sif->read(sin, (uint8_t *) &fmt, sizeof(fmt));
+ if (n == 0) {
+ return false;
+ }
+ if (n != sizeof(fmt)) {
+ return handle_msg_invalid(dev, sin, NULL);
+ }
+ fmt.width = GUINT32_FROM_LE(fmt.width);
+ fmt.height = GUINT32_FROM_LE(fmt.height);
+
+ return true;
+}
+
+static bool
+handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
+{
+ SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
+ int n;
+ while (1) {
+ uint8_t buf[16 * 1024];
n = sif->read(sin, buf, sizeof(buf));
+ /* TODO */
spice_debug("read %d bytes from device", n);
- } while (n > 0);
+ if (n <= 0) {
+ break;
+ }
+ dev->hdr.size -= n;
+ }
- return NULL;
+ return dev->hdr.size == 0;
}
static void

271
SOURCES/0008-stream-channel-Write-a-base-channel-to-implement-the.patch

@ -0,0 +1,271 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 15:29:18 +0000
Subject: [spice-server] stream-channel: Write a base channel to implement the
streaming

Currently only compile, not used and not much sense

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/Makefile.am | 2 +
server/stream-channel.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++
server/stream-channel.h | 53 +++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 server/stream-channel.c
create mode 100644 server/stream-channel.h

diff --git a/server/Makefile.am b/server/Makefile.am
index f08ddf883..e2e3ce861 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -166,6 +166,8 @@ libserver_la_SOURCES = \
stat.h \
stream.c \
stream.h \
+ stream-channel.c \
+ stream-channel.h \
stream-device.c \
sw-canvas.c \
tree.c \
diff --git a/server/stream-channel.c b/server/stream-channel.c
new file mode 100644
index 000000000..fd735f562
--- /dev/null
+++ b/server/stream-channel.c
@@ -0,0 +1,175 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2017 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "red-channel-client.h"
+#include "stream-channel.h"
+#include "reds.h"
+#include "common-graphics-channel.h"
+
+#define TYPE_STREAM_CHANNEL_CLIENT stream_channel_client_get_type()
+
+#define STREAM_CHANNEL_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_STREAM_CHANNEL_CLIENT, StreamChannelClient))
+#define STREAM_CHANNEL_CLIENT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_STREAM_CHANNEL_CLIENT, StreamChannelClientClass))
+#define IS_STREAM_CHANNEL_CLIENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_STREAM_CHANNEL_CLIENT))
+#define IS_STREAM_CHANNEL_CLIENT_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_STREAM_CHANNEL_CLIENT))
+#define STREAM_CHANNEL_CLIENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_STREAM_CHANNEL_CLIENT, StreamChannelClientClass))
+
+typedef struct StreamChannelClient StreamChannelClient;
+typedef struct StreamChannelClientClass StreamChannelClientClass;
+
+/* we need to inherit from CommonGraphicsChannelClient
+ * to get buffer handling */
+struct StreamChannelClient {
+ CommonGraphicsChannelClient parent;
+};
+
+struct StreamChannelClientClass {
+ CommonGraphicsChannelClientClass parent_class;
+};
+
+GType stream_channel_client_get_type(void) G_GNUC_CONST;
+
+G_DEFINE_TYPE(StreamChannelClient, stream_channel_client, TYPE_COMMON_GRAPHICS_CHANNEL_CLIENT)
+
+struct StreamChannel {
+ RedChannel parent;
+};
+
+struct StreamChannelClass {
+ RedChannelClass parent_class;
+};
+
+G_DEFINE_TYPE(StreamChannel, stream_channel, RED_TYPE_CHANNEL)
+
+static void stream_channel_client_on_disconnect(RedChannelClient *rcc);
+
+static void
+stream_channel_client_class_init(StreamChannelClientClass *klass)
+{
+ RedChannelClientClass *channel_class = RED_CHANNEL_CLIENT_CLASS(klass);
+
+ channel_class->on_disconnect = stream_channel_client_on_disconnect;
+}
+
+static void
+stream_channel_client_init(StreamChannelClient *client)
+{
+}
+
+static void
+stream_channel_client_on_disconnect(RedChannelClient *rcc)
+{
+}
+
+static StreamChannelClient*
+stream_channel_client_new(StreamChannel *channel, RedClient *client, RedsStream *stream,
+ int mig_target, RedChannelCapabilities *caps)
+{
+ StreamChannelClient *rcc;
+
+ rcc = g_initable_new(TYPE_STREAM_CHANNEL_CLIENT,
+ NULL, NULL,
+ "channel", channel,
+ "client", client,
+ "stream", stream,
+ "monitor-latency", FALSE,
+ "caps", caps,
+ NULL);
+
+ return rcc;
+}
+
+static void
+stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
+{
+ switch (pipe_item->type) {
+ default:
+ spice_error("invalid pipe item type");
+ }
+
+ red_channel_client_begin_send_message(rcc);
+}
+
+StreamChannel*
+stream_channel_new(RedsState *server, uint32_t id)
+{
+ return g_object_new(TYPE_STREAM_CHANNEL,
+ "spice-server", server,
+ "core-interface", reds_get_core_interface(server),
+ "channel-type", SPICE_CHANNEL_DISPLAY,
+ // TODO this id should be after all qxl devices
+ "id", id,
+ "migration-flags", 0,
+ "handle-acks", TRUE, // TODO sure ??
+ NULL);
+}
+
+static void
+stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedsStream *stream,
+ int migration, RedChannelCapabilities *caps)
+{
+ StreamChannel *channel = STREAM_CHANNEL(red_channel);
+ StreamChannelClient *client;
+
+ spice_return_if_fail(stream != NULL);
+
+ client = stream_channel_client_new(channel, red_client, stream, migration, caps);
+ spice_return_if_fail(client != NULL);
+}
+
+static void
+stream_channel_constructed(GObject *object)
+{
+ ClientCbs client_cbs = { NULL, };
+ RedChannel *red_channel = RED_CHANNEL(object);
+ RedsState *reds = red_channel_get_server(red_channel);
+
+ G_OBJECT_CLASS(stream_channel_parent_class)->constructed(object);
+
+ client_cbs.connect = stream_channel_connect;
+ red_channel_register_client_cbs(red_channel, &client_cbs, NULL);
+
+ reds_register_channel(reds, red_channel);
+}
+
+static void
+stream_channel_class_init(StreamChannelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
+
+ object_class->constructed = stream_channel_constructed;
+
+ channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_DISPLAY, NULL);
+ channel_class->handle_message = red_channel_client_handle_message;
+
+ channel_class->send_item = stream_channel_send_item;
+}
+
+static void
+stream_channel_init(StreamChannel *channel)
+{
+}
diff --git a/server/stream-channel.h b/server/stream-channel.h
new file mode 100644
index 000000000..e50e17e9e
--- /dev/null
+++ b/server/stream-channel.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2017 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef STREAM_CHANNEL_H_
+#define STREAM_CHANNEL_H_
+
+#include "red-channel.h"
+
+G_BEGIN_DECLS
+
+/**
+ * This type it's a RedChannel class which implement display
+ * channel with input only by stream.
+ * A pointer to StreamChannel can be converted to a RedChannel.
+ */
+typedef struct StreamChannel StreamChannel;
+typedef struct StreamChannelClass StreamChannelClass;
+
+#define TYPE_STREAM_CHANNEL stream_channel_get_type()
+
+#define STREAM_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_STREAM_CHANNEL, StreamChannel))
+#define STREAM_CHANNEL_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_STREAM_CHANNEL, StreamChannelClass))
+#define IS_STREAM_CHANNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_STREAM_CHANNEL))
+#define IS_STREAM_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_STREAM_CHANNEL))
+#define STREAM_CHANNEL_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_STREAM_CHANNEL, StreamChannelClass))
+
+GType stream_channel_get_type(void) G_GNUC_CONST;
+
+/**
+ * Create StreamChannel.
+ */
+StreamChannel* stream_channel_new(RedsState *server, uint32_t id);
+
+G_END_DECLS
+
+#endif /* STREAM_CHANNEL_H_ */

88
SOURCES/0009-stream-channel-Start-implementing-DisplayChannel-pro.patch

@ -0,0 +1,88 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Tue, 14 Mar 2017 12:12:22 +0000
Subject: [spice-server] stream-channel: Start implementing DisplayChannel
properly

Handle messages from clients.
Send some messages to clients.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 41 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index fd735f562..df6936513 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -113,6 +113,25 @@ stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
red_channel_client_begin_send_message(rcc);
}
+static bool
+handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, void *msg)
+{
+ switch (type) {
+ case SPICE_MSGC_DISPLAY_INIT:
+ case SPICE_MSGC_DISPLAY_PREFERRED_COMPRESSION:
+ return true;
+ case SPICE_MSGC_DISPLAY_STREAM_REPORT:
+ /* TODO these will help tune the streaming reducing/increasing quality */
+ return true;
+ case SPICE_MSGC_DISPLAY_GL_DRAW_DONE:
+ /* client should not send this message */
+ return false;
+ default:
+ return red_channel_client_handle_message(rcc, type, size, msg);
+ }
+}
+
+
StreamChannel*
stream_channel_new(RedsState *server, uint32_t id)
{
@@ -138,6 +157,22 @@ stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedsStrea
client = stream_channel_client_new(channel, red_client, stream, migration, caps);
spice_return_if_fail(client != NULL);
+
+ // TODO set capabilities like SPICE_DISPLAY_CAP_MONITORS_CONFIG
+ // see guest_set_client_capabilities
+ RedChannelClient *rcc = RED_CHANNEL_CLIENT(client);
+ red_channel_client_push_set_ack(rcc);
+
+ // TODO what should happen on migration, dcc return if on migration wait ??
+ red_channel_client_ack_zero_messages_window(rcc);
+
+ // "emulate" dcc_start
+ // TODO only if "surface"
+ red_channel_client_pipe_add_empty_msg(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
+ // TODO red_surface_create_item_new
+ // TODO surface data ??
+ // TODO monitor configs ??
+ red_channel_client_pipe_add_empty_msg(rcc, SPICE_MSG_DISPLAY_MARK);
}
static void
@@ -152,6 +187,10 @@ stream_channel_constructed(GObject *object)
client_cbs.connect = stream_channel_connect;
red_channel_register_client_cbs(red_channel, &client_cbs, NULL);
+ // TODO, send monitor to support multiple monitors in the future
+// red_channel_set_cap(red_channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
+ red_channel_set_cap(red_channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
+
reds_register_channel(reds, red_channel);
}
@@ -164,7 +203,7 @@ stream_channel_class_init(StreamChannelClass *klass)
object_class->constructed = stream_channel_constructed;
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_DISPLAY, NULL);
- channel_class->handle_message = red_channel_client_handle_message;
+ channel_class->handle_message = handle_message;
channel_class->send_item = stream_channel_send_item;
}

151
SOURCES/0010-stream-device-Create-channel-for-stream-device.patch

@ -0,0 +1,151 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 14:02:29 +0000
Subject: [spice-server] stream-device: Create channel for stream device

So can be used by the device to communicate with the clients.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++--
server/stream-device.c | 14 +++++++++++++
2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index df6936513..baf3d58a6 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -19,6 +19,8 @@
#include <config.h>
#endif
+#include <common/generated_server_marshallers.h>
+
#include "red-channel-client.h"
#include "stream-channel.h"
#include "reds.h"
@@ -64,6 +66,13 @@ struct StreamChannelClass {
G_DEFINE_TYPE(StreamChannel, stream_channel, RED_TYPE_CHANNEL)
+enum {
+ RED_PIPE_ITEM_TYPE_SURFACE_CREATE = RED_PIPE_ITEM_TYPE_COMMON_LAST,
+ RED_PIPE_ITEM_TYPE_FILL_SURFACE,
+};
+
+#define PRIMARY_SURFACE_ID 0
+
static void stream_channel_client_on_disconnect(RedChannelClient *rcc);
static void
@@ -103,9 +112,46 @@ stream_channel_client_new(StreamChannel *channel, RedClient *client, RedsStream
}
static void
+fill_base(SpiceMarshaller *m)
+{
+ SpiceMsgDisplayBase base;
+
+ base.surface_id = PRIMARY_SURFACE_ID;
+ base.box = (SpiceRect) { 0, 0, 1024, 768 };
+ base.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
+
+ spice_marshall_DisplayBase(m, &base);
+}
+
+static void
stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
{
+ SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
+
switch (pipe_item->type) {
+ case RED_PIPE_ITEM_TYPE_SURFACE_CREATE: {
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_CREATE);
+ SpiceMsgSurfaceCreate surface_create = {
+ PRIMARY_SURFACE_ID,
+ 1024, 768,
+ SPICE_SURFACE_FMT_32_xRGB, SPICE_SURFACE_FLAGS_PRIMARY
+ };
+ spice_marshall_msg_display_surface_create(m, &surface_create);
+ break;
+ }
+ case RED_PIPE_ITEM_TYPE_FILL_SURFACE: {
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_FILL);
+
+ fill_base(m);
+
+ SpiceFill fill;
+ fill.brush = (SpiceBrush) { SPICE_BRUSH_TYPE_SOLID, { .color = 0 } };
+ fill.rop_descriptor = SPICE_ROPD_OP_PUT;
+ fill.mask = (SpiceQMask) { 0, { 0, 0 }, NULL };
+ SpiceMarshaller *brush_pat_out, *mask_bitmap_out;
+ spice_marshall_Fill(m, &fill, &brush_pat_out, &mask_bitmap_out);
+ break;
+ }
default:
spice_error("invalid pipe item type");
}
@@ -169,8 +215,10 @@ stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedsStrea
// "emulate" dcc_start
// TODO only if "surface"
red_channel_client_pipe_add_empty_msg(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
- // TODO red_surface_create_item_new
- // TODO surface data ??
+ // TODO pass proper data
+ red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_SURFACE_CREATE);
+ // surface data
+ red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_FILL_SURFACE);
// TODO monitor configs ??
red_channel_client_pipe_add_empty_msg(rcc, SPICE_MSG_DISPLAY_MARK);
}
diff --git a/server/stream-device.c b/server/stream-device.c
index 58edb3d11..0c9173ae0 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -22,6 +22,8 @@
#include <spice/stream-device.h>
#include "char-device.h"
+#include "stream-channel.h"
+#include "reds.h"
#define TYPE_STREAM_DEVICE stream_device_get_type()
@@ -37,9 +39,11 @@ typedef struct StreamDeviceClass StreamDeviceClass;
struct StreamDevice {
RedCharDevice parent;
+
StreamDevHeader hdr;
uint8_t hdr_pos;
bool has_error;
+ StreamChannel *stream_channel;
};
struct StreamDeviceClass {
@@ -204,7 +208,10 @@ stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif;
+ StreamChannel *stream_channel = stream_channel_new(reds, 1); // TODO id
+
StreamDevice *dev = stream_device_new(sin, reds);
+ dev->stream_channel = stream_channel;
sif = spice_char_device_get_interface(sin);
if (sif->state) {
@@ -217,6 +224,13 @@ stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin)
static void
stream_device_dispose(GObject *object)
{
+ StreamDevice *dev = STREAM_DEVICE(object);
+
+ if (dev->stream_channel) {
+ // close all current connections and drop the reference
+ red_channel_destroy(RED_CHANNEL(dev->stream_channel));
+ dev->stream_channel = NULL;
+ }
}
static void

231
SOURCES/0011-stream-device-Handle-streaming-data-from-device-to-c.patch

@ -0,0 +1,231 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 10:47:40 +0000
Subject: [spice-server] stream-device: Handle streaming data from device to
channel

Handle stream data from device sending to the channel.
The StreamChannel will forward the data to the clients using standard
DisplayChannel messages, and will create and destroy streams as
necessary.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
server/stream-channel.h | 8 ++++
server/stream-device.c | 4 +-
3 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index baf3d58a6..8931d8794 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -20,11 +20,13 @@
#endif
#include <common/generated_server_marshallers.h>
+#include <spice/stream-device.h>
#include "red-channel-client.h"
#include "stream-channel.h"
#include "reds.h"
#include "common-graphics-channel.h"
+#include "display-limits.h"
#define TYPE_STREAM_CHANNEL_CLIENT stream_channel_client_get_type()
@@ -46,6 +48,10 @@ typedef struct StreamChannelClientClass StreamChannelClientClass;
* to get buffer handling */
struct StreamChannelClient {
CommonGraphicsChannelClient parent;
+
+ /* current video stream id, <0 if not initialized or
+ * we are not sending a stream */
+ int stream_id;
};
struct StreamChannelClientClass {
@@ -58,6 +64,10 @@ G_DEFINE_TYPE(StreamChannelClient, stream_channel_client, TYPE_COMMON_GRAPHICS_C
struct StreamChannel {
RedChannel parent;
+
+ /* current video stream id, <0 if not initialized or
+ * we are not sending a stream */
+ int stream_id;
};
struct StreamChannelClass {
@@ -69,8 +79,22 @@ G_DEFINE_TYPE(StreamChannel, stream_channel, RED_TYPE_CHANNEL)
enum {
RED_PIPE_ITEM_TYPE_SURFACE_CREATE = RED_PIPE_ITEM_TYPE_COMMON_LAST,
RED_PIPE_ITEM_TYPE_FILL_SURFACE,
+ RED_PIPE_ITEM_TYPE_STREAM_CREATE,
+ RED_PIPE_ITEM_TYPE_STREAM_DATA,
+ RED_PIPE_ITEM_TYPE_STREAM_DESTROY,
};
+typedef struct StreamCreateItem {
+ RedPipeItem base;
+ SpiceMsgDisplayStreamCreate stream_create;
+} StreamCreateItem;
+
+typedef struct StreamDataItem {
+ RedPipeItem base;
+ // NOTE: this must be the last field in the structure
+ SpiceMsgDisplayStreamData data;
+} StreamDataItem;
+
#define PRIMARY_SURFACE_ID 0
static void stream_channel_client_on_disconnect(RedChannelClient *rcc);
@@ -86,6 +110,7 @@ stream_channel_client_class_init(StreamChannelClientClass *klass)
static void
stream_channel_client_init(StreamChannelClient *client)
{
+ client->stream_id = -1;
}
static void
@@ -127,6 +152,7 @@ static void
stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
{
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
+ StreamChannelClient *client = STREAM_CHANNEL_CLIENT(rcc);
switch (pipe_item->type) {
case RED_PIPE_ITEM_TYPE_SURFACE_CREATE: {
@@ -152,6 +178,32 @@ stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
spice_marshall_Fill(m, &fill, &brush_pat_out, &mask_bitmap_out);
break;
}
+ case RED_PIPE_ITEM_TYPE_STREAM_CREATE: {
+ StreamCreateItem *item = SPICE_UPCAST(StreamCreateItem, pipe_item);
+ client->stream_id = item->stream_create.id;
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE);
+ spice_marshall_msg_display_stream_create(m, &item->stream_create);
+ break;
+ }
+ case RED_PIPE_ITEM_TYPE_STREAM_DATA: {
+ StreamDataItem *item = SPICE_UPCAST(StreamDataItem, pipe_item);
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA);
+ spice_marshall_msg_display_stream_data(m, &item->data);
+ red_pipe_item_ref(pipe_item);
+ spice_marshaller_add_by_ref_full(m, item->data.data, item->data.data_size,
+ marshaller_unref_pipe_item, pipe_item);
+ break;
+ }
+ case RED_PIPE_ITEM_TYPE_STREAM_DESTROY: {
+ if (client->stream_id < 0) {
+ return;
+ }
+ SpiceMsgDisplayStreamDestroy stream_destroy = { client->stream_id };
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY);
+ spice_marshall_msg_display_stream_destroy(m, &stream_destroy);
+ client->stream_id = -1;
+ break;
+ }
default:
spice_error("invalid pipe item type");
}
@@ -259,4 +311,55 @@ stream_channel_class_init(StreamChannelClass *klass)
static void
stream_channel_init(StreamChannel *channel)
{
+ channel->stream_id = -1;
+}
+
+void
+stream_channel_change_format(StreamChannel *channel, const StreamMsgFormat *fmt)
+{
+ RedChannel *red_channel = RED_CHANNEL(channel);
+
+ // send destroy old stream
+ red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
+
+ // TODO send new create surface if required
+
+ // allocate a new stream id
+ channel->stream_id = (channel->stream_id + 1) % NUM_STREAMS;
+
+ // send create stream
+ StreamCreateItem *item = g_new0(StreamCreateItem, 1);
+ red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_CREATE);
+ item->stream_create.id = channel->stream_id;
+ item->stream_create.flags = SPICE_STREAM_FLAGS_TOP_DOWN;
+ item->stream_create.codec_type = fmt->codec;
+ item->stream_create.stream_width = fmt->width;
+ item->stream_create.stream_height = fmt->height;
+ item->stream_create.src_width = fmt->width;
+ item->stream_create.src_height = fmt->height;
+ item->stream_create.dest = (SpiceRect) { 0, 0, fmt->width, fmt->height };
+ item->stream_create.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
+ red_channel_pipes_add(red_channel, &item->base);
+}
+
+void
+stream_channel_send_data(StreamChannel *channel, const void *data, size_t size, uint32_t mm_time)
+{
+ if (channel->stream_id < 0) {
+ // this condition can happen if the guest didn't handle
+ // the format stop that we send so think the stream is still
+ // started
+ return;
+ }
+
+ RedChannel *red_channel = RED_CHANNEL(channel);
+
+ StreamDataItem *item = g_malloc(sizeof(*item) + size);
+ red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_DATA);
+ item->data.base.id = channel->stream_id;
+ item->data.base.multi_media_time = mm_time;
+ item->data.data_size = size;
+ // TODO try to optimize avoiding the copy
+ memcpy(item->data.data, data, size);
+ red_channel_pipes_add(red_channel, &item->base);
}
diff --git a/server/stream-channel.h b/server/stream-channel.h
index e50e17e9e..156a75d31 100644
--- a/server/stream-channel.h
+++ b/server/stream-channel.h
@@ -48,6 +48,14 @@ GType stream_channel_get_type(void) G_GNUC_CONST;
*/
StreamChannel* stream_channel_new(RedsState *server, uint32_t id);
+struct StreamMsgFormat;
+
+void stream_channel_change_format(StreamChannel *channel,
+ const struct StreamMsgFormat *fmt);
+void stream_channel_send_data(StreamChannel *channel,
+ const void *data, size_t size,
+ uint32_t mm_time);
+
G_END_DECLS
#endif /* STREAM_CHANNEL_H_ */
diff --git a/server/stream-device.c b/server/stream-device.c
index 0c9173ae0..6e78b1a99 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -164,6 +164,7 @@ handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin)
}
fmt.width = GUINT32_FROM_LE(fmt.width);
fmt.height = GUINT32_FROM_LE(fmt.height);
+ stream_channel_change_format(dev->stream_channel, &fmt);
return true;
}
@@ -176,11 +177,10 @@ handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
while (1) {
uint8_t buf[16 * 1024];
n = sif->read(sin, buf, sizeof(buf));
- /* TODO */
- spice_debug("read %d bytes from device", n);
if (n <= 0) {
break;
}
+ stream_channel_send_data(dev->stream_channel, buf, n, reds_get_mm_time());
dev->hdr.size -= n;
}

115
SOURCES/0012-stream-channel-Allows-not-fixed-size.patch

@ -0,0 +1,115 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 19:03:11 +0000
Subject: [spice-server] stream-channel: Allows not fixed size

Remove the fixed size stream and support any display size.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index 8931d8794..59f566f50 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -68,6 +68,8 @@ struct StreamChannel {
/* current video stream id, <0 if not initialized or
* we are not sending a stream */
int stream_id;
+ /* size of the current video stream */
+ unsigned width, height;
};
struct StreamChannelClass {
@@ -78,6 +80,7 @@ G_DEFINE_TYPE(StreamChannel, stream_channel, RED_TYPE_CHANNEL)
enum {
RED_PIPE_ITEM_TYPE_SURFACE_CREATE = RED_PIPE_ITEM_TYPE_COMMON_LAST,
+ RED_PIPE_ITEM_TYPE_SURFACE_DESTROY,
RED_PIPE_ITEM_TYPE_FILL_SURFACE,
RED_PIPE_ITEM_TYPE_STREAM_CREATE,
RED_PIPE_ITEM_TYPE_STREAM_DATA,
@@ -137,12 +140,12 @@ stream_channel_client_new(StreamChannel *channel, RedClient *client, RedsStream
}
static void
-fill_base(SpiceMarshaller *m)
+fill_base(SpiceMarshaller *m, const StreamChannel *channel)
{
SpiceMsgDisplayBase base;
base.surface_id = PRIMARY_SURFACE_ID;
- base.box = (SpiceRect) { 0, 0, 1024, 768 };
+ base.box = (SpiceRect) { 0, 0, channel->width, channel->height };
base.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
spice_marshall_DisplayBase(m, &base);
@@ -153,22 +156,29 @@ stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
{
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
StreamChannelClient *client = STREAM_CHANNEL_CLIENT(rcc);
+ StreamChannel *channel = STREAM_CHANNEL(red_channel_client_get_channel(rcc));
switch (pipe_item->type) {
case RED_PIPE_ITEM_TYPE_SURFACE_CREATE: {
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_CREATE);
SpiceMsgSurfaceCreate surface_create = {
PRIMARY_SURFACE_ID,
- 1024, 768,
+ channel->width, channel->height,
SPICE_SURFACE_FMT_32_xRGB, SPICE_SURFACE_FLAGS_PRIMARY
};
spice_marshall_msg_display_surface_create(m, &surface_create);
break;
}
+ case RED_PIPE_ITEM_TYPE_SURFACE_DESTROY: {
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_DESTROY);
+ SpiceMsgSurfaceDestroy surface_destroy = { PRIMARY_SURFACE_ID };
+ spice_marshall_msg_display_surface_destroy(m, &surface_destroy);
+ break;
+ }
case RED_PIPE_ITEM_TYPE_FILL_SURFACE: {
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_FILL);
- fill_base(m);
+ fill_base(m, channel);
SpiceFill fill;
fill.brush = (SpiceBrush) { SPICE_BRUSH_TYPE_SOLID, { .color = 0 } };
@@ -267,7 +277,7 @@ stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedsStrea
// "emulate" dcc_start
// TODO only if "surface"
red_channel_client_pipe_add_empty_msg(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
- // TODO pass proper data
+ // pass proper data
red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_SURFACE_CREATE);
// surface data
red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_FILL_SURFACE);
@@ -312,6 +322,8 @@ static void
stream_channel_init(StreamChannel *channel)
{
channel->stream_id = -1;
+ channel->width = 1024;
+ channel->height = 768;
}
void
@@ -322,7 +334,14 @@ stream_channel_change_format(StreamChannel *channel, const StreamMsgFormat *fmt)
// send destroy old stream
red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
- // TODO send new create surface if required
+ // send new create surface if required
+ if (channel->width != fmt->width || channel->height != fmt->height) {
+ channel->width = fmt->width;
+ channel->height = fmt->height;
+ red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_SURFACE_DESTROY);
+ red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_SURFACE_CREATE);
+ // TODO monitors config ??
+ }
// allocate a new stream id
channel->stream_id = (channel->stream_id + 1) % NUM_STREAMS;

67
SOURCES/0013-stream-channel-Allows-to-register-callback-to-get-ne.patch

@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 19:08:12 +0000
Subject: [spice-server] stream-channel: Allows to register callback to get new
stream request

The channel needs to communicate when it receive a new
stream request from the guest.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 12 ++++++++++++
server/stream-channel.h | 6 ++++++
2 files changed, 18 insertions(+)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index 59f566f50..be6f7c7d1 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -70,6 +70,10 @@ struct StreamChannel {
int stream_id;
/* size of the current video stream */
unsigned width, height;
+
+ /* callback to notify when a stream should be started or stopped */
+ stream_channel_start_proc start_cb;
+ void *start_opaque;
};
struct StreamChannelClass {
@@ -382,3 +386,11 @@ stream_channel_send_data(StreamChannel *channel, const void *data, size_t size,
memcpy(item->data.data, data, size);
red_channel_pipes_add(red_channel, &item->base);
}
+
+void
+stream_channel_register_start_cb(StreamChannel *channel,
+ stream_channel_start_proc cb, void *opaque)
+{
+ channel->start_cb = cb;
+ channel->start_opaque = opaque;
+}
diff --git a/server/stream-channel.h b/server/stream-channel.h
index 156a75d31..ba098df49 100644
--- a/server/stream-channel.h
+++ b/server/stream-channel.h
@@ -49,6 +49,7 @@ GType stream_channel_get_type(void) G_GNUC_CONST;
StreamChannel* stream_channel_new(RedsState *server, uint32_t id);
struct StreamMsgFormat;
+struct StreamMsgStartStop;
void stream_channel_change_format(StreamChannel *channel,
const struct StreamMsgFormat *fmt);
@@ -56,6 +57,11 @@ void stream_channel_send_data(StreamChannel *channel,
const void *data, size_t size,
uint32_t mm_time);
+typedef void (*stream_channel_start_proc)(void *opaque, struct StreamMsgStartStop *start,
+ StreamChannel *channel);
+void stream_channel_register_start_cb(StreamChannel *channel,
+ stream_channel_start_proc cb, void *opaque);
+
G_END_DECLS
#endif /* STREAM_CHANNEL_H_ */

131
SOURCES/0014-stream-channel-Support-client-connection-disconnecti.patch

@ -0,0 +1,131 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 19:03:19 +0000
Subject: [spice-server] stream-channel: Support client
connection/disconnection

When a new client is connected we must restart the stream so new
clients can receive correct data without having to wait for the
next full screen (which on idle screen could take ages).
On disconnection we should tell the guest to stop streaming
not wasting resources to stream not needed data.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index be6f7c7d1..2ad9ebae3 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -121,8 +121,32 @@ stream_channel_client_init(StreamChannelClient *client)
}
static void
+request_new_stream(StreamChannel *channel, StreamMsgStartStop *start)
+{
+ if (channel->start_cb) {
+ channel->start_cb(channel->start_opaque, start, channel);
+ }
+}
+
+static void
stream_channel_client_on_disconnect(RedChannelClient *rcc)
{
+ RedChannel *red_channel = red_channel_client_get_channel(rcc);
+
+ // if there are still some client connected keep streaming
+ // TODO, maybe would be worth sending new codecs if they are better
+ if (red_channel_is_connected(red_channel)) {
+ return;
+ }
+
+ StreamChannel *channel = STREAM_CHANNEL(red_channel);
+ channel->stream_id = -1;
+ channel->width = 0;
+ channel->height = 0;
+
+ // send stream stop to device
+ StreamMsgStartStop stop = { 0, };
+ request_new_stream(channel, &stop);
}
static StreamChannelClient*
@@ -258,18 +282,75 @@ stream_channel_new(RedsState *server, uint32_t id)
NULL);
}
+#define MAX_SUPPORTED_CODECS SPICE_VIDEO_CODEC_TYPE_ENUM_END
+
+// find common codecs supported by all clients
+static uint8_t
+stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs)
+{
+ RedChannelClient *rcc;
+ int codec;
+
+ static const uint16_t codec2cap[] = {
+ 0, // invalid
+ SPICE_DISPLAY_CAP_CODEC_MJPEG,
+ SPICE_DISPLAY_CAP_CODEC_VP8,
+ SPICE_DISPLAY_CAP_CODEC_H264,
+ SPICE_DISPLAY_CAP_CODEC_VP9,
+ };
+
+ bool supported[SPICE_N_ELEMENTS(codec2cap)];
+
+ for (codec = 0; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
+ supported[codec] = true;
+ }
+
+ FOREACH_CLIENT(channel, rcc) {
+ for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
+ // if do not support codec delete from list
+ if (!red_channel_client_test_remote_cap(rcc, codec2cap[codec])) {
+ supported[codec] = false;
+ }
+ }
+ }
+
+ // surely mjpeg is supported
+ supported[SPICE_VIDEO_CODEC_TYPE_MJPEG] = true;
+
+ int num = 0;
+ for (codec = 1; codec < SPICE_N_ELEMENTS(codec2cap); ++codec) {
+ if (supported[codec]) {
+ out_codecs[num++] = codec;
+ }
+ }
+
+ return num;
+}
+
static void
stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedsStream *stream,
int migration, RedChannelCapabilities *caps)
{
StreamChannel *channel = STREAM_CHANNEL(red_channel);
StreamChannelClient *client;
+ struct {
+ StreamMsgStartStop base;
+ uint8_t codecs_buffer[MAX_SUPPORTED_CODECS];
+ } start_msg;
+ StreamMsgStartStop *const start = &start_msg.base;
spice_return_if_fail(stream != NULL);
client = stream_channel_client_new(channel, red_client, stream, migration, caps);
spice_return_if_fail(client != NULL);
+ // request new stream
+ start->num_codecs = stream_channel_get_supported_codecs(channel, start->codecs);
+ // send in any case, even if list is not changed
+ // notify device about changes
+ request_new_stream(channel, start);
+
+
// TODO set capabilities like SPICE_DISPLAY_CAP_MONITORS_CONFIG
// see guest_set_client_capabilities
RedChannelClient *rcc = RED_CHANNEL_CLIENT(client);

64
SOURCES/0015-stream-channel-Do-not-show-an-empty-blank-screen-on-.patch

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Sat, 21 Jan 2017 09:01:18 +0000
Subject: [spice-server] stream-channel: Do not show an empty blank screen on
start

Start showing something when we have a surface and stream
instead of showing a blank screen which is now not useful.
Was useful for debugging purposes to understand that the
new channel was sending messages correctly to client and
client could handle them.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index 2ad9ebae3..e89563b82 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -360,8 +360,13 @@ stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedsStrea
red_channel_client_ack_zero_messages_window(rcc);
// "emulate" dcc_start
- // TODO only if "surface"
red_channel_client_pipe_add_empty_msg(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
+
+ // only if "surface"
+ if (channel->width == 0 || channel->height == 0) {
+ return;
+ }
+
// pass proper data
red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_SURFACE_CREATE);
// surface data
@@ -407,8 +412,8 @@ static void
stream_channel_init(StreamChannel *channel)
{
channel->stream_id = -1;
- channel->width = 1024;
- channel->height = 768;
+ channel->width = 0;
+ channel->height = 0;
}
void
@@ -421,11 +426,14 @@ stream_channel_change_format(StreamChannel *channel, const StreamMsgFormat *fmt)
// send new create surface if required
if (channel->width != fmt->width || channel->height != fmt->height) {
+ if (channel->width != 0 && channel->height != 0) {
+ red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_SURFACE_DESTROY);
+ }
channel->width = fmt->width;
channel->height = fmt->height;
- red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_SURFACE_DESTROY);
red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_SURFACE_CREATE);
// TODO monitors config ??
+ red_channel_pipes_add_empty_msg(red_channel, SPICE_MSG_DISPLAY_MARK);
}
// allocate a new stream id

67
SOURCES/0016-char-device-Do-not-stop-and-clear-interface-on-reset.patch

@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Tue, 24 Jan 2017 11:36:27 +0000
Subject: [spice-server] char-device: Do not stop and clear interface on reset

Currently, red_char_device_reset() stops the device, clears all pending
messages, and clears its device instance. After this function is called,
the char device will not work again until it is assigned a new device
instance and restarted. This is fine for the vdagent char device, which
is currently the only user of this function. But for the stream device,
we want to be able to reset the char device to a working state (e.g.
clear all pending messages, etc) without stopping or disabling the char
device. So this function will now only reset the char device to a clean
working state, and the _stop() and _reset_dev_instance() calls will be
moved up to the caller.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/char-device.c | 2 --
server/reds.c | 6 +++++-
2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/server/char-device.c b/server/char-device.c
index 658f9f364..f8a098bd8 100644
--- a/server/char-device.c
+++ b/server/char-device.c
@@ -823,7 +823,6 @@ void red_char_device_reset(RedCharDevice *dev)
GList *client_item;
RedCharDeviceWriteBuffer *buf;
- red_char_device_stop(dev);
dev->priv->wait_for_migrate_data = FALSE;
spice_debug("char device %p", dev);
while ((buf = g_queue_pop_tail(&dev->priv->write_queue))) {
@@ -845,7 +844,6 @@ void red_char_device_reset(RedCharDevice *dev)
dev_client->num_client_tokens += dev_client->num_client_tokens_free;
dev_client->num_client_tokens_free = 0;
}
- red_char_device_reset_dev_instance(dev, NULL);
}
void red_char_device_wakeup(RedCharDevice *dev)
diff --git a/server/reds.c b/server/reds.c
index b24f61ab2..401d242fb 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -470,6 +470,7 @@ static void reds_reset_vdp(RedsState *reds)
{
RedCharDeviceVDIPort *dev = reds->agent_dev;
SpiceCharDeviceInterface *sif;
+ RedCharDevice *char_dev;
dev->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER;
dev->priv->receive_pos = (uint8_t *)&dev->priv->vdi_chunk_header;
@@ -502,7 +503,10 @@ static void reds_reset_vdp(RedsState *reds)
* The tokens are also reset to avoid mismatch in upon agent reconnection.
*/
dev->priv->agent_attached = FALSE;
- red_char_device_reset(RED_CHAR_DEVICE(dev));
+ char_dev = RED_CHAR_DEVICE(dev);
+ red_char_device_stop(char_dev);
+ red_char_device_reset(char_dev);
+ red_char_device_reset_dev_instance(char_dev, NULL);
sif = spice_char_device_get_interface(reds->vdagent);
if (sif->state) {

166
SOURCES/0017-stream-device-Start-supporting-resetting-device-when.patch

@ -0,0 +1,166 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Wed, 25 Jan 2017 22:42:00 +0000
Subject: [spice-server] stream-device: Start supporting resetting device when
close/open on guest

When guest close the device the host device has to be reset too.
This make easier to restart the guest device which can happen in case
of reboot, agent issues or if we want to update the agent.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 34 ++++++++++++++++++++++++++++++++++
server/stream-channel.h | 7 ++++++-
server/stream-device.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index e89563b82..51b8badf9 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -483,3 +483,37 @@ stream_channel_register_start_cb(StreamChannel *channel,
channel->start_cb = cb;
channel->start_opaque = opaque;
}
+
+void
+stream_channel_reset(StreamChannel *channel)
+{
+ struct {
+ StreamMsgStartStop base;
+ uint8_t codecs_buffer[MAX_SUPPORTED_CODECS];
+ } start_msg;
+ StreamMsgStartStop *const start = &start_msg.base;
+ RedChannel *red_channel = RED_CHANNEL(channel);
+
+ // send destroy old stream
+ red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
+
+ // destroy display surface
+ if (channel->width != 0 && channel->height != 0) {
+ red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_SURFACE_DESTROY);
+ }
+
+ channel->stream_id = -1;
+ channel->width = 0;
+ channel->height = 0;
+
+ if (!red_channel_is_connected(red_channel)) {
+ return;
+ }
+
+ // try to request a new stream, this should start a new stream
+ // if the guest is connected to the device and a client is already connected
+ start->num_codecs = stream_channel_get_supported_codecs(channel, start->codecs);
+ // send in any case, even if list is not changed
+ // notify device about changes
+ request_new_stream(channel, start);
+}
diff --git a/server/stream-channel.h b/server/stream-channel.h
index ba098df49..bd075a951 100644
--- a/server/stream-channel.h
+++ b/server/stream-channel.h
@@ -48,7 +48,12 @@ GType stream_channel_get_type(void) G_GNUC_CONST;
*/
StreamChannel* stream_channel_new(RedsState *server, uint32_t id);
-struct StreamMsgFormat;
+/**
+ * Reset channel at initial state
+ */
+void stream_channel_reset(StreamChannel *channel);
+
+struct StreamMsgStreamFormat;
struct StreamMsgStartStop;
void stream_channel_change_format(StreamChannel *channel,
diff --git a/server/stream-device.c b/server/stream-device.c
index 6e78b1a99..9e401f8ed 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -43,6 +43,7 @@ struct StreamDevice {
StreamDevHeader hdr;
uint8_t hdr_pos;
bool has_error;
+ bool opened;
StreamChannel *stream_channel;
};
@@ -203,6 +204,35 @@ stream_device_remove_client(RedCharDevice *self, RedClient *client)
{
}
+static void
+stream_device_stream_start(void *opaque, StreamMsgStartStop *start,
+ StreamChannel *stream_channel G_GNUC_UNUSED)
+{
+ StreamDevice *dev = (StreamDevice *) opaque;
+
+ if (!dev->opened) {
+ return;
+ }
+
+ int msg_size = sizeof(*start) + sizeof(start->codecs[0]) * start->num_codecs;
+ int total_size = sizeof(StreamDevHeader) + msg_size;
+
+ RedCharDevice *char_dev = RED_CHAR_DEVICE(dev);
+ RedCharDeviceWriteBuffer *buf =
+ red_char_device_write_buffer_get_server_no_token(char_dev, total_size);
+ buf->buf_used = total_size;
+
+ StreamDevHeader *hdr = (StreamDevHeader *)buf->buf;
+ hdr->protocol_version = STREAM_DEVICE_PROTOCOL;
+ hdr->padding = 0;
+ hdr->type = GUINT16_TO_LE(STREAM_TYPE_START_STOP);
+ hdr->size = GUINT32_TO_LE(msg_size);
+
+ memcpy(&hdr[1], start, msg_size);
+
+ red_char_device_write_buffer_add(char_dev, buf);
+}
+
RedCharDevice *
stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin)
{
@@ -212,6 +242,7 @@ stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin)
StreamDevice *dev = stream_device_new(sin, reds);
dev->stream_channel = stream_channel;
+ stream_channel_register_start_cb(stream_channel, stream_device_stream_start, dev);
sif = spice_char_device_get_interface(sin);
if (sif->state) {
@@ -234,6 +265,23 @@ stream_device_dispose(GObject *object)
}
static void
+stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
+{
+ if (event != SPICE_PORT_EVENT_OPENED && event != SPICE_PORT_EVENT_CLOSED) {
+ return;
+ }
+
+ StreamDevice *dev = STREAM_DEVICE(char_dev);
+
+ // reset device and channel on close/open
+ dev->opened = (event == SPICE_PORT_EVENT_OPENED);
+ dev->hdr_pos = 0;
+ dev->has_error = false;
+ red_char_device_reset(char_dev);
+ stream_channel_reset(dev->stream_channel);
+}
+
+static void
stream_device_class_init(StreamDeviceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
@@ -245,6 +293,7 @@ stream_device_class_init(StreamDeviceClass *klass)
char_dev_class->send_msg_to_client = stream_device_send_msg_to_client;
char_dev_class->send_tokens_to_client = stream_device_send_tokens_to_client;
char_dev_class->remove_client = stream_device_remove_client;
+ char_dev_class->port_event = stream_device_port_event;
}
static void

89
SOURCES/0018-stream-device-Create-channel-when-needed.patch

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Fri, 25 Aug 2017 00:02:54 +0100
Subject: [spice-server] stream-device: Create channel when needed

This allows a better id allocation as devices are created after
fixed ones.
Also will allow to support more easily multiple monitor.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-device.c | 38 ++++++++++++++++++++++++++++++++------
1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/server/stream-device.c b/server/stream-device.c
index 9e401f8ed..ae108788b 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -72,7 +72,7 @@ stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *si
int n;
bool handled = false;
- if (dev->has_error) {
+ if (dev->has_error || !dev->stream_channel) {
return NULL;
}
@@ -238,11 +238,7 @@ stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin)
{
SpiceCharDeviceInterface *sif;
- StreamChannel *stream_channel = stream_channel_new(reds, 1); // TODO id
-
StreamDevice *dev = stream_device_new(sin, reds);
- dev->stream_channel = stream_channel;
- stream_channel_register_start_cb(stream_channel, stream_device_stream_start, dev);
sif = spice_char_device_get_interface(sin);
if (sif->state) {
@@ -265,6 +261,33 @@ stream_device_dispose(GObject *object)
}
static void
+allocate_channels(StreamDevice *dev)
+{
+ if (dev->stream_channel) {
+ return;
+ }
+
+ SpiceServer* reds = red_char_device_get_server(RED_CHAR_DEVICE(dev));
+
+ int id = reds_get_free_channel_id(reds, SPICE_CHANNEL_DISPLAY);
+ g_return_if_fail(id >= 0);
+
+ StreamChannel *stream_channel = stream_channel_new(reds, id);
+
+ dev->stream_channel = stream_channel;
+
+ stream_channel_register_start_cb(stream_channel, stream_device_stream_start, dev);
+}
+
+static void
+reset_channels(StreamDevice *dev)
+{
+ if (dev->stream_channel) {
+ stream_channel_reset(dev->stream_channel);
+ }
+}
+
+static void
stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
{
if (event != SPICE_PORT_EVENT_OPENED && event != SPICE_PORT_EVENT_CLOSED) {
@@ -275,10 +298,13 @@ stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
// reset device and channel on close/open
dev->opened = (event == SPICE_PORT_EVENT_OPENED);
+ if (dev->opened) {
+ allocate_channels(dev);
+ }
dev->hdr_pos = 0;
dev->has_error = false;
red_char_device_reset(char_dev);
- stream_channel_reset(dev->stream_channel);
+ reset_channels(dev);
}
static void

206
SOURCES/0019-stream-device-Limit-sending-queue-from-guest-to-serv.patch

@ -0,0 +1,206 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Wed, 19 Apr 2017 16:24:54 +0100
Subject: [spice-server] stream-device: Limit sending queue from guest to
server

Do not allow the guest to fill host memory.
Also having a huge queue mainly cause to have a higher video
latency.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 41 ++++++++++++++++++++++++++++++++++++++++-
server/stream-channel.h | 10 ++++++++++
server/stream-device.c | 35 ++++++++++++++++++++++++++++++++++-
3 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index 51b8badf9..ec4bf021d 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -71,9 +71,15 @@ struct StreamChannel {
/* size of the current video stream */
unsigned width, height;
+ StreamQueueStat queue_stat;
+
/* callback to notify when a stream should be started or stopped */
stream_channel_start_proc start_cb;
void *start_opaque;
+
+ /* callback to notify when queue statistics changes */
+ stream_channel_queue_stat_proc queue_cb;
+ void *queue_opaque;
};
struct StreamChannelClass {
@@ -98,6 +104,7 @@ typedef struct StreamCreateItem {
typedef struct StreamDataItem {
RedPipeItem base;
+ StreamChannel *channel;
// NOTE: this must be the last field in the structure
SpiceMsgDisplayStreamData data;
} StreamDataItem;
@@ -454,6 +461,27 @@ stream_channel_change_format(StreamChannel *channel, const StreamMsgFormat *fmt)
red_channel_pipes_add(red_channel, &item->base);
}
+static inline void
+stream_channel_update_queue_stat(StreamChannel *channel,
+ int32_t num_diff, int32_t size_diff)
+{
+ channel->queue_stat.num_items += num_diff;
+ channel->queue_stat.size += size_diff;
+ if (channel->queue_cb) {
+ channel->queue_cb(channel->queue_opaque, &channel->queue_stat, channel);
+ }
+}
+
+static void
+data_item_free(RedPipeItem *base)
+{
+ StreamDataItem *pipe_item = SPICE_UPCAST(StreamDataItem, base);
+
+ stream_channel_update_queue_stat(pipe_item->channel, -1, -pipe_item->data.data_size);
+
+ g_free(pipe_item);
+}
+
void
stream_channel_send_data(StreamChannel *channel, const void *data, size_t size, uint32_t mm_time)
{
@@ -467,10 +495,13 @@ stream_channel_send_data(StreamChannel *channel, const void *data, size_t size,
RedChannel *red_channel = RED_CHANNEL(channel);
StreamDataItem *item = g_malloc(sizeof(*item) + size);
- red_pipe_item_init(&item->base, RED_PIPE_ITEM_TYPE_STREAM_DATA);
+ red_pipe_item_init_full(&item->base, RED_PIPE_ITEM_TYPE_STREAM_DATA,
+ data_item_free);
item->data.base.id = channel->stream_id;
item->data.base.multi_media_time = mm_time;
item->data.data_size = size;
+ item->channel = channel;
+ stream_channel_update_queue_stat(channel, 1, size);
// TODO try to optimize avoiding the copy
memcpy(item->data.data, data, size);
red_channel_pipes_add(red_channel, &item->base);
@@ -485,6 +516,14 @@ stream_channel_register_start_cb(StreamChannel *channel,
}
void
+stream_channel_register_queue_stat_cb(StreamChannel *channel,
+ stream_channel_queue_stat_proc cb, void *opaque)
+{
+ channel->queue_cb = cb;
+ channel->queue_opaque = opaque;
+}
+
+void
stream_channel_reset(StreamChannel *channel)
{
struct {
diff --git a/server/stream-channel.h b/server/stream-channel.h
index bd075a951..f961d7157 100644
--- a/server/stream-channel.h
+++ b/server/stream-channel.h
@@ -67,6 +67,16 @@ typedef void (*stream_channel_start_proc)(void *opaque, struct StreamMsgStartSto
void stream_channel_register_start_cb(StreamChannel *channel,
stream_channel_start_proc cb, void *opaque);
+typedef struct StreamQueueStat {
+ uint32_t num_items;
+ uint32_t size;
+} StreamQueueStat;
+
+typedef void (*stream_channel_queue_stat_proc)(void *opaque, const StreamQueueStat *stats,
+ StreamChannel *channel);
+void stream_channel_register_queue_stat_cb(StreamChannel *channel,
+ stream_channel_queue_stat_proc cb, void *opaque);
+
G_END_DECLS
#endif /* STREAM_CHANNEL_H_ */
diff --git a/server/stream-device.c b/server/stream-device.c
index ae108788b..f87538d49 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -44,6 +44,7 @@ struct StreamDevice {
uint8_t hdr_pos;
bool has_error;
bool opened;
+ bool flow_stopped;
StreamChannel *stream_channel;
};
@@ -72,7 +73,7 @@ stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *si
int n;
bool handled = false;
- if (dev->has_error || !dev->stream_channel) {
+ if (dev->has_error || dev->flow_stopped || !dev->stream_channel) {
return NULL;
}
@@ -181,6 +182,9 @@ handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
if (n <= 0) {
break;
}
+ // TODO collect all message ??
+ // up: we send a single frame together
+ // down: guest can cause a crash
stream_channel_send_data(dev->stream_channel, buf, n, reds_get_mm_time());
dev->hdr.size -= n;
}
@@ -233,6 +237,33 @@ stream_device_stream_start(void *opaque, StreamMsgStartStop *start,
red_char_device_write_buffer_add(char_dev, buf);
}
+static void
+stream_device_stream_queue_stat(void *opaque, const StreamQueueStat *stats G_GNUC_UNUSED,
+ StreamChannel *stream_channel G_GNUC_UNUSED)
+{
+ StreamDevice *dev = (StreamDevice *) opaque;
+
+ if (!dev->opened) {
+ return;
+ }
+
+ // very easy control flow... if any data stop
+ // this seems a very small queue but as we use tcp
+ // there's already that queue
+ if (stats->num_items) {
+ dev->flow_stopped = true;
+ return;
+ }
+
+ if (dev->flow_stopped) {
+ dev->flow_stopped = false;
+ // TODO resume flow...
+ // avoid recursion if we need to call get data from data handling from
+ // data handling
+ red_char_device_wakeup(&dev->parent);
+ }
+}
+
RedCharDevice *
stream_device_connect(RedsState *reds, SpiceCharDeviceInstance *sin)
{
@@ -277,6 +308,7 @@ allocate_channels(StreamDevice *dev)
dev->stream_channel = stream_channel;
stream_channel_register_start_cb(stream_channel, stream_device_stream_start, dev);
+ stream_channel_register_queue_stat_cb(stream_channel, stream_device_stream_queue_stat, dev);
}
static void
@@ -303,6 +335,7 @@ stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
}
dev->hdr_pos = 0;
dev->has_error = false;
+ dev->flow_stopped = false;
red_char_device_reset(char_dev);
reset_channels(dev);
}

65
SOURCES/0020-stream-channel-Activate-streaming-report-from-client.patch

@ -0,0 +1,65 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Wed, 7 Jun 2017 13:13:21 +0100
Subject: [spice-server] stream-channel: Activate streaming report from client

Setting the capability is not enough, each stream must be enabled
so do so if client support them.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
---
server/stream-channel.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index ec4bf021d..7e15dd363 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -27,6 +27,7 @@
#include "reds.h"
#include "common-graphics-channel.h"
#include "display-limits.h"
+#include "stream.h" // TODO remove, put common stuff
#define TYPE_STREAM_CHANNEL_CLIENT stream_channel_client_get_type()
@@ -95,6 +96,7 @@ enum {
RED_PIPE_ITEM_TYPE_STREAM_CREATE,
RED_PIPE_ITEM_TYPE_STREAM_DATA,
RED_PIPE_ITEM_TYPE_STREAM_DESTROY,
+ RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
};
typedef struct StreamCreateItem {
@@ -230,6 +232,20 @@ stream_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_item)
spice_marshall_msg_display_stream_create(m, &item->stream_create);
break;
}
+ case RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT: {
+ if (client->stream_id < 0
+ || !red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_STREAM_REPORT)) {
+ return;
+ }
+ SpiceMsgDisplayStreamActivateReport msg;
+ msg.stream_id = client->stream_id;
+ msg.unique_id = 1; // TODO useful ?
+ msg.max_window_size = RED_STREAM_CLIENT_REPORT_WINDOW;
+ msg.timeout_ms = RED_STREAM_CLIENT_REPORT_TIMEOUT;
+ red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT);
+ spice_marshall_msg_display_stream_activate_report(m, &msg);
+ break;
+ }
case RED_PIPE_ITEM_TYPE_STREAM_DATA: {
StreamDataItem *item = SPICE_UPCAST(StreamDataItem, pipe_item);
red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA);
@@ -459,6 +475,9 @@ stream_channel_change_format(StreamChannel *channel, const StreamMsgFormat *fmt)
item->stream_create.dest = (SpiceRect) { 0, 0, fmt->width, fmt->height };
item->stream_create.clip = (SpiceClip) { SPICE_CLIP_TYPE_NONE, NULL };
red_channel_pipes_add(red_channel, &item->base);
+
+ // activate stream report if possible
+ red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
}
static inline void

271
SPECS/spice.spec

@ -1,27 +1,50 @@
Name: spice Name: spice
Version: 0.14.0 Version: 0.14.0
Release: 1%{?dist} Release: 2%{?dist}
Summary: Implements the SPICE protocol Summary: Implements the SPICE protocol
Group: User Interface/Desktops Group: User Interface/Desktops
License: LGPLv2+ License: LGPLv2+
URL: http://www.spice-space.org/ URL: http://www.spice-space.org/
Source0: http://www.spice-space.org/download/releases/%{name}-%{version}.tar.bz2 Source0: http://www.spice-space.org/download/releases/%{name}-%{version}.tar.bz2
Source1: http://www.spice-space.org/download/releases/%{name}-%{version}.tar.bz2.sign Patch1: 0001-inputs-channel-Check-message-size-handling-migration.patch
Source2: cfergeau-29AC6C82.keyring Patch2: 0002-red-channel-Remove-red_channel_init_outgoing_message.patch
Patch3: 0003-reds-Remove-leak-allocating-migration-state.patch
Patch4: 0004-tests-Check-leaks-registering-migration-interface.patch
Patch5: 0005-Notify-client-of-the-creation-of-new-channels-dynami.patch
Patch6: 0006-stream-device-Add-device-to-handle-streaming.patch
Patch7: 0007-stream-device-Start-parsing-new-protocol-from-guest.patch
Patch8: 0008-stream-channel-Write-a-base-channel-to-implement-the.patch
Patch9: 0009-stream-channel-Start-implementing-DisplayChannel-pro.patch
Patch10: 0010-stream-device-Create-channel-for-stream-device.patch
Patch11: 0011-stream-device-Handle-streaming-data-from-device-to-c.patch
Patch12: 0012-stream-channel-Allows-not-fixed-size.patch
Patch13: 0013-stream-channel-Allows-to-register-callback-to-get-ne.patch
Patch14: 0014-stream-channel-Support-client-connection-disconnecti.patch
Patch15: 0015-stream-channel-Do-not-show-an-empty-blank-screen-on-.patch
Patch16: 0016-char-device-Do-not-stop-and-clear-interface-on-reset.patch
Patch17: 0017-stream-device-Start-supporting-resetting-device-when.patch
Patch18: 0018-stream-device-Create-channel-when-needed.patch
Patch19: 0019-stream-device-Limit-sending-queue-from-guest-to-serv.patch
Patch20: 0020-stream-channel-Activate-streaming-report-from-client.patch

# https://bugzilla.redhat.com/show_bug.cgi?id=613529
%if 0%{?rhel}
ExclusiveArch: x86_64
%else
ExclusiveArch: i686 x86_64 armv6l armv7l armv7hl
%endif

BuildRequires: pkgconfig BuildRequires: pkgconfig
BuildRequires: glib2-devel >= 2.22 BuildRequires: glib2-devel >= 2.22
BuildRequires: spice-protocol >= 0.12.3 BuildRequires: spice-protocol >= 0.12.10
BuildRequires: celt051-devel BuildRequires: celt051-devel
BuildRequires: opus-devel BuildRequires: pixman-devel alsa-lib-devel openssl-devel libjpeg-turbo-devel
BuildRequires: pixman-devel openssl-devel libjpeg-devel
BuildRequires: libcacard-devel cyrus-sasl-devel BuildRequires: libcacard-devel cyrus-sasl-devel
BuildRequires: lz4-devel BuildRequires: lz4-devel
BuildRequires: gstreamer1-devel gstreamer1-plugins-base-devel
BuildRequires: orc-devel
BuildRequires: pyparsing BuildRequires: pyparsing
BuildRequires: python-six BuildRequires: opus-devel
BuildRequires: gnupg2 BuildRequires: git
BuildRequires: git-core BuildRequires: autoconf automake libtool


%description %description
The Simple Protocol for Independent Computing Environments (SPICE) is The Simple Protocol for Independent Computing Environments (SPICE) is
@ -52,6 +75,7 @@ Summary: Header files, libraries and development documentation for spice-
Group: Development/Libraries Group: Development/Libraries
Requires: %{name}-server%{?_isa} = %{version}-%{release} Requires: %{name}-server%{?_isa} = %{version}-%{release}
Requires: pkgconfig Requires: pkgconfig
Requires: spice-protocol >= 0.12.3


%description server-devel %description server-devel
This package contains the header files, static libraries and development This package contains the header files, static libraries and development
@ -60,13 +84,12 @@ using spice-server, you will need to install spice-server-devel.




%prep %prep
gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0}
%autosetup -S git_am %autosetup -S git_am




%build %build
%define configure_client --disable-client autoreconf -fi
%configure --enable-smartcard --disable-client --enable-lz4 --enable-gstreamer=1.0 %configure --enable-smartcard --disable-client
make %{?_smp_mflags} WARN_CFLAGS='' V=1 make %{?_smp_mflags} WARN_CFLAGS='' V=1




@ -82,9 +105,7 @@ mkdir -p %{buildroot}%{_libexecdir}




%files server %files server
%{!?_licensedir:%global license %%doc} %doc COPYING README NEWS
%license COPYING
%doc README NEWS
%{_libdir}/libspice-server.so.1* %{_libdir}/libspice-server.so.1*


%files server-devel %files server-devel
@ -94,87 +115,165 @@ mkdir -p %{buildroot}%{_libexecdir}




%changelog %changelog
* Wed Oct 11 2017 Christophe Fergeau <cfergeau@redhat.com> - 0.14.0-1 * Thu Oct 12 2017 Christophe Fergeau <cfergeau@redhat.com> - 0.14.0-2
- Update to new stable release - Add streaming patches for use with spice-streaming-agent

Related: rhbz#1478356
* Tue Sep 26 2017 Christophe Fergeau <christophe@redhat.com> - 0.13.91-1
- Update to latest upstream release


* Thu Aug 24 2017 Christophe Fergeau <cfergeau@redhat.com> - 0.13.90-3 * Wed Oct 11 2017 Christophe Fergeau <cfergeau@redhat.com> - 0.14.0-1
- Add missing (new) BuildRequires, remove obsolete one - Rebase to 0.14.0 release
Resolves: rhbz#1472948


* Thu Aug 03 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.13.90-2 * Fri Sep 22 2017 Christophe Fergeau <cfergeau@redhat.com> 0.13.90-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild - Add lz4-devel BuildRequires
Resolves: rhbz#1460191


* Wed Jul 26 2017 Christophe Fergeau <cfergeau@redhat.com> 0.13.90-1 * Wed Jul 26 2017 Christophe Fergeau <cfergeau@redhat.com> 0.13.90-1
- Update to latest upstream release (0.13.90) - Rebase to latest upstream release

Resolves: rhbz#1472948
* Mon Feb 06 2017 Christophe Fergeau <cfergeau@redhat.com> 0.13.3-2
- Add upstream patches fixing CVE-2016-9577 and CVE-2016-9578 * Fri Jul 14 2017 Jonathon Jongsma <jjongsma@redhat.com> - 0.12.8-4

- build with opus support
* Mon Nov 21 2016 Christophe Fergeau <cfergeau@redhat.com> 0.13.3-1 Resolves: rhbz#1456832
- Update to spice 0.13.3

* Fri Jun 30 2017 Christophe Fergeau <cfergeau@redhat.com> 0.12.8-3
* Fri Aug 05 2016 Christophe Fergeau <cfergeau@redhat.com> - 0.13.2-1 - Prevent potential buffer/integer overflows with invalid MonitorsConfig messages
- Update to spice 0.13.2 sent from an authenticated client

Resolves: CVE-2017-7506
* Tue Jun 14 2016 Peter Robinson <pbrobinson@fedoraproject.org> 0.13.1-2
- Use %%license * Tue Apr 25 2017 Christophe Fergeau <cfergeau@redhat.com> 0.12.8-2
- Build on aarch64 - Drop clients immediatly if the magic they send is wrong

Resolves: rhbz#1416692
* Wed Apr 13 2016 Christophe Fergeau <cfergeau@redhat.com> 0.13.1-1
- Update to 0.13.1 release. This is a development release, but by the * Mon Jan 16 2017 Christophe Fergeau <cfergeau@redhat.com> 0.12.8-1
time Fedora 25 gets released, a stable 0.14.0 should be released. - Rebase to spice-server 0.12.8

Resolves: rhbz#1388947
* Fri Feb 05 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.12.6-2 Resolves: rhbz#1377551
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild Resolves: rhbz#1283202

* Fri Dec 09 2016 Frediano Ziglio <fziglio@redhat.com> - 0.12.4-20
* Tue Oct 06 2015 Christophe Fergeau <cfergeau@redhat.com> 0.12.6-1 - Fix buffer overflow in main_channel_alloc_msg_rcv_buf when reading large
- Update to new 0.12.6 upstream release messages.

Resolves: CVE-2016-9577
* Wed Jul 29 2015 Christophe Fergeau <cfergeau@redhat.com> 0.12.5-9 - Fix remote DoS via crafted message.
- Drop patch added in previous build which is no longer needed with Resolves: CVE-2016-9578
spice-protocol 0.12.9 (and actually is actually breaking QEMU compilation * Fri Sep 09 2016 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-19
without an additional patch) - Ensure SPICE_MIGRATE_COMPLETED is sent in all cases when it's needed.

Resolves: rhbz#1352836
* Fri Jul 03 2015 Christophe Fergeau <cfergeau@redhat.com> 0.12.5-8 * Fri Jul 01 2016 Christophe Fergeau <cfergeau@redhat.com> - 0.12.4-18
- Add upstream patch avoiding a regression in spice-protocol 0.12.8 which - Fix crash when connecting to VM using smartcard passthrough
breaks SPICE support in QEMU Resolves: rhbz#1340899

- Fix hang after unredirecting a USB device
* Thu Jul 02 2015 Christophe Fergeau <cfergeau@redhat.com> 0.12.5-7 Resolves: rhbz#1338752
- Fix migration race condition which causes a crash when triggered - Backport spice_qxl_set_max_monitors()
Resolves: rhbz#1238212 Resolves: rhbz#1283202

* Wed Apr 27 2016 Christophe Fergeau <cfergeau@redhat.com> - 0.12.4-17
* Fri Jun 19 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.12.5-6 - Fix crash when the client sends a wrong header (for example when using spice-html5)
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild Resolves: rhbz#1281442

- Fix crash when guest provides wrong address
* Mon Aug 25 2014 Christophe Fergeau <cfergeau@redhat.com> 0.12.5-5 Resolves: rhbz#1264356
- Fix advertised sound playback/recording rates in public headers - Fix thread-safety issue causing a crash when playing a Youtube video spanning
Resolves: rhbz#1129961 (QEMU would need a rebuild though) multiple monitors

Resolves: rhbz#1253375
* Mon Aug 18 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.12.5-4 - Add patches reducing QEMU wake-ups
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild Related: rhbz#912763, rhbz#1186146

- Fix use-after-free after resetting a VM
* Sun Jun 08 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.12.5-3 Resolves: rhbz#1281455
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild - Send KeepAlive probes every 10 minutes

Resolves: rhbz#1298590
* Mon May 19 2014 Christophe Fergeau <cfergeau@redhat.com> 0.12.5-2 - Add client to guest volume synchronization
- Add missing BuildRequires in order to enable Opus support Resolves: rhbz#1264107


* Mon May 19 2014 Christophe Fergeau <cfergeau@redhat.com> 0.12.5-1 * Mon Apr 25 2016 Christophe Fergeau <cfergeau@redhat.com> - 0.12.4-16
- Update to new 0.12.5 release - Use autosetup

Related: CVE-2016-0749
* Wed Oct 30 2013 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-3 - Fix heap-based memory corruption within smartcard handling
- Add patch fixing CVE-2013-4282 Resolves: CVE-2016-0749
- Fix host memory access from guest with invalid primary surface parameters
Resolves: CVE-2016-2150

* Wed Sep 23 2015 Frediano Ziglio <fziglio@redhat.com> 0.12.4-15
- CVE-2015-5260 CVE-2015-5261 fixed various security flaws
Resolves: rhbz#1267134

* Thu Sep 10 2015 Frediano Ziglio <fziglio@redhat.com> 0.12.4-14
- Validate surface_id
Resolves: rhbz#1260971

* Tue Jul 21 2015 Frediano Ziglio <fziglio@redhat.com> 0.12.4-13
- Clean stale statistics file before creating a new one
Resolves: rhbz#1177326

* Fri Jul 10 2015 Fabiano Fidêncio <fidencio@redhat.com> 0.12.4-12
- Fix a backport issue on Patch0040.
Related: rhbz#1071176
Resolves: rhbz#1241860

* Thu Jul 09 2015 Fabiano Fidêncio <fidencio@redhat.com> 0.12.4-11
- Don't assert on invalid client message
Resolves: rhbz#1227410
- Don't truncate large 'now' values in _spice_timer_set
Resolves: rhbz#1227408
- Avoid race conditions reading monitor configs from guest
Resolves: rhbz#1239128
- Lock the pixmap image cache for the entire fill_bits call
Resolves: rhbz#1235443

* Wed Jul 08 2015 Fabiano Fidêncio <fidencio@redhat.com> 0.12.4-10
- Fix qemu segmentation fault (core dumped) when boot KVM guest with
spice in FIPS enabled mode.
Resolves: rhbz#1071176

* Mon Jan 05 2015 Marc-Andre Lureau <marcandre.lureau@redhat.com> 0.12.4-9
- Allow recent TLS/SSL methods, block SSLv2/SSLv3. Resolves: rhbz#1175540

* Tue Oct 21 2014 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-8
- Fix defects reported by Coverity
Resolves: rhbz#885717
- Validate surface bounding box sent from QXL driver
Resolves: rhbz#1052856
- Fix assertion sometimes happening during migration while a client is
connected
Resolves: rhbz#1035184
- Fix crash when restarting VM with old client
Resolves: rhbz#1145919

* Thu Sep 18 2014 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-7
- Fix assert in mjpeg_encoder_adjust_params_to_bit_rate()
Resolves: rhbz#1086823
- Fix "Spice-ERROR **: reds.c:1464:reds_send_link_ack: assertion
`link->link_mess->channel_type == SPICE_CHANNEL_MAIN' failed" assertion
Resolves: rhbz#1058625
- Lower a monitor-config warning to debug level
Resolves: rhbz#1119220
- mjpeg: Don't warn on unsupported image formats
Resolves: rhbz#1070028

* Thu Aug 07 2014 Marc-Andre Lureau <marcandre.lureau@redhat.com> 0.12.4-6
- Fix invalid surface clearing
Resolves: rhbz#1029646

* Wed Jan 29 2014 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-5
- Fix qemu crash during migration with reboot
Resolves: rhbz#1016795
- Monitor whether the client is alive
Resolves: rhbz#1016790

* Tue Oct 15 2013 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-3
- Fix spice-server crash when client sends a password which is too long
Resolves: CVE-2013-4282


* Fri Sep 13 2013 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-2 * Fri Sep 13 2013 Christophe Fergeau <cfergeau@redhat.com> 0.12.4-2
- Add upstream patch fixing rhbz#995041 - Add upstream patch fixing rhbz#995041


* Fri Aug 2 2013 Hans de Goede <hdegoede@redhat.com> - 0.12.4-1 * Fri Aug 2 2013 Hans de Goede <hdegoede@redhat.com> - 0.12.4-1
- New upstream bug-fix release 0.12.4
- Add patches from upstream git to fix sound-channel-free crash (rhbz#986407) - Add patches from upstream git to fix sound-channel-free crash (rhbz#986407)
- Add Obsoletes for dropped spice-client sub-package - Add Obsoletes for dropped spice-client sub-package


* Mon Jul 22 2013 Yonit Halperin <yhalperi@redhat.com> 0.12.4-1
- New upstream release 0.12.4
- Require libjpeg-turbo-devel instead of libjpeg-devel
- Remove "BuildRequires: spice-protocol" from spice-server
- Add "Requires: spice-protocol" to spice-server-devel.

* Thu May 23 2013 Christophe Fergeau <cfergeau@redhat.com> 0.12.3-2 * Thu May 23 2013 Christophe Fergeau <cfergeau@redhat.com> 0.12.3-2
- Stop building spicec, it's obsolete and superseded by remote-viewer - Stop building spicec, it's obsolete and superseded by remote-viewer
(part of virt-viewer) (part of virt-viewer)

Loading…
Cancel
Save