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

7bbc9c
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
7bbc9c
From: Frediano Ziglio <fziglio@redhat.com>
7bbc9c
Date: Fri, 13 Jan 2017 18:20:43 +0000
7bbc9c
Subject: [spice-server] stream-device: Start parsing new protocol from guest
7bbc9c
7bbc9c
Parse the data sent from the guest to the streaming device.
7bbc9c
At the moment, the data is simply discarded after it is parsed.
7bbc9c
7bbc9c
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
7bbc9c
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
7bbc9c
---
7bbc9c
 server/stream-device.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++--
7bbc9c
 1 file changed, 124 insertions(+), 4 deletions(-)
7bbc9c
7bbc9c
diff --git a/server/stream-device.c b/server/stream-device.c
7bbc9c
index f3a147b80..58edb3d11 100644
7bbc9c
--- a/server/stream-device.c
7bbc9c
+++ b/server/stream-device.c
7bbc9c
@@ -19,6 +19,8 @@
7bbc9c
 #include <config.h>
7bbc9c
 #endif
7bbc9c
 
7bbc9c
+#include <spice/stream-device.h>
7bbc9c
+
7bbc9c
 #include "char-device.h"
7bbc9c
 
7bbc9c
 #define TYPE_STREAM_DEVICE stream_device_get_type()
7bbc9c
@@ -35,6 +37,9 @@ typedef struct StreamDeviceClass StreamDeviceClass;
7bbc9c
 
7bbc9c
 struct StreamDevice {
7bbc9c
     RedCharDevice parent;
7bbc9c
+    StreamDevHeader hdr;
7bbc9c
+    uint8_t hdr_pos;
7bbc9c
+    bool has_error;
7bbc9c
 };
7bbc9c
 
7bbc9c
 struct StreamDeviceClass {
7bbc9c
@@ -46,21 +51,136 @@ static StreamDevice *stream_device_new(SpiceCharDeviceInstance *sin, RedsState *
7bbc9c
 
7bbc9c
 G_DEFINE_TYPE(StreamDevice, stream_device, RED_TYPE_CHAR_DEVICE)
7bbc9c
 
7bbc9c
+typedef bool StreamMsgHandler(StreamDevice *dev, SpiceCharDeviceInstance *sin)
7bbc9c
+    SPICE_GNUC_WARN_UNUSED_RESULT;
7bbc9c
+
7bbc9c
+static StreamMsgHandler handle_msg_format, handle_msg_data;
7bbc9c
+
7bbc9c
+static bool handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin,
7bbc9c
+                               const char *error_msg) SPICE_GNUC_WARN_UNUSED_RESULT;
7bbc9c
+
7bbc9c
 static RedPipeItem *
7bbc9c
 stream_device_read_msg_from_dev(RedCharDevice *self, SpiceCharDeviceInstance *sin)
7bbc9c
 {
7bbc9c
+    StreamDevice *dev = STREAM_DEVICE(self);
7bbc9c
     SpiceCharDeviceInterface *sif;
7bbc9c
     int n;
7bbc9c
+    bool handled = false;
7bbc9c
+
7bbc9c
+    if (dev->has_error) {
7bbc9c
+        return NULL;
7bbc9c
+    }
7bbc9c
 
7bbc9c
     sif = spice_char_device_get_interface(sin);
7bbc9c
 
7bbc9c
-    do {
7bbc9c
-        uint8_t buf[256];
7bbc9c
+    /* read header */
7bbc9c
+    while (dev->hdr_pos < sizeof(dev->hdr)) {
7bbc9c
+        n = sif->read(sin, (uint8_t *) &dev->hdr, sizeof(dev->hdr) - dev->hdr_pos);
7bbc9c
+        if (n <= 0) {
7bbc9c
+            return NULL;
7bbc9c
+        }
7bbc9c
+        dev->hdr_pos += n;
7bbc9c
+        if (dev->hdr_pos >= sizeof(dev->hdr)) {
7bbc9c
+            dev->hdr.type = GUINT16_FROM_LE(dev->hdr.type);
7bbc9c
+            dev->hdr.size = GUINT32_FROM_LE(dev->hdr.size);
7bbc9c
+        }
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    switch ((StreamMsgType) dev->hdr.type) {
7bbc9c
+    case STREAM_TYPE_FORMAT:
7bbc9c
+        if (dev->hdr.size != sizeof(StreamMsgFormat)) {
7bbc9c
+            handled = handle_msg_invalid(dev, sin, "Wrong size for StreamMsgFormat");
7bbc9c
+        } else {
7bbc9c
+            handled = handle_msg_format(dev, sin);
7bbc9c
+        }
7bbc9c
+        break;
7bbc9c
+    case STREAM_TYPE_DATA:
7bbc9c
+        handled = handle_msg_data(dev, sin);
7bbc9c
+        break;
7bbc9c
+    case STREAM_TYPE_CAPABILITIES:
7bbc9c
+        /* FIXME */
7bbc9c
+    default:
7bbc9c
+        handled = handle_msg_invalid(dev, sin, "Invalid message type");
7bbc9c
+        break;
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    /* current message has been handled, so reset state and get ready to parse
7bbc9c
+     * the next message */
7bbc9c
+    if (handled) {
7bbc9c
+        dev->hdr_pos = 0;
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    return NULL;
7bbc9c
+}
7bbc9c
+
7bbc9c
+static bool
7bbc9c
+handle_msg_invalid(StreamDevice *dev, SpiceCharDeviceInstance *sin, const char *error_msg)
7bbc9c
+{
7bbc9c
+    static const char default_error_msg[] = "Protocol error";
7bbc9c
+
7bbc9c
+    if (!error_msg) {
7bbc9c
+        error_msg = default_error_msg;
7bbc9c
+    }
7bbc9c
+
7bbc9c
+    int msg_size = sizeof(StreamMsgNotifyError) + strlen(error_msg) + 1;
7bbc9c
+    int total_size = sizeof(StreamDevHeader) + msg_size;
7bbc9c
+
7bbc9c
+    RedCharDevice *char_dev = RED_CHAR_DEVICE(dev);
7bbc9c
+    RedCharDeviceWriteBuffer *buf =
7bbc9c
+        red_char_device_write_buffer_get_server_no_token(char_dev, total_size);
7bbc9c
+    buf->buf_used = total_size;
7bbc9c
+
7bbc9c
+    StreamDevHeader *const hdr = (StreamDevHeader *)buf->buf;
7bbc9c
+    hdr->protocol_version = STREAM_DEVICE_PROTOCOL;
7bbc9c
+    hdr->padding = 0;
7bbc9c
+    hdr->type = GUINT16_TO_LE(STREAM_TYPE_NOTIFY_ERROR);
7bbc9c
+    hdr->size = GUINT32_TO_LE(msg_size);
7bbc9c
+
7bbc9c
+    StreamMsgNotifyError *const error = (StreamMsgNotifyError *)(hdr+1);
7bbc9c
+    error->error_code = GUINT32_TO_LE(0);
7bbc9c
+    strcpy((char *) error->msg, error_msg);
7bbc9c
+
7bbc9c
+    red_char_device_write_buffer_add(char_dev, buf);
7bbc9c
+
7bbc9c
+    dev->has_error = true;
7bbc9c
+    return false;
7bbc9c
+}
7bbc9c
+
7bbc9c
+static bool
7bbc9c
+handle_msg_format(StreamDevice *dev, SpiceCharDeviceInstance *sin)
7bbc9c
+{
7bbc9c
+    StreamMsgFormat fmt;
7bbc9c
+    SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
7bbc9c
+    int n = sif->read(sin, (uint8_t *) &fmt, sizeof(fmt));
7bbc9c
+    if (n == 0) {
7bbc9c
+        return false;
7bbc9c
+    }
7bbc9c
+    if (n != sizeof(fmt)) {
7bbc9c
+        return handle_msg_invalid(dev, sin, NULL);
7bbc9c
+    }
7bbc9c
+    fmt.width = GUINT32_FROM_LE(fmt.width);
7bbc9c
+    fmt.height = GUINT32_FROM_LE(fmt.height);
7bbc9c
+
7bbc9c
+    return true;
7bbc9c
+}
7bbc9c
+
7bbc9c
+static bool
7bbc9c
+handle_msg_data(StreamDevice *dev, SpiceCharDeviceInstance *sin)
7bbc9c
+{
7bbc9c
+    SpiceCharDeviceInterface *sif = spice_char_device_get_interface(sin);
7bbc9c
+    int n;
7bbc9c
+    while (1) {
7bbc9c
+        uint8_t buf[16 * 1024];
7bbc9c
         n = sif->read(sin, buf, sizeof(buf));
7bbc9c
+        /* TODO */
7bbc9c
         spice_debug("read %d bytes from device", n);
7bbc9c
-    } while (n > 0);
7bbc9c
+        if (n <= 0) {
7bbc9c
+            break;
7bbc9c
+        }
7bbc9c
+        dev->hdr.size -= n;
7bbc9c
+    }
7bbc9c
 
7bbc9c
-    return NULL;
7bbc9c
+    return dev->hdr.size == 0;
7bbc9c
 }
7bbc9c
 
7bbc9c
 static void