[Spice-commits] 6 commits - configure.ac server/inputs_channel.c server/main_channel.c server/red_channel.c server/red_channel.h server/red_dispatcher.c server/red_dispatcher.h server/red_tunnel_worker.c server/red_worker.c server/smartcard.c server/snd_worker.c server/spicevmc.c spice.proto

Yonit Halperin yhalperi at kemper.freedesktop.org
Thu Jan 12 06:35:42 PST 2012


 configure.ac               |    2 
 server/inputs_channel.c    |   10 +
 server/main_channel.c      |    8 +
 server/red_channel.c       |  253 ++++++++++++++++++++++++++++++++++++++-------
 server/red_channel.h       |   82 +++++++++++---
 server/red_dispatcher.c    |   16 ++
 server/red_dispatcher.h    |    8 +
 server/red_tunnel_worker.c |   43 +++----
 server/red_worker.c        |  221 ++++++++++++++++++++++++++++++---------
 server/smartcard.c         |   18 +--
 server/snd_worker.c        |   93 ++++++++++------
 server/spicevmc.c          |   24 ++--
 spice.proto                |    1 
 13 files changed, 597 insertions(+), 182 deletions(-)

New commits:
commit 65c859ba819fdc70ebc3ba5208bb994d06174873
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Jan 8 09:20:55 2012 +0200

    server: add support for SPICE_COMMON_CAP_MINI_HEADER
    
    Support for a header without a serial and without sub list.
    red_channel: Support the two types of headers.
                 Keep a consistent consecutive messages serial.
    red_worker: use urgent marshaller instead of sub list.
    snd_worker: Sound channels need special support since they still don't use
                red_channel for sending & receiving.

diff --git a/server/red_channel.c b/server/red_channel.c
index 06b4ef0..e526179 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -40,6 +40,82 @@ static void red_client_add_channel(RedClient *client, RedChannelClient *rcc);
 static void red_client_remove_channel(RedChannelClient *rcc);
 static void red_channel_client_restore_main_sender(RedChannelClient *rcc);
 
+static uint32_t full_header_get_msg_size(SpiceDataHeaderOpaque *header)
+{
+    return ((SpiceDataHeader *)header->data)->size;
+}
+
+static uint32_t mini_header_get_msg_size(SpiceDataHeaderOpaque *header)
+{
+    return ((SpiceMiniDataHeader *)header->data)->size;
+}
+
+static uint16_t full_header_get_msg_type(SpiceDataHeaderOpaque *header)
+{
+    return ((SpiceDataHeader *)header->data)->type;
+}
+
+static uint16_t mini_header_get_msg_type(SpiceDataHeaderOpaque *header)
+{
+    return ((SpiceMiniDataHeader *)header->data)->type;
+}
+
+static void full_header_set_msg_type(SpiceDataHeaderOpaque *header, uint16_t type)
+{
+    ((SpiceDataHeader *)header->data)->type = type;
+}
+
+static void mini_header_set_msg_type(SpiceDataHeaderOpaque *header, uint16_t type)
+{
+    ((SpiceMiniDataHeader *)header->data)->type = type;
+}
+
+static void full_header_set_msg_size(SpiceDataHeaderOpaque *header, uint32_t size)
+{
+    ((SpiceDataHeader *)header->data)->size = size;
+}
+
+static void mini_header_set_msg_size(SpiceDataHeaderOpaque *header, uint32_t size)
+{
+    ((SpiceMiniDataHeader *)header->data)->size = size;
+}
+
+static void full_header_set_msg_serial(SpiceDataHeaderOpaque *header, uint64_t serial)
+{
+    ((SpiceDataHeader *)header->data)->serial = serial;
+}
+
+static void mini_header_set_msg_serial(SpiceDataHeaderOpaque *header, uint64_t serial)
+{
+    red_error("attempt to set header serial on mini header");
+}
+
+static void full_header_set_msg_sub_list(SpiceDataHeaderOpaque *header, uint32_t sub_list)
+{
+    ((SpiceDataHeader *)header->data)->sub_list = sub_list;
+}
+
+static void mini_header_set_msg_sub_list(SpiceDataHeaderOpaque *header, uint32_t sub_list)
+{
+    red_error("attempt to set header sub list on mini header");
+}
+
+static SpiceDataHeaderOpaque full_header_wrapper = {NULL, sizeof(SpiceDataHeader),
+                                                    full_header_set_msg_type,
+                                                    full_header_set_msg_size,
+                                                    full_header_set_msg_serial,
+                                                    full_header_set_msg_sub_list,
+                                                    full_header_get_msg_type,
+                                                    full_header_get_msg_size};
+
+static SpiceDataHeaderOpaque mini_header_wrapper = {NULL, sizeof(SpiceMiniDataHeader),
+                                                    mini_header_set_msg_type,
+                                                    mini_header_set_msg_size,
+                                                    mini_header_set_msg_serial,
+                                                    mini_header_set_msg_sub_list,
+                                                    mini_header_get_msg_type,
+                                                    mini_header_get_msg_size};
+
 /* return the number of bytes read. -1 in case of error */
 static int red_peer_receive(RedsStream *stream, uint8_t *buf, uint32_t size)
 {
@@ -83,29 +159,31 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
     uint8_t *parsed;
     size_t parsed_size;
     message_destructor_t parsed_free;
+    uint16_t msg_type;
+    uint32_t msg_size;
 
     for (;;) {
         int ret_handle;
-        if (handler->header_pos < sizeof(SpiceDataHeader)) {
+        if (handler->header_pos < handler->header.header_size) {
             bytes_read = red_peer_receive(stream,
-                                          ((uint8_t *)&handler->header) + handler->header_pos,
-                                          sizeof(SpiceDataHeader) - handler->header_pos);
+                                          handler->header.data + handler->header_pos,
+                                          handler->header.header_size - handler->header_pos);
             if (bytes_read == -1) {
                 handler->cb->on_error(handler->opaque);
                 return;
             }
             handler->header_pos += bytes_read;
 
-            if (handler->header_pos != sizeof(SpiceDataHeader)) {
+            if (handler->header_pos != handler->header.header_size) {
                 return;
             }
         }
 
-        if (handler->msg_pos < handler->header.size) {
+        msg_size = handler->header.get_msg_size(&handler->header);
+        msg_type = handler->header.get_msg_type(&handler->header);
+        if (handler->msg_pos < msg_size) {
             if (!handler->msg) {
-                handler->msg = handler->cb->alloc_msg_buf(handler->opaque,
-                                                          handler->header.type,
-                                                          handler->header.size);
+                handler->msg = handler->cb->alloc_msg_buf(handler->opaque, msg_type, msg_size);
                 if (handler->msg == NULL) {
                     red_printf("ERROR: channel refused to allocate buffer.");
                     handler->cb->on_error(handler->opaque);
@@ -115,47 +193,37 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
 
             bytes_read = red_peer_receive(stream,
                                           handler->msg + handler->msg_pos,
-                                          handler->header.size - handler->msg_pos);
+                                          msg_size - handler->msg_pos);
             if (bytes_read == -1) {
-                handler->cb->release_msg_buf(handler->opaque,
-                                             handler->header.type,
-                                             handler->header.size,
-                                             handler->msg);
+                handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
                 handler->cb->on_error(handler->opaque);
                 return;
             }
             handler->msg_pos += bytes_read;
-            if (handler->msg_pos != handler->header.size) {
+            if (handler->msg_pos != msg_size) {
                 return;
             }
         }
 
         if (handler->cb->parser) {
             parsed = handler->cb->parser(handler->msg,
-                handler->msg + handler->header.size, handler->header.type,
+                handler->msg + msg_size, msg_type,
                 SPICE_VERSION_MINOR, &parsed_size, &parsed_free);
             if (parsed == NULL) {
-                red_printf("failed to parse message type %d", handler->header.type);
-                handler->cb->release_msg_buf(handler->opaque, handler->header.type,
-                                             handler->header.size,
-                                             handler->msg);
+                red_printf("failed to parse message type %d", msg_type);
+                handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
                 handler->cb->on_error(handler->opaque);
                 return;
             }
             ret_handle = handler->cb->handle_parsed(handler->opaque, parsed_size,
-                                    handler->header.type, parsed);
+                                                    msg_type, parsed);
             parsed_free(parsed);
         } else {
-            ret_handle = handler->cb->handle_message(handler->opaque,
-                                                     handler->header.type,
-                                                     handler->header.size,
+            ret_handle = handler->cb->handle_message(handler->opaque, msg_type, msg_size,
                                                      handler->msg);
         }
         handler->msg_pos = 0;
-        handler->cb->release_msg_buf(handler->opaque,
-                                     handler->header.type,
-                                     handler->header.size,
-                                     handler->msg);
+        handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
         handler->msg = NULL;
         handler->header_pos = 0;
 
@@ -276,21 +344,32 @@ static inline int red_channel_client_urgent_marshaller_is_active(RedChannelClien
 static void red_channel_client_reset_send_data(RedChannelClient *rcc)
 {
     spice_marshaller_reset(rcc->send_data.marshaller);
-    rcc->send_data.header = (SpiceDataHeader *)
-        spice_marshaller_reserve_space(rcc->send_data.marshaller, sizeof(SpiceDataHeader));
-    spice_marshaller_set_base(rcc->send_data.marshaller, sizeof(SpiceDataHeader));
-    rcc->send_data.header->type = 0;
-    rcc->send_data.header->size = 0;
-    rcc->send_data.header->sub_list = 0;
-
-    if (!red_channel_client_urgent_marshaller_is_active(rcc)) {
-        rcc->send_data.header->serial = ++rcc->send_data.serial;
-    } else {
-        /*  The serial was incremented by the call to reset_send_data
-         *  that was done for the main marshaller. The urgent msg should
-         *  receive this serial, and the main msg serial should be
-         *  the following one. */
-        rcc->send_data.header->serial = rcc->send_data.serial++;
+    rcc->send_data.header.data = spice_marshaller_reserve_space(rcc->send_data.marshaller,
+                                                                rcc->send_data.header.header_size);
+    spice_marshaller_set_base(rcc->send_data.marshaller, rcc->send_data.header.header_size);
+    rcc->send_data.header.set_msg_type(&rcc->send_data.header, 0);
+    rcc->send_data.header.set_msg_size(&rcc->send_data.header, 0);
+
+    /* Keeping the serial consecutive: reseting it if reset_send_data
+     * has been called before, but no message has been sent since then.
+     */
+    if (rcc->send_data.last_sent_serial != rcc->send_data.serial) {
+        ASSERT(rcc->send_data.serial - rcc->send_data.last_sent_serial == 1);
+        /*  When the urgent marshaller is active, the serial was incremented by
+         *  the call to reset_send_data that was made for the main marshaller.
+         *  The urgent msg receives this serial, and the main msg serial is
+         *  the following one. Thus, (rcc->send_data.serial - rcc->send_data.last_sent_serial)
+         *  should be 1 in this case*/
+        if (!red_channel_client_urgent_marshaller_is_active(rcc)) {
+            rcc->send_data.serial = rcc->send_data.last_sent_serial;
+        }
+    }
+    rcc->send_data.serial++;
+
+    if (!rcc->is_mini_header) {
+        ASSERT(rcc->send_data.marshaller != rcc->send_data.urgent.marshaller);
+        rcc->send_data.header.set_msg_sub_list(&rcc->send_data.header, 0);
+        rcc->send_data.header.set_msg_serial(&rcc->send_data.header, rcc->send_data.serial);
     }
 }
 
@@ -376,7 +455,7 @@ static void red_channel_peer_on_out_msg_done(void *opaque)
 
     if (red_channel_client_urgent_marshaller_is_active(rcc)) {
         red_channel_client_restore_main_sender(rcc);
-        ASSERT(rcc->send_data.header != NULL);
+        ASSERT(rcc->send_data.header.data != NULL);
         red_channel_client_begin_send_message(rcc);
     }
 }
@@ -457,6 +536,18 @@ RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedCl
     rcc->outgoing.size = 0;
 
     red_channel_client_set_remote_caps(rcc, num_common_caps, common_caps, num_caps, caps);
+    if (red_channel_client_test_remote_common_cap(rcc, SPICE_COMMON_CAP_MINI_HEADER)) {
+        rcc->incoming.header = mini_header_wrapper;
+        rcc->send_data.header = mini_header_wrapper;
+        rcc->is_mini_header = TRUE;
+    } else {
+        rcc->incoming.header = full_header_wrapper;
+        rcc->send_data.header = full_header_wrapper;
+        rcc->is_mini_header = FALSE;
+    }
+
+    rcc->incoming.header.data = rcc->incoming.header_buf;
+    rcc->incoming.serial = 1;
 
     if (!channel->channel_cbs.config_socket(rcc)) {
         goto error;
@@ -545,6 +636,7 @@ RedChannel *red_channel_create(int size,
     client_cbs.migrate = red_channel_client_default_migrate;
 
     red_channel_register_client_cbs(channel, &client_cbs);
+    red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER);
 
     channel->thread_id = pthread_self();
 
@@ -590,6 +682,7 @@ RedChannel *red_channel_create_dummy(int size, uint32_t type, uint32_t id)
     client_cbs.migrate = red_channel_client_default_migrate;
 
     red_channel_register_client_cbs(channel, &client_cbs);
+    red_channel_set_common_cap(channel, SPICE_COMMON_CAP_MINI_HEADER);
 
     channel->thread_id = pthread_self();
 
@@ -850,7 +943,7 @@ static void red_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size
 }
 
 int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
-                               uint16_t type, void *message)
+                                      uint16_t type, void *message)
 {
     switch (type) {
     case SPICE_MSGC_ACK_SYNC:
@@ -897,7 +990,7 @@ void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type,
 {
     ASSERT(red_channel_client_no_item_being_sent(rcc));
     ASSERT(msg_type != 0);
-    rcc->send_data.header->type = msg_type;
+    rcc->send_data.header.set_msg_type(&rcc->send_data.header, msg_type);
     rcc->send_data.item = item;
     if (item) {
         rcc->channel->channel_cbs.hold_item(rcc, item);
@@ -909,23 +1002,25 @@ void red_channel_client_begin_send_message(RedChannelClient *rcc)
     SpiceMarshaller *m = rcc->send_data.marshaller;
 
     // TODO - better check: type in channel_allowed_types. Better: type in channel_allowed_types(channel_state)
-    if (rcc->send_data.header->type == 0) {
+    if (rcc->send_data.header.get_msg_type(&rcc->send_data.header) == 0) {
         red_printf("BUG: header->type == 0");
         return;
     }
     spice_marshaller_flush(m);
     rcc->send_data.size = spice_marshaller_get_total_size(m);
-    rcc->send_data.header->size = rcc->send_data.size - sizeof(SpiceDataHeader);
+    rcc->send_data.header.set_msg_size(&rcc->send_data.header,
+                                       rcc->send_data.size - rcc->send_data.header.header_size);
     rcc->ack_data.messages_window++;
-    rcc->send_data.header = NULL; /* avoid writing to this until we have a new message */
+    rcc->send_data.last_sent_serial = rcc->send_data.serial;
+    rcc->send_data.header.data = NULL; /* avoid writing to this until we have a new message */
     red_channel_client_send(rcc);
 }
 
 SpiceMarshaller *red_channel_client_switch_to_urgent_sender(RedChannelClient *rcc)
 {
     ASSERT(red_channel_client_no_item_being_sent(rcc));
-    ASSERT(rcc->send_data.header != NULL);
-    rcc->send_data.main.header = rcc->send_data.header;
+    ASSERT(rcc->send_data.header.data != NULL);
+    rcc->send_data.main.header_data = rcc->send_data.header.data;
     rcc->send_data.main.item = rcc->send_data.item;
 
     rcc->send_data.marshaller = rcc->send_data.urgent.marshaller;
@@ -938,8 +1033,10 @@ static void red_channel_client_restore_main_sender(RedChannelClient *rcc)
 {
     spice_marshaller_reset(rcc->send_data.urgent.marshaller);
     rcc->send_data.marshaller = rcc->send_data.main.marshaller;
-    rcc->send_data.header = rcc->send_data.main.header;
-    rcc->send_data.header->serial = rcc->send_data.serial;
+    rcc->send_data.header.data = rcc->send_data.main.header_data;
+    if (!rcc->is_mini_header) {
+        rcc->send_data.header.set_msg_serial(&rcc->send_data.header, rcc->send_data.serial);
+    }
     rcc->send_data.item = rcc->send_data.main.item;
 }
 
@@ -1069,7 +1166,6 @@ void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_
     rcc->ack_data.client_window = client_window;
 }
 
-
 static void red_channel_remove_client(RedChannelClient *rcc)
 {
     ASSERT(pthread_equal(pthread_self(), rcc->channel->thread_id));
@@ -1127,6 +1223,19 @@ RedChannelClient *red_channel_client_create_dummy(int size,
     rcc->client = client;
     rcc->channel = channel;
     red_channel_client_set_remote_caps(rcc, num_common_caps, common_caps, num_caps, caps);
+    if (red_channel_client_test_remote_common_cap(rcc, SPICE_COMMON_CAP_MINI_HEADER)) {
+        rcc->incoming.header = mini_header_wrapper;
+        rcc->send_data.header = mini_header_wrapper;
+        rcc->is_mini_header = TRUE;
+    } else {
+        rcc->incoming.header = full_header_wrapper;
+        rcc->send_data.header = full_header_wrapper;
+        rcc->is_mini_header = FALSE;
+    }
+
+    rcc->incoming.header.data = rcc->incoming.header_buf;
+    rcc->incoming.serial = 1;
+
     red_channel_add_client(channel, rcc);
     return rcc;
 }
@@ -1200,7 +1309,7 @@ int red_channel_client_blocked(RedChannelClient *rcc)
 
 int red_channel_client_send_message_pending(RedChannelClient *rcc)
 {
-    return rcc->send_data.header->type != 0;
+    return rcc->send_data.header.get_msg_type(&rcc->send_data.header) != 0;
 }
 
 /* accessors for RedChannelClient */
@@ -1221,7 +1330,7 @@ RedClient *red_channel_client_get_client(RedChannelClient *rcc)
 
 void red_channel_client_set_header_sub_list(RedChannelClient *rcc, uint32_t sub_list)
 {
-    rcc->send_data.header->sub_list = sub_list;
+    rcc->send_data.header.set_msg_sub_list(&rcc->send_data.header, sub_list);
 }
 
 /* end of accessors */
diff --git a/server/red_channel.h b/server/red_channel.h
index 40792c1..045bfd4 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -33,10 +33,34 @@
 #define MAX_SEND_VEC 100
 #define CLIENT_ACK_WINDOW 20
 
+#define MAX_HEADER_SIZE sizeof(SpiceDataHeader)
+
 /* Basic interface for channels, without using the RedChannel interface.
    The intention is to move towards one channel interface gradually.
    At the final stage, this interface shouldn't be exposed. Only RedChannel will use it. */
 
+typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
+
+typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header);
+typedef uint32_t (*get_msg_size_proc)(SpiceDataHeaderOpaque *header);
+typedef void (*set_msg_type_proc)(SpiceDataHeaderOpaque *header, uint16_t type);
+typedef void (*set_msg_size_proc)(SpiceDataHeaderOpaque *header, uint32_t size);
+typedef void (*set_msg_serial_proc)(SpiceDataHeaderOpaque *header, uint64_t serial);
+typedef void (*set_msg_sub_list_proc)(SpiceDataHeaderOpaque *header, uint32_t sub_list);
+
+struct SpiceDataHeaderOpaque {
+    uint8_t *data;
+    uint16_t header_size;
+
+    set_msg_type_proc set_msg_type;
+    set_msg_size_proc set_msg_size;
+    set_msg_serial_proc set_msg_serial;
+    set_msg_sub_list_proc set_msg_sub_list;
+
+    get_msg_type_proc get_msg_type;
+    get_msg_size_proc get_msg_size;
+};
+
 typedef int (*handle_message_proc)(void *opaque,
                                    uint16_t type, uint32_t size, uint8_t *msg);
 typedef int (*handle_parsed_proc)(void *opaque, uint32_t size, uint16_t type, void *message);
@@ -58,10 +82,12 @@ typedef struct IncomingHandlerInterface {
 typedef struct IncomingHandler {
     IncomingHandlerInterface *cb;
     void *opaque;
-    SpiceDataHeader header;
+    uint8_t header_buf[MAX_HEADER_SIZE];
+    SpiceDataHeaderOpaque header;
     uint32_t header_pos;
     uint8_t *msg; // data of the msg following the header. allocated by alloc_msg_buf.
     uint32_t msg_pos;
+    uint64_t serial;
 } IncomingHandler;
 
 typedef int (*get_outgoing_msg_size_proc)(void *opaque);
@@ -202,21 +228,21 @@ struct RedChannelClient {
 
     struct {
         SpiceMarshaller *marshaller;
-        SpiceDataHeader *header;
+        SpiceDataHeaderOpaque header;
         uint32_t size;
         PipeItem *item;
         int blocked;
         uint64_t serial;
+        uint64_t last_sent_serial;
 
         struct {
             SpiceMarshaller *marshaller;
-            SpiceDataHeader *header;
+            uint8_t *header_data;
             PipeItem *item;
         } main;
 
         struct {
             SpiceMarshaller *marshaller;
-            SpiceDataHeader *header;
         } urgent;
     } send_data;
 
@@ -228,6 +254,7 @@ struct RedChannelClient {
     uint32_t pipe_size;
 
     RedChannelCapabilities remote_caps;
+    int is_mini_header;
 };
 
 struct RedChannel {
diff --git a/server/red_worker.c b/server/red_worker.c
index f454302..d096ee4 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -593,6 +593,9 @@ typedef struct CommonChannelClient {
     struct RedWorker *worker;
 } CommonChannelClient;
 
+/* Each drawable can refer to at most 3 images: src, brush and mask */
+#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3
+
 struct DisplayChannelClient {
     CommonChannelClient common;
 
@@ -616,6 +619,8 @@ struct DisplayChannelClient {
         RedCompressBuf *used_compress_bufs;
 
         FreeList free_list;
+        uint64_t pixmap_cache_items[MAX_DRAWABLE_PIXMAP_CACHE_ITEMS];
+        int num_pixmap_cache_items;
     } send_data;
 
     /* global lz encoding entities */
@@ -986,8 +991,7 @@ static void red_display_release_stream(RedWorker *worker, StreamAgent *agent);
 static inline void red_detach_stream(RedWorker *worker, Stream *stream);
 static void red_stop_stream(RedWorker *worker, Stream *stream);
 static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect);
-static inline void display_begin_send_message(RedChannelClient *rcc,
-                                              SpiceMarshaller *base_marshaller);
+static inline void display_begin_send_message(RedChannelClient *rcc);
 static void red_release_pixmap_cache(DisplayChannelClient *dcc);
 static void red_release_glz(DisplayChannelClient *dcc);
 static void red_freeze_glz(DisplayChannelClient *dcc);
@@ -6248,6 +6252,8 @@ static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
                                  image->descriptor.width * image->descriptor.height, is_lossy,
                                  dcc)) {
                 io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
+                dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] =
+                                                                               image->descriptor.id;
                 stat_inc_counter(display_channel->add_to_cache_counter, 1);
             }
         }
@@ -6290,6 +6296,8 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
         int lossy_cache_item;
         if (pixmap_cache_hit(dcc->pixmap_cache, image.descriptor.id,
                              &lossy_cache_item, dcc)) {
+            dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] =
+                                                                               image.descriptor.id;
             if (can_lossy || !lossy_cache_item) {
                 if (!display_channel->enable_jpeg || lossy_cache_item) {
                     image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
@@ -6463,6 +6471,7 @@ static inline void red_display_reset_send_data(DisplayChannelClient *dcc)
 {
     red_display_reset_compress_buf(dcc);
     dcc->send_data.free_list.res->count = 0;
+    dcc->send_data.num_pixmap_cache_items = 0;
     memset(dcc->send_data.free_list.sync, 0, sizeof(dcc->send_data.free_list.sync));
 }
 
@@ -7780,27 +7789,123 @@ static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type
     free_list->res->resources[free_list->res->count++].id = id;
 }
 
-static inline void display_begin_send_message(RedChannelClient *rcc,
-                                              SpiceMarshaller *base_marshaller)
+static inline void display_marshal_sub_msg_inval_list(SpiceMarshaller *m,
+                                                       FreeList *free_list)
+{
+    /* type + size + submessage */
+    spice_marshaller_add_uint16(m, SPICE_MSG_DISPLAY_INVAL_LIST);
+    spice_marshaller_add_uint32(m, sizeof(*free_list->res) +
+                                free_list->res->count * sizeof(free_list->res->resources[0]));
+    spice_marshall_msg_display_inval_list(m, free_list->res);
+}
+
+static inline void display_marshal_sub_msg_inval_list_wait(SpiceMarshaller *m,
+                                                            FreeList *free_list)
+
+{
+    /* type + size + submessage */
+    spice_marshaller_add_uint16(m, SPICE_MSG_WAIT_FOR_CHANNELS);
+    spice_marshaller_add_uint32(m, sizeof(free_list->wait.header) +
+                                free_list->wait.header.wait_count * sizeof(free_list->wait.buf[0]));
+    spice_marshall_msg_wait_for_channels(m, &free_list->wait.header);
+}
+
+/* use legacy SpiceDataHeader (with sub_list) */
+static inline void display_channel_send_free_list_legacy(RedChannelClient *rcc)
+{
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    FreeList *free_list = &dcc->send_data.free_list;
+    SpiceMarshaller *marshaller;
+    int sub_list_len = 1;
+    SpiceMarshaller *wait_m = NULL;
+    SpiceMarshaller *inval_m;
+    SpiceMarshaller *sub_list_m;
+
+    marshaller = red_channel_client_get_marshaller(rcc);
+    inval_m = spice_marshaller_get_submarshaller(marshaller);
+
+    display_marshal_sub_msg_inval_list(inval_m, free_list);
+
+    if (free_list->wait.header.wait_count) {
+        wait_m = spice_marshaller_get_submarshaller(marshaller);
+        display_marshal_sub_msg_inval_list_wait(wait_m, free_list);
+        sub_list_len++;
+    }
+
+    sub_list_m = spice_marshaller_get_submarshaller(marshaller);
+    spice_marshaller_add_uint16(sub_list_m, sub_list_len);
+    if (wait_m) {
+        spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m));
+    }
+    spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
+    red_channel_client_set_header_sub_list(rcc, spice_marshaller_get_offset(sub_list_m));
+}
+
+/* use mini header and SPICE_MSG_LIST */
+static inline void display_channel_send_free_list(RedChannelClient *rcc)
+{
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    FreeList *free_list = &dcc->send_data.free_list;
+    int sub_list_len = 1;
+    SpiceMarshaller *urgent_marshaller;
+    SpiceMarshaller *wait_m = NULL;
+    SpiceMarshaller *inval_m;
+    uint32_t sub_arr_offset;
+    uint32_t wait_offset = 0;
+    uint32_t inval_offset = 0;
+    int i;
+
+    urgent_marshaller = red_channel_client_switch_to_urgent_sender(rcc);
+    for (i = 0; i < dcc->send_data.num_pixmap_cache_items; i++) {
+        int dummy;
+        /* When using the urgent marshaller, the serial number of the message that is
+         * going to be sent right after the SPICE_MSG_LIST, is increased by one.
+         * But all this message pixmaps cache references used its old serial.
+         * we use pixmap_cache_items to collect these pixmaps, and we update their serial by calling pixmap_cache_hit.*/
+        pixmap_cache_hit(dcc->pixmap_cache, dcc->send_data.pixmap_cache_items[i],
+                         &dummy, dcc);
+    }
+
+    if (free_list->wait.header.wait_count) {
+        red_channel_client_init_send_data(rcc, SPICE_MSG_LIST, NULL);
+    } else { /* only one message, no need for a list */
+        red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_LIST, NULL);
+        spice_marshall_msg_display_inval_list(urgent_marshaller, free_list->res);
+        return;
+    }
+
+    inval_m = spice_marshaller_get_submarshaller(urgent_marshaller);
+    display_marshal_sub_msg_inval_list(inval_m, free_list);
+
+    if (free_list->wait.header.wait_count) {
+        wait_m = spice_marshaller_get_submarshaller(urgent_marshaller);
+        display_marshal_sub_msg_inval_list_wait(wait_m, free_list);
+        sub_list_len++;
+    }
+
+    sub_arr_offset = sub_list_len * sizeof(uint32_t);
+
+    spice_marshaller_add_uint16(urgent_marshaller, sub_list_len);
+    inval_offset = spice_marshaller_get_offset(inval_m); // calc the offset before
+                                                         // adding the sub list
+                                                         // offsets array to the marshaller
+    /* adding the array of offsets */
+    if (wait_m) {
+        wait_offset = spice_marshaller_get_offset(wait_m);
+        spice_marshaller_add_uint32(urgent_marshaller, wait_offset + sub_arr_offset);
+    }
+    spice_marshaller_add_uint32(urgent_marshaller, inval_offset + sub_arr_offset);
+}
+
+static inline void display_begin_send_message(RedChannelClient *rcc)
 {
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     FreeList *free_list = &dcc->send_data.free_list;
 
     if (free_list->res->count) {
-        int sub_list_len = 1;
-        SpiceMarshaller *wait_m = NULL;
-        SpiceMarshaller *inval_m;
         int sync_count = 0;
         int i;
 
-        inval_m = spice_marshaller_get_submarshaller(base_marshaller);
-
-        /* type + size + submessage */
-        spice_marshaller_add_uint16(inval_m, SPICE_MSG_DISPLAY_INVAL_LIST);
-        spice_marshaller_add_uint32(inval_m, sizeof(*free_list->res) +
-                        free_list->res->count * sizeof(free_list->res->resources[0]));
-        spice_marshall_msg_display_inval_list(inval_m, free_list->res);
-
         for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
             if (i != dcc->common.id && free_list->sync[i] != 0) {
                 free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY;
@@ -7810,24 +7915,11 @@ static inline void display_begin_send_message(RedChannelClient *rcc,
         }
         free_list->wait.header.wait_count = sync_count;
 
-        if (sync_count) {
-            wait_m = spice_marshaller_get_submarshaller(base_marshaller);
-
-            /* type + size + submessage */
-            spice_marshaller_add_uint16(wait_m, SPICE_MSG_WAIT_FOR_CHANNELS);
-            spice_marshaller_add_uint32(wait_m, sizeof(free_list->wait.header) +
-                                                sync_count * sizeof(free_list->wait.buf[0]));
-            spice_marshall_msg_wait_for_channels(wait_m, &free_list->wait.header);
-            sub_list_len++;
-        }
-
-        SpiceMarshaller *sub_list_m = spice_marshaller_get_submarshaller(base_marshaller);
-        spice_marshaller_add_uint16(sub_list_m, sub_list_len);
-        if (wait_m) {
-            spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m));
+        if (rcc->is_mini_header) {
+            display_channel_send_free_list(rcc);
+        } else {
+            display_channel_send_free_list_legacy(rcc);
         }
-        spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
-        red_channel_client_set_header_sub_list(rcc, spice_marshaller_get_offset(sub_list_m));
     }
     red_channel_client_begin_send_message(rcc);
 }
@@ -8495,7 +8587,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
 
     // a message is pending
     if (red_channel_client_send_message_pending(rcc)) {
-        display_begin_send_message(rcc, m);
+        display_begin_send_message(rcc);
     }
 }
 
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 048da34..5d58077 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -101,7 +101,6 @@ struct SndChannel {
 
     struct {
         uint64_t serial;
-        SpiceDataHeader *header;
         SpiceMarshaller *marshaller;
         uint32_t size;
         uint32_t pos;
@@ -109,7 +108,7 @@ struct SndChannel {
 
     struct {
         uint8_t buf[RECIVE_BUF_SIZE];
-        SpiceDataHeader *message;
+        uint8_t *message_start;
         uint8_t *now;
         uint8_t *end;
     } recive_data;
@@ -417,10 +416,14 @@ static int snd_record_handle_message(SndChannel *channel, size_t size, uint32_t
 static void snd_receive(void* data)
 {
     SndChannel *channel = (SndChannel*)data;
+    SpiceDataHeaderOpaque *header;
+
     if (!channel) {
         return;
     }
 
+    header = &channel->channel_client->incoming.header;
+
     for (;;) {
         ssize_t n;
         n = channel->recive_data.end - channel->recive_data.now;
@@ -448,40 +451,44 @@ static void snd_receive(void* data)
         } else {
             channel->recive_data.now += n;
             for (;;) {
-                SpiceDataHeader *header = channel->recive_data.message;
-                uint8_t *data = (uint8_t *)(header+1);
+                uint8_t *msg_start = channel->recive_data.message_start;
+                uint8_t *data = msg_start + header->header_size;
                 size_t parsed_size;
                 uint8_t *parsed;
                 message_destructor_t parsed_free;
 
-                n = channel->recive_data.now - (uint8_t *)header;
-                if (n < sizeof(SpiceDataHeader) || n < sizeof(SpiceDataHeader) + header->size) {
+                header->data = msg_start;
+                n = channel->recive_data.now - msg_start;
+
+                if (n < header->header_size ||
+                    n < header->header_size + header->get_msg_size(header)) {
                     break;
                 }
-                parsed = channel->parser((void *)data, data + header->size, header->type,
+                parsed = channel->parser((void *)data, data + header->get_msg_size(header),
+                                         header->get_msg_type(header),
                                          SPICE_VERSION_MINOR, &parsed_size, &parsed_free);
                 if (parsed == NULL) {
-                    red_printf("failed to parse message type %d", header->type);
+                    red_printf("failed to parse message type %d", header->get_msg_type(header));
                     snd_disconnect_channel(channel);
                     return;
                 }
-                if (!channel->handle_message(channel, parsed_size, header->type, parsed)) {
+                if (!channel->handle_message(channel, parsed_size,
+                                             header->get_msg_type(header), parsed)) {
                     free(parsed);
                     snd_disconnect_channel(channel);
                     return;
                 }
                 parsed_free(parsed);
-                channel->recive_data.message = (SpiceDataHeader *)((uint8_t *)header +
-                                                                 sizeof(SpiceDataHeader) +
-                                                                 header->size);
+                channel->recive_data.message_start = msg_start + header->header_size +
+                                                     header->get_msg_size(header);
             }
-            if (channel->recive_data.now == (uint8_t *)channel->recive_data.message) {
+            if (channel->recive_data.now == channel->recive_data.message_start) {
                 channel->recive_data.now = channel->recive_data.buf;
-                channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
+                channel->recive_data.message_start = channel->recive_data.buf;
             } else if (channel->recive_data.now == channel->recive_data.end) {
-                memcpy(channel->recive_data.buf, channel->recive_data.message, n);
+                memcpy(channel->recive_data.buf, channel->recive_data.message_start, n);
                 channel->recive_data.now = channel->recive_data.buf + n;
-                channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
+                channel->recive_data.message_start = channel->recive_data.buf;
             }
         }
     }
@@ -501,28 +508,37 @@ static void snd_event(int fd, int event, void *data)
 
 static inline int snd_reset_send_data(SndChannel *channel, uint16_t verb)
 {
+    SpiceDataHeaderOpaque *header;
+
     if (!channel) {
         return FALSE;
     }
 
+    header = &channel->channel_client->send_data.header;
     spice_marshaller_reset(channel->send_data.marshaller);
-    channel->send_data.header = (SpiceDataHeader *)
-        spice_marshaller_reserve_space(channel->send_data.marshaller, sizeof(SpiceDataHeader));
-    spice_marshaller_set_base(channel->send_data.marshaller, sizeof(SpiceDataHeader));
+    header->data = spice_marshaller_reserve_space(channel->send_data.marshaller,
+                                                  header->header_size);
+    spice_marshaller_set_base(channel->send_data.marshaller,
+                              header->header_size);
     channel->send_data.pos = 0;
-    channel->send_data.header->sub_list = 0;
-    channel->send_data.header->size = 0;
-    channel->send_data.header->type = verb;
-    channel->send_data.header->serial = ++channel->send_data.serial;
+    header->set_msg_size(header, 0);
+    header->set_msg_type(header, verb);
+    channel->send_data.serial++;
+    if (!channel->channel_client->is_mini_header) {
+        header->set_msg_serial(header, channel->send_data.serial);
+        header->set_msg_sub_list(header, 0);
+    }
+
     return TRUE;
 }
 
 static int snd_begin_send_message(SndChannel *channel)
 {
+    SpiceDataHeaderOpaque *header = &channel->channel_client->send_data.header;
+
     spice_marshaller_flush(channel->send_data.marshaller);
     channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
-    channel->send_data.header->size = channel->send_data.size - sizeof(SpiceDataHeader);
-    channel->send_data.header = NULL; /* avoid writing to this until we have a new message */
+    header->set_msg_size(header, channel->send_data.size - header->header_size);
     return snd_send_data(channel);
 }
 
@@ -709,22 +725,25 @@ static int snd_record_send_migrate(RecordChannel *record_channel)
 {
     SndChannel *channel = (SndChannel *)record_channel;
     SpiceMsgMigrate migrate;
-    SpiceDataHeader *header;
+    SpiceDataHeaderOpaque *header;
     RecordMigrateData *data;
 
     if (!snd_reset_send_data(channel, SPICE_MSG_MIGRATE)) {
         return FALSE;
     }
 
+    header = &channel->channel_client->send_data.header;
     migrate.flags = SPICE_MIGRATE_NEED_DATA_TRANSFER;
     spice_marshall_msg_migrate(channel->send_data.marshaller, &migrate);
 
-    header = (SpiceDataHeader *)spice_marshaller_reserve_space(channel->send_data.marshaller,
-                                                               sizeof(SpiceDataHeader));
-    header->type = SPICE_MSG_MIGRATE_DATA;
-    header->size = sizeof(RecordMigrateData);
-    header->serial = ++channel->send_data.serial;
-    header->sub_list = 0;
+    header->data = spice_marshaller_reserve_space(channel->send_data.marshaller, header->header_size);
+    header->set_msg_size(header, sizeof(RecordMigrateData));
+    header->set_msg_type(header, SPICE_MSG_MIGRATE_DATA);
+    ++channel->send_data.serial;
+    if (!channel->channel_client->is_mini_header) {
+        header->set_msg_serial(header, channel->send_data.serial);
+        header->set_msg_sub_list(header, 0);
+    }
 
     data = (RecordMigrateData *)spice_marshaller_reserve_space(channel->send_data.marshaller,
                                                                sizeof(RecordMigrateData));
@@ -735,7 +754,8 @@ static int snd_record_send_migrate(RecordChannel *record_channel)
     data->mode_time = record_channel->mode_time;
 
     channel->send_data.size = spice_marshaller_get_total_size(channel->send_data.marshaller);
-    channel->send_data.header->size = channel->send_data.size - sizeof(SpiceDataHeader) - sizeof(SpiceDataHeader) - sizeof(*data);
+    header->set_msg_size(header, channel->send_data.size - header->header_size -
+                         header->header_size - sizeof(*data));
 
     return snd_send_data(channel);
 }
@@ -876,6 +896,7 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i
                                  snd_channel_handle_message_proc handle_message,
                                  snd_channel_on_message_done_proc on_message_done,
                                  snd_channel_cleanup_channel_proc cleanup,
+                                 uint32_t *common_caps, int num_common_caps,
                                  uint32_t *caps, int num_caps)
 {
     SndChannel *channel;
@@ -917,7 +938,7 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i
     channel->parser = spice_get_client_channel_parser(channel_id, NULL);
     channel->stream = stream;
     channel->worker = worker;
-    channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
+    channel->recive_data.message_start = channel->recive_data.buf;
     channel->recive_data.now = channel->recive_data.buf;
     channel->recive_data.end = channel->recive_data.buf + sizeof(channel->recive_data.buf);
     channel->send_data.marshaller = spice_marshaller_new();
@@ -938,7 +959,7 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i
     channel->channel_client = red_channel_client_create_dummy(sizeof(RedChannelClient),
                                                               worker->base_channel,
                                                               client,
-                                                              0, NULL,
+                                                              num_common_caps, common_caps,
                                                               num_caps, caps);
     return channel;
 
@@ -1159,6 +1180,7 @@ static void snd_set_playback_peer(RedChannel *channel, RedClient *client, RedsSt
                                                               snd_playback_handle_message,
                                                               snd_playback_on_message_done,
                                                               snd_playback_cleanup,
+                                                              common_caps, num_common_caps,
                                                               caps, num_caps))) {
         goto error_2;
     }
@@ -1367,6 +1389,7 @@ static void snd_set_record_peer(RedChannel *channel, RedClient *client, RedsStre
                                                           snd_record_handle_message,
                                                           snd_record_on_message_done,
                                                           snd_record_cleanup,
+                                                          common_caps, num_common_caps,
                                                           caps, num_caps))) {
         goto error_2;
     }
commit ec0bf2488f2ac0b7fb5102fd3d8822fd2883bd0a
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Sun Jan 8 09:26:31 2012 +0200

    configure: spice-protocol >= 0.10.1 (mini header support)

diff --git a/configure.ac b/configure.ac
index 861e939..cf3eda6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,7 +132,7 @@ AM_CONDITIONAL(SUPPORT_CLIENT, test "x$enable_client" = "xyes")
 dnl =========================================================================
 dnl Check deps
 
-PKG_CHECK_MODULES(PROTOCOL, spice-protocol >= 0.9.1)
+PKG_CHECK_MODULES(PROTOCOL, spice-protocol >= 0.10.1)
 AC_SUBST(PROTOCOL_CFLAGS)
 
 AC_CHECK_LIBM
commit 8b64b95c4339c145867e42f71b3206378bc7c83b
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Jan 5 17:31:34 2012 +0200

    server: Limit the access to SpiceDataHeader of messages - only via red_channel.

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index 0fa4162..4fe36b8 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -168,18 +168,22 @@ const VDAgentMouseState *inputs_get_mouse_state(void)
     return &g_inputs_channel->mouse_state;
 }
 
-static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
+static uint8_t *inputs_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
+                                                 uint16_t type,
+                                                 uint32_t size)
 {
     InputsChannel *inputs_channel = SPICE_CONTAINEROF(rcc->channel, InputsChannel, base);
 
-    if (msg_header->size > RECEIVE_BUF_SIZE) {
+    if (size > RECEIVE_BUF_SIZE) {
         red_printf("error: too large incoming message");
         return NULL;
     }
     return inputs_channel->recv_buf;
 }
 
-static void inputs_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
+static void inputs_channel_release_msg_rcv_buf(RedChannelClient *rcc,
+                                               uint16_t type,
+                                               uint32_t size,
                                                uint8_t *msg)
 {
 }
diff --git a/server/main_channel.c b/server/main_channel.c
index 4b5b669..b55bf00 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -852,14 +852,18 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
     return TRUE;
 }
 
-static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
+static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
+                                               uint16_t type,
+                                               uint32_t size)
 {
     MainChannel *main_chan = SPICE_CONTAINEROF(rcc->channel, MainChannel, base);
 
     return main_chan->recv_buf;
 }
 
-static void main_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
+static void main_channel_release_msg_rcv_buf(RedChannelClient *rcc,
+                                               uint16_t type,
+                                               uint32_t size,
                                                uint8_t *msg)
 {
 }
diff --git a/server/red_channel.c b/server/red_channel.c
index 671bcf5..06b4ef0 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -103,7 +103,9 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
 
         if (handler->msg_pos < handler->header.size) {
             if (!handler->msg) {
-                handler->msg = handler->cb->alloc_msg_buf(handler->opaque, &handler->header);
+                handler->msg = handler->cb->alloc_msg_buf(handler->opaque,
+                                                          handler->header.type,
+                                                          handler->header.size);
                 if (handler->msg == NULL) {
                     red_printf("ERROR: channel refused to allocate buffer.");
                     handler->cb->on_error(handler->opaque);
@@ -115,7 +117,10 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           handler->msg + handler->msg_pos,
                                           handler->header.size - handler->msg_pos);
             if (bytes_read == -1) {
-                handler->cb->release_msg_buf(handler->opaque, &handler->header, handler->msg);
+                handler->cb->release_msg_buf(handler->opaque,
+                                             handler->header.type,
+                                             handler->header.size,
+                                             handler->msg);
                 handler->cb->on_error(handler->opaque);
                 return;
             }
@@ -131,7 +136,9 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                 SPICE_VERSION_MINOR, &parsed_size, &parsed_free);
             if (parsed == NULL) {
                 red_printf("failed to parse message type %d", handler->header.type);
-                handler->cb->release_msg_buf(handler->opaque, &handler->header, handler->msg);
+                handler->cb->release_msg_buf(handler->opaque, handler->header.type,
+                                             handler->header.size,
+                                             handler->msg);
                 handler->cb->on_error(handler->opaque);
                 return;
             }
@@ -139,11 +146,16 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                     handler->header.type, parsed);
             parsed_free(parsed);
         } else {
-            ret_handle = handler->cb->handle_message(handler->opaque, &handler->header,
-                                                 handler->msg);
+            ret_handle = handler->cb->handle_message(handler->opaque,
+                                                     handler->header.type,
+                                                     handler->header.size,
+                                                     handler->msg);
         }
         handler->msg_pos = 0;
-        handler->cb->release_msg_buf(handler->opaque, &handler->header, handler->msg);
+        handler->cb->release_msg_buf(handler->opaque,
+                                     handler->header.type,
+                                     handler->header.size,
+                                     handler->msg);
         handler->msg = NULL;
         handler->header_pos = 0;
 
@@ -586,7 +598,10 @@ RedChannel *red_channel_create_dummy(int size, uint32_t type, uint32_t id)
     return channel;
 }
 
-static int do_nothing_handle_message(RedChannelClient *rcc, SpiceDataHeader *header, uint8_t *msg)
+static int do_nothing_handle_message(RedChannelClient *rcc,
+                                     uint16_t type,
+                                     uint32_t size,
+                                     uint8_t *msg)
 {
     return TRUE;
 }
@@ -1204,10 +1219,11 @@ RedClient *red_channel_client_get_client(RedChannelClient *rcc)
     return rcc->client;
 }
 
-SpiceDataHeader *red_channel_client_get_header(RedChannelClient *rcc)
+void red_channel_client_set_header_sub_list(RedChannelClient *rcc, uint32_t sub_list)
 {
-    return rcc->send_data.header;
+    rcc->send_data.header->sub_list = sub_list;
 }
+
 /* end of accessors */
 
 int red_channel_get_first_socket(RedChannel *channel)
diff --git a/server/red_channel.h b/server/red_channel.h
index cb80100..40792c1 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -38,11 +38,11 @@
    At the final stage, this interface shouldn't be exposed. Only RedChannel will use it. */
 
 typedef int (*handle_message_proc)(void *opaque,
-                                   SpiceDataHeader *header, uint8_t *msg);
+                                   uint16_t type, uint32_t size, uint8_t *msg);
 typedef int (*handle_parsed_proc)(void *opaque, uint32_t size, uint16_t type, void *message);
-typedef uint8_t *(*alloc_msg_recv_buf_proc)(void *opaque, SpiceDataHeader *msg_header);
+typedef uint8_t *(*alloc_msg_recv_buf_proc)(void *opaque, uint16_t type, uint32_t size);
 typedef void (*release_msg_recv_buf_proc)(void *opaque,
-                                          SpiceDataHeader *msg_header, uint8_t *msg);
+                                          uint16_t type, uint32_t size, uint8_t *msg);
 typedef void (*on_incoming_error_proc)(void *opaque);
 
 typedef struct IncomingHandlerInterface {
@@ -119,13 +119,13 @@ typedef struct PipeItem {
 } PipeItem;
 
 typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient *channel,
-                                                    SpiceDataHeader *msg_header);
+                                                    uint16_t type, uint32_t size);
 typedef int (*channel_handle_parsed_proc)(RedChannelClient *rcc, uint32_t size, uint16_t type,
                                         void *message);
 typedef int (*channel_handle_message_proc)(RedChannelClient *rcc,
-                                           SpiceDataHeader *header, uint8_t *msg);
+                                           uint16_t type, uint32_t size, uint8_t *msg);
 typedef void (*channel_release_msg_recv_buf_proc)(RedChannelClient *channel,
-                                                  SpiceDataHeader *msg_header, uint8_t *msg);
+                                                  uint16_t type, uint32_t size, uint8_t *msg);
 typedef void (*channel_disconnect_proc)(RedChannelClient *rcc);
 typedef int (*channel_configure_socket_proc)(RedChannelClient *rcc);
 typedef void (*channel_send_pipe_item_proc)(RedChannelClient *rcc, PipeItem *item);
@@ -334,7 +334,7 @@ void red_channel_init_outgoing_messages_window(RedChannel *channel);
 
 /* handles general channel msgs from the client */
 int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
-                               uint16_t type, void *message);
+                                      uint16_t type, void *message);
 
 /* when preparing send_data: should call init and then use marshaller */
 void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type, PipeItem *item);
@@ -444,13 +444,9 @@ SpiceMarshaller *red_channel_client_get_marshaller(RedChannelClient *rcc);
 RedsStream *red_channel_client_get_stream(RedChannelClient *rcc);
 RedClient *red_channel_client_get_client(RedChannelClient *rcc);
 
-/* this is a convenience function for sending messages, sometimes (migration only?)
- * the serial from the header needs to be available for sending. Note that the header
- * pointer retrieved is not valid except between red_channel_reset_send_data and
- * red_channel_begin_send_message. red_channel_init_send_data changes the header (sets
- * the type in it) as a convenience function. It is preffered to do that through it and
- * not via the below accessor and direct header manipulation. */
-SpiceDataHeader *red_channel_client_get_header(RedChannelClient *rcc);
+/* Note that the header is valid only between red_channel_reset_send_data and
+ * red_channel_begin_send_message.*/
+void red_channel_client_set_header_sub_list(RedChannelClient *rcc, uint32_t sub_list);
 
 /* return the sum of all the rcc pipe size */
 uint32_t red_channel_max_pipe_size(RedChannel *channel);
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 1e8267e..250e8b3 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -1644,27 +1644,27 @@ static int tunnel_channel_handle_socket_token(TunnelChannelClient *channel, RedS
 }
 
 static uint8_t *tunnel_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
-                                                 SpiceDataHeader *msg_header)
+                                                 uint16_t type, uint32_t size)
 {
     TunnelChannelClient *tunnel_channel = (TunnelChannelClient *)rcc->channel;
 
-    if (msg_header->type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
+    if (type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
         return (__tunnel_worker_alloc_socket_rcv_buf(tunnel_channel->worker)->buf);
-    } else if ((msg_header->type == SPICE_MSGC_MIGRATE_DATA) ||
-               (msg_header->type == SPICE_MSGC_TUNNEL_SERVICE_ADD)) {
-        return spice_malloc(msg_header->size);
+    } else if ((type == SPICE_MSGC_MIGRATE_DATA) ||
+               (type == SPICE_MSGC_TUNNEL_SERVICE_ADD)) {
+        return spice_malloc(size);
     } else {
         return (tunnel_channel->control_rcv_buf);
     }
 }
 
 // called by the receive routine of the channel, before the buffer was assigned to a socket
-static void tunnel_channel_release_msg_rcv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header,
+static void tunnel_channel_release_msg_rcv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size,
                                                uint8_t *msg)
 {
     TunnelChannelClient *tunnel_channel = (TunnelChannelClient *)rcc->channel;
 
-    if (msg_header->type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
+    if (type == SPICE_MSGC_TUNNEL_SOCKET_DATA) {
         ASSERT(!(SPICE_CONTAINEROF(msg, RedSocketRawRcvBuf, buf)->base.usr_opaque));
         __tunnel_worker_free_socket_rcv_buf(tunnel_channel->worker,
                                             SPICE_CONTAINEROF(msg, RedSocketRawRcvBuf, buf));
@@ -2243,12 +2243,13 @@ error:
 }
 
 //  msg was allocated by tunnel_channel_alloc_msg_rcv_buf
-static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader *header, uint8_t *msg)
+static int tunnel_channel_handle_message(RedChannelClient *rcc, uint16_t type,
+                                         uint32_t size, uint8_t *msg)
 {
     TunnelChannelClient *tunnel_channel = (TunnelChannelClient *)rcc->channel;
     RedSocket *sckt = NULL;
     // retrieve the sckt
-    switch (header->type) {
+    switch (type) {
     case SPICE_MSGC_MIGRATE_FLUSH_MARK:
     case SPICE_MSGC_MIGRATE_DATA:
     case SPICE_MSGC_TUNNEL_SERVICE_ADD:
@@ -2269,12 +2270,12 @@ static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader
         }
         break;
     default:
-        return red_channel_client_handle_message(rcc, header->size, header->type, msg);
+        return red_channel_client_handle_message(rcc, size, type, msg);
     }
 
-    switch (header->type) {
+    switch (type) {
     case SPICE_MSGC_TUNNEL_SERVICE_ADD:
-        if (header->size < sizeof(SpiceMsgcTunnelAddGenericService)) {
+        if (size < sizeof(SpiceMsgcTunnelAddGenericService)) {
             red_printf("bad message size");
             free(msg);
             return FALSE;
@@ -2285,7 +2286,7 @@ static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader
         red_printf("REDC_TUNNEL_REMOVE_SERVICE not supported yet");
         return FALSE;
     case SPICE_MSGC_TUNNEL_SOCKET_OPEN_ACK:
-        if (header->size != sizeof(SpiceMsgcTunnelSocketOpenAck)) {
+        if (size != sizeof(SpiceMsgcTunnelSocketOpenAck)) {
             red_printf("bad message size");
             return FALSE;
         }
@@ -2294,7 +2295,7 @@ static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader
                                                         ((SpiceMsgcTunnelSocketOpenAck *)msg)->tokens);
 
     case SPICE_MSGC_TUNNEL_SOCKET_OPEN_NACK:
-        if (header->size != sizeof(SpiceMsgcTunnelSocketOpenNack)) {
+        if (size != sizeof(SpiceMsgcTunnelSocketOpenNack)) {
             red_printf("bad message size");
             return FALSE;
         }
@@ -2302,35 +2303,35 @@ static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader
         return tunnel_channel_handle_socket_connect_nack(tunnel_channel, sckt);
     case SPICE_MSGC_TUNNEL_SOCKET_DATA:
     {
-        if (header->size < sizeof(SpiceMsgcTunnelSocketData)) {
+        if (size < sizeof(SpiceMsgcTunnelSocketData)) {
             red_printf("bad message size");
             return FALSE;
         }
 
         return tunnel_channel_handle_socket_receive_data(tunnel_channel, sckt,
                                                     SPICE_CONTAINEROF(msg, RedSocketRawRcvBuf, buf),
-                                                    header->size - sizeof(SpiceMsgcTunnelSocketData));
+                                                    size - sizeof(SpiceMsgcTunnelSocketData));
     }
     case SPICE_MSGC_TUNNEL_SOCKET_FIN:
-        if (header->size != sizeof(SpiceMsgcTunnelSocketFin)) {
+        if (size != sizeof(SpiceMsgcTunnelSocketFin)) {
             red_printf("bad message size");
             return FALSE;
         }
         return tunnel_channel_handle_socket_fin(tunnel_channel, sckt);
     case SPICE_MSGC_TUNNEL_SOCKET_CLOSED:
-        if (header->size != sizeof(SpiceMsgcTunnelSocketClosed)) {
+        if (size != sizeof(SpiceMsgcTunnelSocketClosed)) {
             red_printf("bad message size");
             return FALSE;
         }
         return tunnel_channel_handle_socket_closed(tunnel_channel, sckt);
     case SPICE_MSGC_TUNNEL_SOCKET_CLOSED_ACK:
-        if (header->size != sizeof(SpiceMsgcTunnelSocketClosedAck)) {
+        if (size != sizeof(SpiceMsgcTunnelSocketClosedAck)) {
             red_printf("bad message size");
             return FALSE;
         }
         return tunnel_channel_handle_socket_closed_ack(tunnel_channel, sckt);
     case SPICE_MSGC_TUNNEL_SOCKET_TOKEN:
-        if (header->size != sizeof(SpiceMsgcTunnelSocketTokens)) {
+        if (size != sizeof(SpiceMsgcTunnelSocketTokens)) {
             red_printf("bad message size");
             return FALSE;
         }
@@ -2338,7 +2339,7 @@ static int tunnel_channel_handle_message(RedChannelClient *rcc, SpiceDataHeader
         return tunnel_channel_handle_socket_token(tunnel_channel, sckt,
                                                   (SpiceMsgcTunnelSocketTokens *)msg);
     default:
-        return red_channel_client_handle_message(rcc, header->size, header->type, msg);
+        return red_channel_client_handle_message(rcc, size, type, msg);
     }
     return TRUE;
 }
diff --git a/server/red_worker.c b/server/red_worker.c
index d82c84e..f454302 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1517,15 +1517,15 @@ static void release_upgrade_item(RedWorker* worker, UpgradeItem *item)
     }
 }
 
-static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, SpiceDataHeader *msg_header)
+static uint8_t *common_alloc_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size)
 {
     CommonChannel *common = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base);
 
     return common->recv_buf;
 }
 
-static void common_release_recv_buf(RedChannelClient *rcc,
-                                    SpiceDataHeader *msg_header, uint8_t* msg)
+static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32_t size,
+                                    uint8_t* msg)
 {
 }
 
@@ -7785,7 +7785,6 @@ static inline void display_begin_send_message(RedChannelClient *rcc,
 {
     DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     FreeList *free_list = &dcc->send_data.free_list;
-    SpiceDataHeader *header = red_channel_client_get_header(rcc);
 
     if (free_list->res->count) {
         int sub_list_len = 1;
@@ -7828,7 +7827,7 @@ static inline void display_begin_send_message(RedChannelClient *rcc,
             spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m));
         }
         spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m));
-        header->sub_list = spice_marshaller_get_offset(sub_list_m);
+        red_channel_client_set_header_sub_list(rcc, spice_marshaller_get_offset(sub_list_m));
     }
     red_channel_client_begin_send_message(rcc);
 }
diff --git a/server/smartcard.c b/server/smartcard.c
index f9cafdf..08ba3da 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -273,15 +273,18 @@ static int smartcard_channel_client_config_socket(RedChannelClient *rcc)
 }
 
 static uint8_t *smartcard_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
-                                                    SpiceDataHeader *msg_header)
+                                                    uint16_t type,
+                                                    uint32_t size)
 {
-    return spice_malloc(msg_header->size);
+    return spice_malloc(size);
 }
 
 static void smartcard_channel_release_msg_rcv_buf(RedChannelClient *rcc,
-                                SpiceDataHeader *msg_header, uint8_t *msg)
+                                                  uint16_t type,
+                                                  uint32_t size,
+                                                  uint8_t *msg)
 {
-    red_printf("freeing %d bytes", msg_header->size);
+    red_printf("freeing %d bytes", size);
     free(msg);
 }
 
@@ -439,14 +442,15 @@ static void smartcard_channel_write_to_reader(VSCMsgHeader *vheader)
 }
 
 static int smartcard_channel_handle_message(RedChannelClient *rcc,
-                                            SpiceDataHeader *header,
+                                            uint16_t type,
+                                            uint32_t size,
                                             uint8_t *msg)
 {
     VSCMsgHeader* vheader = (VSCMsgHeader*)msg;
 
-    if (header->type != SPICE_MSGC_SMARTCARD_DATA) {
+    if (type != SPICE_MSGC_SMARTCARD_DATA) {
         /* handle ack's, spicy sends them while spicec does not */
-        return red_channel_client_handle_message(rcc, header->size, header->type, msg);
+        return red_channel_client_handle_message(rcc, size, type, msg);
     }
 
     ASSERT(header->size == vheader->length + sizeof(VSCMsgHeader));
diff --git a/server/spicevmc.c b/server/spicevmc.c
index bed8488..c2e249c 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -126,7 +126,9 @@ static void spicevmc_red_channel_client_on_disconnect(RedChannelClient *rcc)
 }
 
 static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
-    SpiceDataHeader *header, uint8_t *msg)
+                                                      uint16_t type,
+                                                      uint32_t size,
+                                                      uint8_t *msg)
 {
     SpiceVmcState *state;
     SpiceCharDeviceInstance *sin;
@@ -136,22 +138,22 @@ static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
     sin = state->chardev_sin;
     sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
 
-    if (header->type != SPICE_MSGC_SPICEVMC_DATA) {
-        return red_channel_client_handle_message(rcc, header->size,
-                                                 header->type, msg);
+    if (type != SPICE_MSGC_SPICEVMC_DATA) {
+        return red_channel_client_handle_message(rcc, size, type, msg);
     }
 
     /*
      * qemu spicevmc will consume everything we give it, no need for
      * flow control checks (or to use a pipe).
      */
-    sif->write(sin, msg, header->size);
+    sif->write(sin, msg, size);
 
     return TRUE;
 }
 
 static uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
-    SpiceDataHeader *msg_header)
+                                                       uint16_t type,
+                                                       uint32_t size)
 {
     SpiceVmcState *state;
 
@@ -159,9 +161,9 @@ static uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
 
     assert(!state->rcv_buf_in_use);
 
-    if (msg_header->size > state->rcv_buf_size) {
-        state->rcv_buf = spice_realloc(state->rcv_buf, msg_header->size);
-        state->rcv_buf_size = msg_header->size;
+    if (size > state->rcv_buf_size) {
+        state->rcv_buf = spice_realloc(state->rcv_buf, size);
+        state->rcv_buf_size = size;
     }
 
     state->rcv_buf_in_use = 1;
@@ -170,7 +172,9 @@ static uint8_t *spicevmc_red_channel_alloc_msg_rcv_buf(RedChannelClient *rcc,
 }
 
 static void spicevmc_red_channel_release_msg_rcv_buf(RedChannelClient *rcc,
-    SpiceDataHeader *msg_header, uint8_t *msg)
+                                                     uint16_t type,
+                                                     uint32_t size,
+                                                     uint8_t *msg)
 {
     SpiceVmcState *state;
 
commit a54f26d04e9a391977a8030d609b52e50243ba52
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Dec 28 14:10:27 2011 +0200

    server/red_worker: pass remote caps to display/cursor red_channel_client's

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 17b469e..321232b 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -102,6 +102,14 @@ static void red_dispatcher_set_display_peer(RedChannel *channel, RedClient *clie
     payload.client = client;
     payload.stream = stream;
     payload.migration = migration;
+    payload.num_common_caps = num_common_caps;
+    payload.common_caps = spice_malloc(sizeof(uint32_t)*num_common_caps);
+    payload.num_caps = num_caps;
+    payload.caps = spice_malloc(sizeof(uint32_t)*num_caps);
+
+    memcpy(payload.common_caps, common_caps, sizeof(uint32_t)*num_common_caps);
+    memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
+
     dispatcher_send_message(&dispatcher->dispatcher,
                             RED_WORKER_MESSAGE_DISPLAY_CONNECT,
                             &payload);
@@ -154,6 +162,14 @@ static void red_dispatcher_set_cursor_peer(RedChannel *channel, RedClient *clien
     payload.client = client;
     payload.stream = stream;
     payload.migration = migration;
+    payload.num_common_caps = num_common_caps;
+    payload.common_caps = spice_malloc(sizeof(uint32_t)*num_common_caps);
+    payload.num_caps = num_caps;
+    payload.caps = spice_malloc(sizeof(uint32_t)*num_caps);
+
+    memcpy(payload.common_caps, common_caps, sizeof(uint32_t)*num_common_caps);
+    memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
+
     dispatcher_send_message(&dispatcher->dispatcher,
                             RED_WORKER_MESSAGE_CURSOR_CONNECT,
                             &payload);
diff --git a/server/red_dispatcher.h b/server/red_dispatcher.h
index 7417aac..36db4e3 100644
--- a/server/red_dispatcher.h
+++ b/server/red_dispatcher.h
@@ -38,6 +38,10 @@ typedef struct RedWorkerMessageDisplayConnect {
     RedClient * client;
     RedsStream * stream;
     int migration;
+    uint32_t *common_caps; // red_worker should free
+    int num_common_caps;
+    uint32_t *caps;        // red_worker should free
+    int num_caps;
 } RedWorkerMessageDisplayConnect;
 
 typedef struct RedWorkerMessageDisplayDisconnect {
@@ -52,6 +56,10 @@ typedef struct RedWorkerMessageCursorConnect {
     RedClient *client;
     RedsStream *stream;
     int migration;
+    uint32_t *common_caps; // red_worker should free
+    int num_common_caps;
+    uint32_t *caps;        // red_worker should free
+    int num_caps;
 } RedWorkerMessageCursorConnect;
 
 typedef struct RedWorkerMessageCursorDisconnect {
diff --git a/server/red_worker.c b/server/red_worker.c
index 0d873ed..d82c84e 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9442,12 +9442,18 @@ SpiceCoreInterface worker_core = {
 };
 
 static CommonChannelClient *common_channel_client_create(int size,
-    CommonChannel *common, RedClient *client, RedsStream *stream)
+                                                         CommonChannel *common,
+                                                         RedClient *client,
+                                                         RedsStream *stream,
+                                                         uint32_t *common_caps,
+                                                         int num_common_caps,
+                                                         uint32_t *caps,
+                                                         int num_caps)
 {
     MainChannelClient *mcc = red_client_get_main(client);
     RedChannelClient *rcc =
         red_channel_client_create(size, &common->base, client, stream,
-                                  0, NULL, 0, NULL);
+                                  num_common_caps, common_caps, num_caps, caps);
     CommonChannelClient *common_cc = (CommonChannelClient*)rcc;
     common_cc->worker = common->worker;
 
@@ -9460,11 +9466,15 @@ static CommonChannelClient *common_channel_client_create(int size,
 
 
 DisplayChannelClient *display_channel_client_create(CommonChannel *common,
-                             RedClient *client, RedsStream *stream)
+                                                    RedClient *client, RedsStream *stream,
+                                                    uint32_t *common_caps, int num_common_caps,
+                                                    uint32_t *caps, int num_caps)
 {
     DisplayChannelClient *dcc =
         (DisplayChannelClient*)common_channel_client_create(
-            sizeof(DisplayChannelClient), common, client, stream);
+            sizeof(DisplayChannelClient), common, client, stream,
+            common_caps, num_common_caps,
+            caps, num_caps);
 
     if (!dcc) {
         return NULL;
@@ -9475,11 +9485,17 @@ DisplayChannelClient *display_channel_client_create(CommonChannel *common,
 }
 
 CursorChannelClient *cursor_channel_create_rcc(CommonChannel *common,
-                             RedClient *client, RedsStream *stream)
+                                               RedClient *client, RedsStream *stream,
+                                               uint32_t *common_caps, int num_common_caps,
+                                               uint32_t *caps, int num_caps)
 {
     CursorChannelClient *ccc =
         (CursorChannelClient*)common_channel_client_create(
-            sizeof(CursorChannelClient), common, client, stream);
+            sizeof(CursorChannelClient), common, client, stream,
+            common_caps,
+            num_common_caps,
+            caps,
+            num_caps);
 
     if (!ccc) {
         return NULL;
@@ -9749,7 +9765,9 @@ static void display_channel_create(RedWorker *worker, int migrate)
 
 
 static void handle_new_display_channel(RedWorker *worker, RedClient *client, RedsStream *stream,
-                                       int migrate)
+                                       int migrate,
+                                       uint32_t *common_caps, int num_common_caps,
+                                       uint32_t *caps, int num_caps)
 {
     DisplayChannel *display_channel;
     DisplayChannelClient *dcc;
@@ -9762,7 +9780,9 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
     }
     display_channel = worker->display_channel;
     red_printf("add display channel client");
-    dcc = display_channel_client_create(&display_channel->common, client, stream);
+    dcc = display_channel_client_create(&display_channel->common, client, stream,
+                                        common_caps, num_common_caps,
+                                        caps, num_caps);
     if (!dcc) {
         return;
     }
@@ -9941,7 +9961,9 @@ static void cursor_channel_create(RedWorker *worker, int migrate)
 }
 
 static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream *stream,
-                               int migrate)
+                               int migrate,
+                               uint32_t *common_caps, int num_common_caps,
+                               uint32_t *caps, int num_caps)
 {
     CursorChannel *channel;
     CursorChannelClient *ccc;
@@ -9952,7 +9974,9 @@ static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream
     }
     channel = worker->cursor_channel;
     red_printf("add cursor channel client");
-    ccc = cursor_channel_create_rcc(&channel->common, client, stream);
+    ccc = cursor_channel_create_rcc(&channel->common, client, stream,
+                                    common_caps, num_common_caps,
+                                    caps, num_caps);
     if (!ccc) {
         return;
     }
@@ -10522,7 +10546,11 @@ void handle_dev_display_connect(void *opaque, void *payload)
     int migration = msg->migration;
 
     red_printf("connect");
-    handle_new_display_channel(worker, client, stream, migration);
+    handle_new_display_channel(worker, client, stream, migration,
+                               msg->common_caps, msg->num_common_caps,
+                               msg->caps, msg->num_caps);
+    free(msg->caps);
+    free(msg->common_caps);
 }
 
 void handle_dev_display_disconnect(void *opaque, void *payload)
@@ -10567,7 +10595,11 @@ void handle_dev_cursor_connect(void *opaque, void *payload)
     int migration = msg->migration;
 
     red_printf("cursor connect");
-    red_connect_cursor(worker, client, stream, migration);
+    red_connect_cursor(worker, client, stream, migration,
+                       msg->common_caps, msg->num_common_caps,
+                       msg->caps, msg->num_caps);
+    free(msg->caps);
+    free(msg->common_caps);
 }
 
 void handle_dev_cursor_disconnect(void *opaque, void *payload)
commit b689abe576c382ab1107e50f7b24de116a622dab
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Dec 28 13:31:20 2011 +0200

    server/red_channel: introduce urgent marshaller
    
    When red_channel::red_channel_client_begin_send_message is called,
    the message that is pending in the urgent marshaller will be sent before
    the one in the main channel.
    The urgent marshaller should be used if in the middle of marshalling one message,
    you find out you need to send another message before. This functionality
    is equivalent to the sub_list messages. It will replace them in the following
    patches, when sub_list is removed from Spice data header.

diff --git a/server/red_channel.c b/server/red_channel.c
index 2ce0094..671bcf5 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -38,6 +38,7 @@
 static void red_channel_client_event(int fd, int event, void *data);
 static void red_client_add_channel(RedClient *client, RedChannelClient *rcc);
 static void red_client_remove_channel(RedChannelClient *rcc);
+static void red_channel_client_restore_main_sender(RedChannelClient *rcc);
 
 /* return the number of bytes read. -1 in case of error */
 static int red_peer_receive(RedsStream *stream, uint8_t *buf, uint32_t size)
@@ -204,10 +205,13 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
             handler->pos += n;
             handler->cb->on_output(handler->opaque, n);
             if (handler->pos == handler->size) { // finished writing data
-                handler->cb->on_msg_done(handler->opaque);
+                /* reset handler before calling on_msg_done, since it
+                 * can trigger another call to red_peer_handle_outgoing (when
+                 * switching from the urgent marshaller to the main one */
                 handler->vec = handler->vec_buf;
                 handler->pos = 0;
                 handler->size = 0;
+                handler->cb->on_msg_done(handler->opaque);
                 return;
             }
         }
@@ -252,6 +256,11 @@ static void red_channel_client_peer_on_out_block(void *opaque)
                                      SPICE_WATCH_EVENT_WRITE);
 }
 
+static inline int red_channel_client_urgent_marshaller_is_active(RedChannelClient *rcc)
+{
+    return (rcc->send_data.marshaller == rcc->send_data.urgent.marshaller);
+}
+
 static void red_channel_client_reset_send_data(RedChannelClient *rcc)
 {
     spice_marshaller_reset(rcc->send_data.marshaller);
@@ -261,7 +270,16 @@ static void red_channel_client_reset_send_data(RedChannelClient *rcc)
     rcc->send_data.header->type = 0;
     rcc->send_data.header->size = 0;
     rcc->send_data.header->sub_list = 0;
-    rcc->send_data.header->serial = ++rcc->send_data.serial;
+
+    if (!red_channel_client_urgent_marshaller_is_active(rcc)) {
+        rcc->send_data.header->serial = ++rcc->send_data.serial;
+    } else {
+        /*  The serial was incremented by the call to reset_send_data
+         *  that was done for the main marshaller. The urgent msg should
+         *  receive this serial, and the main msg serial should be
+         *  the following one. */
+        rcc->send_data.header->serial = rcc->send_data.serial++;
+    }
 }
 
 void red_channel_client_push_set_ack(RedChannelClient *rcc)
@@ -343,6 +361,12 @@ static void red_channel_peer_on_out_msg_done(void *opaque)
         rcc->channel->core->watch_update_mask(rcc->stream->watch,
                                          SPICE_WATCH_EVENT_READ);
     }
+
+    if (red_channel_client_urgent_marshaller_is_active(rcc)) {
+        red_channel_client_restore_main_sender(rcc);
+        ASSERT(rcc->send_data.header != NULL);
+        red_channel_client_begin_send_message(rcc);
+    }
 }
 
 static void red_channel_client_pipe_remove(RedChannelClient *rcc, PipeItem *item)
@@ -407,7 +431,10 @@ RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedCl
                                              // block flags)
     rcc->ack_data.client_generation = ~0;
     rcc->ack_data.client_window = CLIENT_ACK_WINDOW;
-    rcc->send_data.marshaller = spice_marshaller_new();
+    rcc->send_data.main.marshaller = spice_marshaller_new();
+    rcc->send_data.urgent.marshaller = spice_marshaller_new();
+
+    rcc->send_data.marshaller = rcc->send_data.main.marshaller;
 
     rcc->incoming.opaque = rcc;
     rcc->incoming.cb = &channel->incoming_cb;
@@ -643,9 +670,14 @@ void red_channel_client_destroy(RedChannelClient *rcc)
         red_channel_client_disconnect(rcc);
     }
     red_client_remove_channel(rcc);
-    if (rcc->send_data.marshaller) {
-        spice_marshaller_destroy(rcc->send_data.marshaller);
+    if (rcc->send_data.main.marshaller) {
+        spice_marshaller_destroy(rcc->send_data.main.marshaller);
+    }
+
+    if (rcc->send_data.urgent.marshaller) {
+        spice_marshaller_destroy(rcc->send_data.urgent.marshaller);
     }
+
     red_channel_client_destroy_remote_caps(rcc);
     free(rcc);
 }
@@ -874,6 +906,28 @@ void red_channel_client_begin_send_message(RedChannelClient *rcc)
     red_channel_client_send(rcc);
 }
 
+SpiceMarshaller *red_channel_client_switch_to_urgent_sender(RedChannelClient *rcc)
+{
+    ASSERT(red_channel_client_no_item_being_sent(rcc));
+    ASSERT(rcc->send_data.header != NULL);
+    rcc->send_data.main.header = rcc->send_data.header;
+    rcc->send_data.main.item = rcc->send_data.item;
+
+    rcc->send_data.marshaller = rcc->send_data.urgent.marshaller;
+    rcc->send_data.item = NULL;
+    red_channel_client_reset_send_data(rcc);
+    return rcc->send_data.marshaller;
+}
+
+static void red_channel_client_restore_main_sender(RedChannelClient *rcc)
+{
+    spice_marshaller_reset(rcc->send_data.urgent.marshaller);
+    rcc->send_data.marshaller = rcc->send_data.main.marshaller;
+    rcc->send_data.header = rcc->send_data.main.header;
+    rcc->send_data.header->serial = rcc->send_data.serial;
+    rcc->send_data.item = rcc->send_data.main.item;
+}
+
 uint64_t red_channel_client_get_message_serial(RedChannelClient *rcc)
 {
     return rcc->send_data.serial;
diff --git a/server/red_channel.h b/server/red_channel.h
index cce6965..cb80100 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -207,6 +207,17 @@ struct RedChannelClient {
         PipeItem *item;
         int blocked;
         uint64_t serial;
+
+        struct {
+            SpiceMarshaller *marshaller;
+            SpiceDataHeader *header;
+            PipeItem *item;
+        } main;
+
+        struct {
+            SpiceMarshaller *marshaller;
+            SpiceDataHeader *header;
+        } urgent;
     } send_data;
 
     OutgoingHandler outgoing;
@@ -331,9 +342,23 @@ void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type,
 uint64_t red_channel_client_get_message_serial(RedChannelClient *channel);
 void red_channel_client_set_message_serial(RedChannelClient *channel, uint64_t);
 
-/* when sending a msg. should first call red_channel_client_begin_send_message */
+/* When sending a msg. Should first call red_channel_client_begin_send_message.
+ * It will first send the pending urgent data, if there is any, and then
+ * the rest of the data.
+ */
 void red_channel_client_begin_send_message(RedChannelClient *rcc);
 
+/*
+ * Stores the current send data, and switches to urgent send data.
+ * When it begins the actual send, it will send first the urgent data
+ * and afterward the rest of the data.
+ * Should be called only if during the marshalling of on message,
+ * the need to send another message, before, rises.
+ * Important: the serial of the non-urgent sent data, will be succeeded.
+ * return: the urgent send data marshaller
+ */
+SpiceMarshaller *red_channel_client_switch_to_urgent_sender(RedChannelClient *rcc);
+
 void red_channel_pipe_item_init(RedChannel *channel, PipeItem *item, int type);
 
 // TODO: add back the channel_pipe_add functionality - by adding reference counting
commit 33feaf75d67584beae7c548b948dbb34b7cf6171
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Jan 10 09:29:27 2012 +0200

    spice.proto: add SPICE_MSG_LIST to base channel

diff --git a/spice.proto b/spice.proto
index 4d0731b..0e15fe7 100644
--- a/spice.proto
+++ b/spice.proto
@@ -133,6 +133,7 @@ channel BaseChannel {
 	uint8 message[message_len] @end @nomarshal;
     } notify;
 
+    Data list; /* the msg body is SpiceSubMessageList */
  client:
     message {
 	uint32 generation;


More information about the Spice-commits mailing list