[Spice-devel] [RFC PATCH 03/15] stream-device: Start parsing new protocol from guest

Frediano Ziglio fziglio at redhat.com
Wed Apr 19 15:31:02 UTC 2017


Parse the data sent from the guest to the streaming device.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 server/stream-device.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 110 insertions(+), 5 deletions(-)

diff --git a/server/stream-device.c b/server/stream-device.c
index 755e8b4..963bb95 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 STREAM_TYPE_DEVICE stream_device_get_type()
@@ -39,6 +41,9 @@ typedef struct StreamDeviceClass StreamDeviceClass;
 
 struct StreamDevice {
     RedCharDevice parent;
+    StreamDevHeader hdr;
+    uint8_t hdr_pos;
+    bool has_error;
 };
 
 struct StreamDeviceClass {
@@ -50,24 +55,124 @@ static StreamDevice *stream_device_new(SpiceCharDeviceInstance *sin, RedsState *
 
 G_DEFINE_TYPE(StreamDevice, stream_device, RED_TYPE_CHAR_DEVICE)
 
+typedef void StreamMsgHandler(StreamDevice *dev, SpiceCharDeviceInstance *sin);
+
+static StreamMsgHandler handle_msg_format, handle_msg_data, handle_msg_invalid;
+
 static RedPipeItem *
 stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *sin)
 {
+    StreamDevice *dev = STREAM_DEVICE(self);
     SpiceCharDeviceInterface *sif;
     int n;
 
+    if (dev->has_error) {
+        return NULL;
+    }
+
     sif = spice_char_device_get_interface(sin);
 
-    do {
-        uint8_t buf[256];
-        n = sif->read(sin, buf, sizeof(buf));
-        spice_debug("readed %d bytes from device", n);
-    } while (n > 0);
+    /* 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 ((StreamDevType) dev->hdr.type) {
+    case STREAM_TYPE_FORMAT:
+        if (dev->hdr.size != sizeof(StreamMsgFormat)) {
+            handle_msg_invalid(dev, sin);
+        } else {
+            handle_msg_format(dev, sin);
+        }
+        break;
+    case STREAM_TYPE_DATA:
+        handle_msg_data(dev, sin);
+        break;
+    case STREAM_TYPE_CAPABILITIES:
+        /* FIXME */
+    default:
+        handle_msg_invalid(dev, sin);
+        break;
+    }
 
     return NULL;
 }
 
 static void
+handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin)
+{
+    static const char error_msg[] = "Wrong protocol";
+
+    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;
+}
+
+static void
+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;
+    }
+    if (n != sizeof(fmt)) {
+        handle_msg_invalid(dev, sin);
+        return;
+    }
+    fmt.width = GUINT32_FROM_LE(fmt.width);
+    fmt.height = GUINT32_FROM_LE(fmt.height);
+    dev->hdr_pos = 0;
+}
+
+static void
+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("readed %d bytes from device", n);
+        if (n <= 0) {
+            break;
+        }
+        dev->hdr.size -= n;
+    }
+    if (dev->hdr.size == 0) {
+        dev->hdr_pos = 0;
+    }
+}
+
+static void
 stream_device_send_msg_to_client(RedCharDevice *self, RedPipeItem *msg, RedClient *client)
 {
 }
-- 
2.9.3



More information about the Spice-devel mailing list