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

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