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 <fzig...@redhat.com>
---
 server/stream-channel.c | 26 +++++++++++++++++++++++-
 server/stream-channel.h |  5 ++++-
 server/stream-device.c  | 48 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 79 insertions(+)

diff --git a/server/stream-channel.c b/server/stream-channel.c
index d7ce93c..574539a 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -494,3 +494,29 @@ stream_channel_register_start_cb(StreamChannel *channel,
     channel->start_cb = cb;
     channel->start_opaque = opaque;
 }
+
+void
+stream_channel_reset(StreamChannel *channel)
+{
+    RedChannel *red_channel = RED_CHANNEL(channel);
+
+    // send destroy old stream
+    red_channel_pipes_add_type(red_channel, RED_PIPE_ITEM_TYPE_STREAM_DESTROY);
+
+    // send new create surface if required
+    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;
+
+    // try to ask new stream, this should start a new stream
+    // if the guest connect to the device and a client is already connected
+    StreamMsgStart* start = stream_channel_get_supported_codecs(channel);
+    // send in any case, even if list is not changed
+    // notify device about changes
+    ask_new_stream(channel, start);
+    free(start);
+}
diff --git a/server/stream-channel.h b/server/stream-channel.h
index db2c8a9..a8cc0df 100644
--- a/server/stream-channel.h
+++ b/server/stream-channel.h
@@ -47,6 +47,11 @@ GType stream_channel_get_type(void) G_GNUC_CONST;
  */
 StreamChannel* stream_channel_new(RedsState *server);
 
+/**
+ * Reset channel at initial state
+ */
+void stream_channel_reset(StreamChannel *channel);
+
 struct StreamMsgStreamFormat;
 struct StreamMsgStart;
 
diff --git a/server/stream-device.c b/server/stream-device.c
index da71880..f59f496 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -46,6 +46,7 @@ struct StreamDevice {
 
     StreamDevHeader hdr;
     uint8_t hdr_pos;
+    gboolean opened;
     StreamChannel *channel;
 };
 
@@ -161,6 +162,35 @@ stream_device_remove_client(RedCharDevice *self, RedClient 
*client)
 {
 }
 
+static void
+stream_device_stream_start(void *opaque, struct StreamMsgStart *start,
+                           StreamChannel *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_STREAM_START);
+    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)
 {
@@ -170,6 +200,7 @@ stream_device_connect(RedsState *reds, 
SpiceCharDeviceInstance *sin)
 
     StreamDevice *dev = stream_device_new(sin, reds);
     dev->channel = channel;
+    stream_channel_register_start_cb(channel, stream_device_stream_start, dev);
 
     sif = spice_char_device_get_interface(sin);
     if (sif->state) {
@@ -198,6 +229,22 @@ 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 *device = STREAM_DEVICE(char_dev);
+
+    // reset device and channel on close/open
+    device->opened = (event == SPICE_PORT_EVENT_OPENED);
+    device->hdr_pos = 0;
+    red_char_device_reset(char_dev);
+    stream_channel_reset(device->channel);
+}
+
+static void
 stream_device_class_init(StreamDeviceClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS(klass);
@@ -209,6 +256,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
-- 
git-series 0.9.1
_______________________________________________
Spice-devel mailing list
Spice-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/spice-devel

Reply via email to