[Spice-devel] [RFC PATCH spice-server v3 14/20] stream-device: Start supporting resetting device when close/open on guest
Frediano Ziglio
fziglio at redhat.com
Wed Aug 23 09:14:32 UTC 2017
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 at redhat.com>
---
server/stream-channel.c | 30 ++++++++++++++++++++++++++++++
server/stream-channel.h | 7 ++++++-
server/stream-device.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 85 insertions(+), 1 deletion(-)
diff --git a/server/stream-channel.c b/server/stream-channel.c
index b9bb2649..d355887a 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -480,3 +480,33 @@ 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);
+
+ // 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 ask new stream, this should start a new stream
+ // if the guest connect to the device and a client is already connected
+ StreamMsgStartStop* start = stream_channel_get_supported_codecs(channel);
+ // send in any case, even if list is not changed
+ // notify device about changes
+ request_new_stream(channel, start);
+ free(start);
+}
diff --git a/server/stream-channel.h b/server/stream-channel.h
index 37b9e327..5d182205 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);
-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 c1dd02d4..3836cff8 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 *channel;
};
@@ -188,6 +189,35 @@ stream_device_remove_client(RedCharDevice *self, RedClient *client)
{
}
+static void
+stream_device_stream_start(void *opaque, StreamMsgStartStop *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_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)
{
@@ -197,6 +227,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) {
@@ -225,6 +256,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 *device = STREAM_DEVICE(char_dev);
+
+ // reset device and channel on close/open
+ device->opened = (event == SPICE_PORT_EVENT_OPENED);
+ device->hdr_pos = 0;
+ device->has_error = false;
+ 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);
@@ -236,6 +284,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
--
2.13.5
More information about the Spice-devel
mailing list