[Spice-devel] [PATCH spice-server 2/2] stream-device: Handle capabilities
Frediano Ziglio
fziglio at redhat.com
Wed Mar 7 12:30:05 UTC 2018
Handle capabilities from guest device.
Send capability to the guest when device is opened.
Currently there's no capabilities set on the message sent.
On the tests we need to discard the capability message before
reading the error.
Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
server/stream-device.c | 63 +++++++++++++++++++++++++++++++++++++--
server/tests/test-stream-device.c | 22 ++++++++++++++
2 files changed, 82 insertions(+), 3 deletions(-)
diff --git a/server/stream-device.c b/server/stream-device.c
index dc58dce6..0656ff0e 100644
--- a/server/stream-device.c
+++ b/server/stream-device.c
@@ -1,6 +1,6 @@
/* spice-server character device to handle a video stream
- Copyright (C) 2017 Red Hat, Inc.
+ Copyright (C) 2017-2018 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
@@ -38,6 +38,8 @@
typedef struct StreamDevice StreamDevice;
typedef struct StreamDeviceClass StreamDeviceClass;
+#define MAX_GUEST_CAPABILITIES_BYTES ((STREAM_CAP_END+7)/8)
+
struct StreamDevice {
RedCharDevice parent;
@@ -55,6 +57,7 @@ struct StreamDevice {
bool has_error;
bool opened;
bool flow_stopped;
+ uint8_t guest_capabilities[MAX_GUEST_CAPABILITIES_BYTES];
StreamChannel *stream_channel;
CursorChannel *cursor_channel;
SpiceTimer *close_timer;
@@ -75,7 +78,7 @@ typedef bool StreamMsgHandler(StreamDevice *dev, SpiceCharDeviceInstance *sin)
SPICE_GNUC_WARN_UNUSED_RESULT;
static StreamMsgHandler handle_msg_format, handle_msg_data, handle_msg_cursor_set,
- handle_msg_cursor_move;
+ handle_msg_cursor_move, handle_msg_capabilities;
static bool handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin,
const char *error_msg) SPICE_GNUC_WARN_UNUSED_RESULT;
@@ -161,7 +164,8 @@ stream_device_partial_read(StreamDevice *dev, SpiceCharDeviceInstance *sin)
}
break;
case STREAM_TYPE_CAPABILITIES:
- /* FIXME */
+ handled = handle_msg_capabilities(dev, sin);
+ break;
default:
handled = handle_msg_invalid(dev, sin, "Invalid message type");
break;
@@ -268,6 +272,38 @@ handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin)
return true;
}
+static bool
+handle_msg_capabilities(StreamDevice *dev, SpiceCharDeviceInstance *sin)
+{
+ SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
+
+ if (ENABLE_EXTRA_CHECKS) {
+ spice_assert(dev->hdr_pos >= sizeof(StreamDevHeader));
+ spice_assert(dev->hdr.type == STREAM_TYPE_CAPABILITIES);
+ }
+
+ if (dev->hdr.size > STREAM_MSG_CAPABILITIES_MAX_BYTES) {
+ return handle_msg_invalid(dev, sin, "Wrong size for StreamMsgCapabilities");
+ }
+
+ int n = sif->read(sin, dev->msg->buf + dev->msg_pos, dev->hdr.size - dev->msg_pos);
+ if (n < 0) {
+ return handle_msg_invalid(dev, sin, NULL);
+ }
+
+ dev->msg_pos += n;
+
+ if (dev->msg_pos < dev->hdr.size) {
+ return false;
+ }
+
+ // copy only capabilities we care about
+ memset(dev->guest_capabilities, 0, sizeof(dev->guest_capabilities));
+ memcpy(dev->guest_capabilities, dev->msg->buf, MIN(MAX_GUEST_CAPABILITIES_BYTES, dev->hdr.size));
+
+ return true;
+}
+
static bool
handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
{
@@ -600,6 +636,25 @@ char_device_set_state(RedCharDevice *char_dev, int state)
}
}
+static void
+send_capabilities(RedCharDevice *char_dev)
+{
+ int msg_size = MAX_GUEST_CAPABILITIES_BYTES;
+ int total_size = sizeof(StreamDevHeader) + msg_size;
+
+ 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_CAPABILITIES);
+ hdr->size = GUINT32_TO_LE(msg_size);
+
+ red_char_device_write_buffer_add(char_dev, buf);
+}
+
static void
stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
{
@@ -613,6 +668,8 @@ stream_device_port_event(RedCharDevice *char_dev, uint8_t event)
dev->opened = (event == SPICE_PORT_EVENT_OPENED);
if (dev->opened) {
allocate_channels(dev);
+
+ send_capabilities(char_dev);
}
dev->hdr_pos = 0;
dev->msg_pos = 0;
diff --git a/server/tests/test-stream-device.c b/server/tests/test-stream-device.c
index 3c9209a4..43011f9d 100644
--- a/server/tests/test-stream-device.c
+++ b/server/tests/test-stream-device.c
@@ -135,12 +135,33 @@ static uint8_t *add_format(uint8_t *p, uint32_t w, uint32_t h, SpiceVideoCodecTy
return p + sizeof(fmt);
}
+// remove capabilities from server reply
+static void
+consume_server_capabilities(void)
+{
+ StreamDevHeader hdr;
+
+ if (vmc_write_pos == 0) {
+ return;
+ }
+ g_assert(vmc_write_pos >= sizeof(hdr));
+
+ memcpy(&hdr, vmc_write_buf, sizeof(hdr));
+ if (GUINT16_FROM_LE(hdr.type) == STREAM_TYPE_CAPABILITIES) {
+ g_assert_cmpint(GUINT32_FROM_LE(hdr.size), <=, vmc_write_pos - sizeof(hdr));
+ vmc_write_pos -= GUINT32_FROM_LE(hdr.size) + sizeof(hdr);
+ memmove(vmc_write_buf, vmc_write_buf + GUINT32_FROM_LE(hdr.size) + sizeof(hdr), vmc_write_pos);
+ }
+}
+
// check we have an error message on the write buffer
static void
check_vmc_error_message(void)
{
StreamDevHeader hdr;
+ consume_server_capabilities();
+
g_assert(vmc_write_pos >= sizeof(hdr));
memcpy(&hdr, vmc_write_buf, sizeof(hdr));
@@ -245,6 +266,7 @@ static void test_stream_device_unfinished(void)
g_assert(message_sizes_curr - message_sizes == 1);
// we should have no data from the device
+ consume_server_capabilities();
g_assert_cmpint(vmc_write_pos, ==, 0);
test_destroy(test);
--
2.14.3
More information about the Spice-devel
mailing list